Skip to content

Commit

Permalink
Add basic support for Panasonic A/C 64 bits.
Browse files Browse the repository at this point in the history
* `sendPanasonicAC64()` & `decodePanasonicAC64()` added
* Unit tests for the above.
* LSBF order determined by Temperature ranges.

For #1307
  • Loading branch information
crankyoldgit committed Oct 29, 2020
1 parent 18c725d commit a0bd0b7
Show file tree
Hide file tree
Showing 10 changed files with 303 additions and 40 deletions.
4 changes: 4 additions & 0 deletions src/IRrecv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -884,6 +884,10 @@ bool IRrecv::decode(decode_results *results, irparams_t *save,
DPRINTLN("Attempting EliteScreens decode");
if (decodeElitescreens(results, offset)) return true;
#endif // DECODE_ELITESCREENS
#if DECODE_PANASONIC_AC64
DPRINTLN("Attempting Panasonic AC (64bit) decode");
if (decodePanasonicAC64(results, offset)) return true;
#endif // DECODE_PANASONIC_AC64
// Typically new protocols are added above this line.
}
#if DECODE_HASH
Expand Down
8 changes: 7 additions & 1 deletion src/IRrecv.h
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,13 @@ class IRrecv {
uint16_t offset = kStartOffset,
const uint16_t nbits = kPanasonicAcBits,
const bool strict = true);
#endif
#endif // DECODE_PANASONIC_AC
#if DECODE_PANASONIC_AC64
bool decodePanasonicAC64(decode_results *results,
uint16_t offset = kStartOffset,
const uint16_t nbits = kPanasonicAc64Bits,
const bool strict = true);
#endif // DECODE_PANASONIC_AC64
#if DECODE_PIONEER
bool decodePioneer(decode_results *results, uint16_t offset = kStartOffset,
const uint16_t nbits = kPioneerBits,
Expand Down
11 changes: 10 additions & 1 deletion src/IRremoteESP8266.h
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,13 @@
#define SEND_PANASONIC_AC _IR_ENABLE_DEFAULT_
#endif // SEND_PANASONIC_AC

#ifndef DECODE_PANASONIC_AC64
#define DECODE_PANASONIC_AC64 _IR_ENABLE_DEFAULT_
#endif // DECODE_PANASONIC_AC64
#ifndef SEND_PANASONIC_AC64
#define SEND_PANASONIC_AC64 _IR_ENABLE_DEFAULT_
#endif // SEND_PANASONIC_AC64

#ifndef DECODE_MWM
#define DECODE_MWM _IR_ENABLE_DEFAULT_
#endif // DECODE_MWM
Expand Down Expand Up @@ -859,8 +866,9 @@ enum decode_type_t {
TECHNIBEL_AC,
MIRAGE,
ELITESCREENS, // 95
PANASONIC_AC64,
// Add new entries before this one, and update it to point to the last entry.
kLastDecodeType = ELITESCREENS,
kLastDecodeType = PANASONIC_AC64,
};

// Message lengths & required repeat values
Expand Down Expand Up @@ -1022,6 +1030,7 @@ const uint16_t kPanasonicAcStateShortLength = 16;
const uint16_t kPanasonicAcBits = kPanasonicAcStateLength * 8;
const uint16_t kPanasonicAcShortBits = kPanasonicAcStateShortLength * 8;
const uint16_t kPanasonicAcDefaultRepeat = kNoRepeat;
const uint16_t kPanasonicAc64Bits = 64;
const uint16_t kPioneerBits = 64;
const uint16_t kProntoMinLength = 6;
const uint16_t kRC5RawBits = 14;
Expand Down
8 changes: 7 additions & 1 deletion src/IRsend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,7 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) {
case AMCOR:
case CARRIER_AC64:
case DELONGHI_AC:
case PANASONIC_AC64:
case PIONEER:
return 64;
case ARGO:
Expand Down Expand Up @@ -926,7 +927,12 @@ bool IRsend::send(const decode_type_t type, const uint64_t data,
case PANASONIC:
sendPanasonic64(data, nbits, min_repeat);
break;
#endif
#endif // SEND_PANASONIC
#if SEND_PANASONIC_AC64
case PANASONIC_AC64:
sendPanasonicAC64(data, nbits, min_repeat);
break;
#endif // SEND_PANASONIC_AC64
#if SEND_PIONEER
case PIONEER:
sendPioneer(data, nbits, min_repeat);
Expand Down
7 changes: 6 additions & 1 deletion src/IRsend.h
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,12 @@ class IRsend {
void sendPanasonicAC(const unsigned char data[],
const uint16_t nbytes = kPanasonicAcStateLength,
const uint16_t repeat = kPanasonicAcDefaultRepeat);
#endif
#endif // SEND_PANASONIC_AC
#if SEND_PANASONIC_AC64
void sendPanasonicAC64(const uint64_t data,
const uint16_t nbits = kPanasonicAc64Bits,
const uint16_t repeat = kPanasonicAcDefaultRepeat);
#endif // SEND_PANASONIC_AC64
#if SEND_PIONEER
void sendPioneer(const uint64_t data, const uint16_t nbits = kPioneerBits,
const uint16_t repeat = kNoRepeat);
Expand Down
1 change: 1 addition & 0 deletions src/IRtext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,5 +274,6 @@ const PROGMEM char *kAllProtocolNamesStr =
D_STR_TECHNIBEL_AC "\x0"
D_STR_MIRAGE "\x0"
D_STR_ELITESCREENS "\x0"
D_STR_PANASONIC_AC64 "\x0"
///< New protocol strings should be added just above this line.
"\x0"; ///< This string requires double null termination.
151 changes: 128 additions & 23 deletions src/ir_Panasonic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,32 +25,28 @@

// Constants
/// @see http://www.remotecentral.com/cgi-bin/mboard/rc-pronto/thread.cgi?26152
const uint16_t kPanasonicTick = 432;
const uint16_t kPanasonicHdrMarkTicks = 8;
const uint16_t kPanasonicHdrMark = kPanasonicHdrMarkTicks * kPanasonicTick;
const uint16_t kPanasonicHdrSpaceTicks = 4;
const uint16_t kPanasonicHdrSpace = kPanasonicHdrSpaceTicks * kPanasonicTick;
const uint16_t kPanasonicBitMarkTicks = 1;
const uint16_t kPanasonicBitMark = kPanasonicBitMarkTicks * kPanasonicTick;
const uint16_t kPanasonicOneSpaceTicks = 3;
const uint16_t kPanasonicOneSpace = kPanasonicOneSpaceTicks * kPanasonicTick;
const uint16_t kPanasonicZeroSpaceTicks = 1;
const uint16_t kPanasonicZeroSpace = kPanasonicZeroSpaceTicks * kPanasonicTick;
const uint16_t kPanasonicMinCommandLengthTicks = 378;
const uint32_t kPanasonicMinCommandLength =
kPanasonicMinCommandLengthTicks * kPanasonicTick;
const uint16_t kPanasonicEndGap = 5000; // See issue #245
const uint16_t kPanasonicMinGapTicks =
kPanasonicMinCommandLengthTicks -
(kPanasonicHdrMarkTicks + kPanasonicHdrSpaceTicks +
kPanasonicBits * (kPanasonicBitMarkTicks + kPanasonicOneSpaceTicks) +
kPanasonicBitMarkTicks);
const uint32_t kPanasonicMinGap = kPanasonicMinGapTicks * kPanasonicTick;

const uint16_t kPanasonicAcSectionGap = 10000;
const uint16_t kPanasonicHdrMark = 3456; ///< uSeconds.
const uint16_t kPanasonicHdrSpace = 1728; ///< uSeconds.
const uint16_t kPanasonicBitMark = 432; ///< uSeconds.
const uint16_t kPanasonicOneSpace = 1296; ///< uSeconds.
const uint16_t kPanasonicZeroSpace = 432; ///< uSeconds.
const uint32_t kPanasonicMinCommandLength = 163296; ///< uSeconds.
const uint16_t kPanasonicEndGap = 5000; ///< uSeconds. See issue #245
const uint32_t kPanasonicMinGap = 74736; ///< uSeconds.

const uint16_t kPanasonicAcSectionGap = 10000; ///< uSeconds.
const uint16_t kPanasonicAcSection1Length = 8;
const uint32_t kPanasonicAcMessageGap = kDefaultMessageGap; // Just a guess.

const uint16_t kPanasonicAc64HdrMark = 3543; ///< uSeconds.
const uint16_t kPanasonicAc64BitMark = 920; ///< uSeconds.
const uint16_t kPanasonicAc64HdrSpace = 3450; ///< uSeconds.
const uint16_t kPanasonicAc64OneSpace = 2575; ///< uSeconds.
const uint16_t kPanasonicAc64ZeroSpace = 828; ///< uSeconds.
const uint16_t kPanasonicAc64SectionGap = 13946; ///< uSeconds.
const uint8_t kPanasonicAc64Sections = 2;
const uint8_t kPanasonicAc64BlocksPerSection = 2;

using irutils::addBoolToString;
using irutils::addFanToString;
using irutils::addIntToString;
Expand Down Expand Up @@ -926,3 +922,112 @@ bool IRrecv::decodePanasonicAC(decode_results *results, uint16_t offset,
return true;
}
#endif // DECODE_PANASONIC_AC

#if SEND_PANASONIC_AC64
/// Send a Panasonic AC 64bit formatted message.
/// Status: BETA / Probably works.
/// @param[in] data containing the IR command.
/// @param[in] nbits Nr. of bits to send. usually kPanasonicAc64Bits
/// @param[in] repeat Nr. of times the message is to be repeated.
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1307
void IRsend::sendPanasonicAC64(const uint64_t data, const uint16_t nbits,
const uint16_t repeat) {
const uint16_t kSectionBits = nbits / kPanasonicAc64Sections;
for (uint16_t r = 0; r <= repeat; r++) {
for (uint8_t section = 0; section < kPanasonicAc64Sections; section++) {
// Two data blocks per section (i.e. 1 + a repeat)
sendGeneric(kPanasonicAc64HdrMark, kPanasonicAc64HdrSpace, // Header
kPanasonicAc64BitMark, kPanasonicAc64OneSpace, // Data
kPanasonicAc64BitMark, kPanasonicAc64ZeroSpace,
0, 0, // No Footer
GETBITS64(
data,
kSectionBits * (kPanasonicAc64Sections - section - 1),
kSectionBits),
kSectionBits, kPanasonicFreq, false,
kPanasonicAc64BlocksPerSection - 1, // Repeat
50);
// Section Footer
sendGeneric(kPanasonicAc64HdrMark, kPanasonicAc64HdrSpace, // Header
0, 0, 0, 0, // No Data
kPanasonicAc64BitMark, kPanasonicAc64SectionGap, // Footer
data, 0, // No data (bits)
kPanasonicFreq, true, 0, 50);
}
}
}
#endif // SEND_PANASONIC_AC64

#if DECODE_PANASONIC_AC64
/// Decode the supplied Panasonic AC 64bit message.
/// Status: BETA / Probably works.
/// @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/1307
bool IRrecv::decodePanasonicAC64(decode_results *results, uint16_t offset,
const uint16_t nbits, const bool strict) {
if (results->rawlen < 2 * (2 * (nbits + kHeader) + kFooter) - 1 + offset)
return false; // Can't possibly be a valid message.
if (strict && nbits != kPanasonicAc64Bits)
return false; // Not strictly a message.

const uint16_t kSectionBits = nbits / kPanasonicAc64Sections;
uint64_t data = 0;
uint64_t section_data = 0;
uint32_t prev_section_data;

for (uint16_t block = 0;
block < kPanasonicAc64Sections * kPanasonicAc64BlocksPerSection;
block++) {
uint16_t used = matchGeneric(results->rawbuf + offset, &section_data,
results->rawlen - offset, kSectionBits,
kPanasonicAc64HdrMark, kPanasonicAc64HdrSpace,
kPanasonicAc64BitMark, kPanasonicAc64OneSpace,
kPanasonicAc64BitMark, kPanasonicAc64ZeroSpace,
0, 0, // No Footer
false, kUseDefTol, kMarkExcess, false);
if (!used) return false;
offset += used;
// Is it the first block of the section?
if (block % kPanasonicAc64BlocksPerSection == 0) {
prev_section_data = section_data;
// Keep the data from the first of the block pairs.
data = (data << kSectionBits) | section_data;
} else {
// Compliance
if (strict)
// Compare the data from the blocks in pairs.
if (section_data != prev_section_data) return false;
// Look for the section footer at the end of the blocks.
if ((block + 1) % kPanasonicAc64BlocksPerSection == 0) {
uint64_t junk;
used = matchGeneric(results->rawbuf + offset, &junk,
results->rawlen - offset, 0,
// Header
kPanasonicAc64HdrMark, kPanasonicAc64HdrSpace,
// No Data
0, 0,
0, 0,
// Footer
kPanasonicAc64BitMark, kPanasonicAc64SectionGap,
true);
if (!used) return false;
offset += used;
}
}
}

// Success
results->value = data;
results->decode_type = decode_type_t::PANASONIC_AC64;
results->bits = nbits;
results->address = GETBITS64(data, kSectionBits, kSectionBits);
results->command = GETBITS64(data, 0, kSectionBits);;
return true;
}
#endif // DECODE_PANASONIC_AC64
2 changes: 2 additions & 0 deletions src/ir_Panasonic.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
// Brand: Panasonic, Model: A75C2616-1 remote (PANASONIC_AC DKE/3)
// Brand: Panasonic, Model: A75C3704 remote (PANASONIC_AC DKE/3)
// Brand: Panasonic, Model: A75C3747 remote (PANASONIC_AC JKE/4)
// Brand: Panasonic, Model: CS-E9CKP series A/C (PANASONIC_AC64)
// Brand: Panasonic, Model: A75C2295 remote (PANASONIC_AC64)

#ifndef IR_PANASONIC_H_
#define IR_PANASONIC_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 @@ -670,6 +670,9 @@
#ifndef D_STR_PANASONIC_AC
#define D_STR_PANASONIC_AC "PANASONIC_AC"
#endif // D_STR_PANASONIC_AC
#ifndef D_STR_PANASONIC_AC64
#define D_STR_PANASONIC_AC64 D_STR_PANASONIC_AC"64"
#endif // D_STR_PANASONIC_AC64
#ifndef D_STR_PIONEER
#define D_STR_PIONEER "PIONEER"
#endif // D_STR_PIONEER
Expand Down
Loading

0 comments on commit a0bd0b7

Please sign in to comment.