Skip to content

Commit

Permalink
CARRIER_AC128: Experimental Basic support for Carrier AC 128bit proto…
Browse files Browse the repository at this point in the history
…col.

* Add `sendCarrierAC128()` & `decodeCarrierAC128()` methods.
* Basic unit test coverage for new protocol.
* Update supported model info.

For #1797
  • Loading branch information
crankyoldgit committed May 8, 2022
1 parent 21804f5 commit c7e6fa3
Show file tree
Hide file tree
Showing 11 changed files with 244 additions and 9 deletions.
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_CARRIER_AC128
DPRINTLN("Attempting Carrier AC 128-bit decode");
if (decodeCarrierAC128(results, offset)) return true;
#endif // DECODE_CARRIER_AC128
// Typically new protocols are added above this line.
}
#if DECODE_HASH
Expand Down
6 changes: 6 additions & 0 deletions src/IRrecv.h
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,12 @@ class IRrecv {
const uint16_t nbits = kCarrierAc64Bits,
const bool strict = true);
#endif // DECODE_CARRIER_AC64
#if DECODE_CARRIER_AC128
bool decodeCarrierAC128(decode_results *results,
uint16_t offset = kStartOffset,
const uint16_t nbits = kCarrierAc128Bits,
const bool strict = true);
#endif // DECODE_CARRIER_AC128
#if DECODE_GOODWEATHER
bool decodeGoodweather(decode_results *results,
uint16_t offset = kStartOffset,
Expand Down
15 changes: 13 additions & 2 deletions src/IRremoteESP8266.h
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,13 @@
#define SEND_CARRIER_AC64 _IR_ENABLE_DEFAULT_
#endif // SEND_CARRIER_AC64

#ifndef DECODE_CARRIER_AC128
#define DECODE_CARRIER_AC128 _IR_ENABLE_DEFAULT_
#endif // DECODE_CARRIER_AC128
#ifndef SEND_CARRIER_AC128
#define SEND_CARRIER_AC128 _IR_ENABLE_DEFAULT_
#endif // SEND_CARRIER_AC128

#ifndef DECODE_HAIER_AC
#define DECODE_HAIER_AC _IR_ENABLE_DEFAULT_
#endif // DECODE_HAIER_AC
Expand Down Expand Up @@ -876,7 +883,7 @@
DECODE_VOLTAS || DECODE_MIRAGE || DECODE_HAIER_AC176 || \
DECODE_TEKNOPOINT || DECODE_KELON || DECODE_TROTEC_3550 || \
DECODE_SANYO_AC88 || DECODE_RHOSS || DECODE_HITACHI_AC264 || \
DECODE_KELON168 || DECODE_HITACHI_AC296 || \
DECODE_KELON168 || DECODE_HITACHI_AC296 || DECODE_CARRIER_AC128 || \
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 +1037,9 @@ enum decode_type_t {
HITACHI_AC264,
KELON168,
HITACHI_AC296,
CARRIER_AC128,
// Add new entries before this one, and update it to point to the last entry.
kLastDecodeType = HITACHI_AC296,
kLastDecodeType = CARRIER_AC128,
};

// Message lengths & required repeat values
Expand Down Expand Up @@ -1061,6 +1069,9 @@ const uint16_t kCarrierAc40Bits = 40;
const uint16_t kCarrierAc40MinRepeat = 2;
const uint16_t kCarrierAc64Bits = 64;
const uint16_t kCarrierAc64MinRepeat = kNoRepeat;
const uint16_t kCarrierAc128StateLength = 16;
const uint16_t kCarrierAc128Bits = kCarrierAc128StateLength * 8;
const uint16_t kCarrierAc128MinRepeat = kNoRepeat;
const uint16_t kCoronaAcStateLengthShort = 7;
const uint16_t kCoronaAcStateLength = kCoronaAcStateLengthShort * 3;
const uint16_t kCoronaAcBitsShort = kCoronaAcStateLengthShort * 8;
Expand Down
7 changes: 7 additions & 0 deletions src/IRsend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,8 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) {
return kArgoBits;
case CORONA_AC:
return kCoronaAcBits;
case CARRIER_AC128:
return kCarrierAc128Bits;
case DAIKIN:
return kDaikinBits;
case DAIKIN128:
Expand Down Expand Up @@ -1126,6 +1128,11 @@ bool IRsend::send(const decode_type_t type, const uint8_t *state,
sendArgo(state, nbytes);
break;
#endif // SEND_ARGO
#if SEND_CARRIER_AC128
case CARRIER_AC128:
sendCarrierAC128(state, nbytes);
break;
#endif // SEND_CARRIER_AC128
#if SEND_CORONA_AC
case CORONA_AC:
sendCoronaAc(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 @@ -558,6 +558,11 @@ class IRsend {
void sendCarrierAC64(uint64_t data, uint16_t nbits = kCarrierAc64Bits,
uint16_t repeat = kCarrierAc64MinRepeat);
#endif
#if SEND_CARRIER_AC128
void sendCarrierAC128(const uint8_t data[],
uint16_t nbytes = kCarrierAc128StateLength,
uint16_t repeat = kCarrierAc128MinRepeat);
#endif // SEND_CARRIER_AC128
#if (SEND_HAIER_AC || SEND_HAIER_AC_YRW02 || SEND_HAIER_AC176)
void sendHaierAC(const unsigned char data[],
const uint16_t nbytes = kHaierACStateLength,
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_CARRIER_AC128 "\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 @@ -172,6 +172,7 @@ bool hasACState(const decode_type_t protocol) {
// This is kept sorted by name
case AMCOR:
case ARGO:
case CARRIER_AC128:
case CORONA_AC:
case DAIKIN:
case DAIKIN128:
Expand Down
114 changes: 113 additions & 1 deletion src/ir_Carrier.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// Copyright 2018, 2020 David Conran
// Copyright 2018-2022 David Conran
/// @file
/// @brief Carrier protocols.
/// @see CarrierAc https://github.com/crankyoldgit/IRremoteESP8266/issues/385
/// @see CarrierAc64 https://github.com/crankyoldgit/IRremoteESP8266/issues/1127
/// @see CarrierAc128 https://github.com/crankyoldgit/IRremoteESP8266/issues/1797

#include "ir_Carrier.h"
#include <algorithm>
Expand Down Expand Up @@ -45,6 +46,16 @@ const uint16_t kCarrierAc64OneSpace = 1736;
const uint16_t kCarrierAc64ZeroSpace = 615;
const uint32_t kCarrierAc64Gap = kDefaultMessageGap; // A guess.

const uint16_t kCarrierAc128HdrMark = 4600;
const uint16_t kCarrierAc128HdrSpace = 2600;
const uint16_t kCarrierAc128Hdr2Mark = 9300;
const uint16_t kCarrierAc128Hdr2Space = 5000;
const uint16_t kCarrierAc128BitMark = 340;
const uint16_t kCarrierAc128OneSpace = 1000;
const uint16_t kCarrierAc128ZeroSpace = 400;
const uint16_t kCarrierAc128SectionGap = 20600;
const uint16_t kCarrierAc128InterSpace = 6700;
const uint16_t kCarrierAc128SectionBits = kCarrierAc128Bits / 2;

#if SEND_CARRIER_AC
/// Send a Carrier HVAC formatted message.
Expand Down Expand Up @@ -533,3 +544,104 @@ stdAc::state_t IRCarrierAc64::toCommon(void) const {
result.clock = -1;
return result;
}

#if SEND_CARRIER_AC128
/// Send a Carrier 128bit HVAC formatted message.
/// Status: BETA / Seems to work with tests. Needs testing agaisnt real devices.
/// @param[in] data The message to be sent.
/// @param[in] nbytes The byte size of the message being sent.
/// @param[in] repeat The number of times the message is to be repeated.
void IRsend::sendCarrierAC128(const uint8_t data[], const uint16_t nbytes,
const uint16_t repeat) {
// Min length check.
if (nbytes <= kCarrierAc128StateLength / 2) return;

enableIROut(kCarrierAcFreq);
// Handle repeats.
for (uint16_t r = 0; r <= repeat; r++) {
// First part of the message.
// Headers + Data + SectionGap
sendGeneric(kCarrierAc128HdrMark, kCarrierAc128HdrSpace,
kCarrierAc128BitMark, kCarrierAc128OneSpace,
kCarrierAc128BitMark, kCarrierAc128ZeroSpace,
kCarrierAc128BitMark, kCarrierAc128SectionGap,
data, nbytes / 2, kCarrierAcFreq, false, 0, kDutyDefault);
// Inter-message markers
mark(kCarrierAc128HdrMark);
space(kCarrierAc128InterSpace);
// Second part of the message
// Headers + Data + SectionGap
sendGeneric(kCarrierAc128Hdr2Mark, kCarrierAc128Hdr2Space,
kCarrierAc128BitMark, kCarrierAc128OneSpace,
kCarrierAc128BitMark, kCarrierAc128ZeroSpace,
kCarrierAc128BitMark, kCarrierAc128SectionGap,
data + (nbytes / 2), nbytes / 2, kCarrierAcFreq,
false, 0, kDutyDefault);
// Footer
mark(kCarrierAc128HdrMark);
space(kDefaultMessageGap);
}
}
#endif // SEND_CARRIER_AC128

#if DECODE_CARRIER_AC128
/// Decode the supplied Carrier 128-bit HVAC message.
/// Status: STABLE / Expected to work.
/// @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.
bool IRrecv::decodeCarrierAC128(decode_results *results, uint16_t offset,
const uint16_t nbits, const bool strict) {
if (results->rawlen < 2 * (nbits + 2 * kHeader + kFooter) - 1 + offset)
return false; // Can't possibly be a valid Carrier message.
if (strict && nbits != kCarrierAc128Bits)
return false; // We expect Carrier to be 128 bits of message.

uint16_t used;
uint16_t pos = 0;
const uint16_t sectionbits = nbits / 2;
// Match the first section.
used = matchGeneric(results->rawbuf + offset, results->state,
results->rawlen - offset, sectionbits,
kCarrierAc128HdrMark, kCarrierAc128HdrSpace,
kCarrierAc128BitMark, kCarrierAc128OneSpace,
kCarrierAc128BitMark, kCarrierAc128ZeroSpace,
kCarrierAc128BitMark, kCarrierAc128SectionGap, true,
kUseDefTol, kMarkExcess, false);
if (used == 0) return false; // No match.
offset += used;
pos += sectionbits / 8;
// Look for the inter-message markers.
if (!matchMark(results->rawbuf[offset++], kCarrierAc128HdrMark))
return false;
if (!matchSpace(results->rawbuf[offset++], kCarrierAc128InterSpace))
return false;
// Now look for the second section.
used = matchGeneric(results->rawbuf + offset, results->state + pos,
results->rawlen - offset, sectionbits,
kCarrierAc128Hdr2Mark, kCarrierAc128Hdr2Space,
kCarrierAc128BitMark, kCarrierAc128OneSpace,
kCarrierAc128BitMark, kCarrierAc128ZeroSpace,
kCarrierAc128BitMark, kCarrierAc128SectionGap, true,
kUseDefTol, kMarkExcess, false);
if (used == 0) return false; // No match.
offset += used;
// Now check for the Footer.
if (!matchMark(results->rawbuf[offset++], kCarrierAc128HdrMark)) return false;
if (offset < results->rawlen &&
!matchAtLeast(results->rawbuf[offset], kDefaultMessageGap)) return false;


// Compliance
// if (strict && !IRCarrierAc128::validChecksum(results->value)) return false;

// Success
results->bits = nbits;
results->decode_type = CARRIER_AC128;
return true;
}
#endif // DECODE_CARRIER_AC128
4 changes: 3 additions & 1 deletion src/ir_Carrier.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// Copyright 2020 David Conran
// Copyright 2020-2022 David Conran
/// @file
/// @brief Carrier A/C
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1127
/// @see https://docs.google.com/spreadsheets/d/1EZy78L0cn1KDIX1aKq2biptejFqCjD5HO3tLiRvXf48/edit#gid=0
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1797

// Supports:
// Brand: Carrier/Surrey, Model: 42QG5A55970 remote
Expand All @@ -11,6 +12,7 @@
// Brand: Carrier/Surrey, Model: 619EGX0180E0 A/C
// Brand: Carrier/Surrey, Model: 619EGX0220E0 A/C
// Brand: Carrier/Surrey, Model: 53NGK009/012 Inverter
// Brand: Carrier, Model: 40GKX0E2006 remote (CARRIER_AC128)

#ifndef IR_CARRIER_H_
#define IR_CARRIER_H_
Expand Down
3 changes: 3 additions & 0 deletions src/locale/defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,9 @@ D_STR_INDIRECT " " D_STR_MODE
#ifndef D_STR_CARRIER_AC64
#define D_STR_CARRIER_AC64 D_STR_CARRIER_AC "64"
#endif // D_STR_CARRIER_AC64
#ifndef D_STR_CARRIER_AC128
#define D_STR_CARRIER_AC128 D_STR_CARRIER_AC "128"
#endif // D_STR_CARRIER_AC128
#ifndef D_STR_COOLIX
#define D_STR_COOLIX "COOLIX"
#endif // D_STR_COOLIX
Expand Down
Loading

0 comments on commit c7e6fa3

Please sign in to comment.