Tasmota/lib/lib_basic/IRremoteESP8266/src/ir_Epson.cpp

105 lines
4.1 KiB
C++

// Copyright 2020 David Conran
/// @file
/// @brief Support for Epson protocols.
/// Epson is an NEC-like protocol, except it doesn't use the NEC style repeat.
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1034
// Supports:
// Brand: Epson, Model: EN-TW9100W Projector
#define __STDC_LIMIT_MACROS
#include <stdint.h>
#include <algorithm>
#include "IRrecv.h"
#include "IRsend.h"
#include "IRutils.h"
#include "ir_NEC.h"
#if SEND_EPSON
/// Send an Epson formatted message.
/// Status: Beta / Probably works.
/// @param[in] data The message to be sent.
/// @param[in] nbits The number of nbits of message to be sent.
/// @param[in] repeat The number of times the command is to be repeated.
void IRsend::sendEpson(uint64_t data, uint16_t nbits, uint16_t repeat) {
sendGeneric(kNecHdrMark, kNecHdrSpace, kNecBitMark, kNecOneSpace, kNecBitMark,
kNecZeroSpace, kNecBitMark, kNecMinGap, kNecMinCommandLength,
data, nbits, 38, true, repeat, 33);
}
#endif // SEND_EPSON
#if DECODE_EPSON
/// Decode the supplied Epson 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.
/// @note Experimental data indicates there are at least three messages
/// (first + 2 repeats). We only require the first + a single repeat to match.
/// This helps us distinguish it from NEC messages which are near identical.
bool IRrecv::decodeEpson(decode_results *results, uint16_t offset,
const uint16_t nbits, const bool strict) {
const uint8_t kEpsonMinMesgsForDecode = 2;
if (results->rawlen < kEpsonMinMesgsForDecode * (2 * nbits + kHeader +
kFooter) + offset - 1)
return false; // Can't possibly be a valid Epson message.
if (strict && nbits != kEpsonBits)
return false; // Not strictly an Epson message.
uint64_t data = 0;
uint64_t first_data = 0;
bool first = true;
for (uint8_t i = 0; i < kEpsonMinMesgsForDecode; i++) {
// Match Header + Data + Footer
uint16_t delta = matchGeneric(results->rawbuf + offset, &data,
results->rawlen - offset, nbits,
kNecHdrMark, kNecHdrSpace,
kNecBitMark, kNecOneSpace,
kNecBitMark, kNecZeroSpace,
kNecBitMark, kNecMinGap, true);
if (!delta) return false;
offset += delta;
if (first)
first_data = data;
else if (data != first_data) return false;
first = false; // No longer the first message.
}
// Compliance
// Calculate command and optionally enforce integrity checking.
uint8_t command = (data & 0xFF00) >> 8;
// Command is sent twice, once as plain and then inverted.
if ((command ^ 0xFF) != (data & 0xFF)) {
if (strict) return false; // Command integrity failed.
command = 0; // The command value isn't valid, so default to zero.
}
// Success
results->bits = nbits;
results->value = data;
results->decode_type = EPSON;
// Epson command and address are technically in LSB first order so the
// final versions have to be reversed.
results->command = reverseBits(command, 8);
// Normal Epson (NEC) protocol has an 8 bit address sent,
// followed by it inverted.
uint8_t address = (data & 0xFF000000) >> 24;
uint8_t address_inverted = (data & 0x00FF0000) >> 16;
if (address == (address_inverted ^ 0xFF))
// Inverted, so it is normal Epson (NEC) protocol.
results->address = reverseBits(address, 8);
else
// Not inverted, so must be Extended Epson (NEC) protocol,
// thus 16 bit address.
results->address = reverseBits((data >> 16) & UINT16_MAX, 16);
results->repeat = !first;
return true;
}
#endif // DECODE_EPSON