-
Notifications
You must be signed in to change notification settings - Fork 833
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for Metz protocol. (#1242)
* Add `sendMetz()` & `decodeMetz()`. * Add `encodeMetz()` to handle creation of valid Metz codes from Address & Command bits (inc toggle bit) * Unit test coverage based on supplied data. Note: Protocol is a simple non-A/C one for controlling TVs etc. Fixes #1241
- Loading branch information
1 parent
dcefcad
commit 2c6f814
Showing
9 changed files
with
236 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
// Copyright 2020 David Conran (crankyoldgit) | ||
/// @file | ||
/// @brief Support for Metz protocol | ||
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1241 | ||
|
||
// Supports: | ||
// Brand: Metz, Model: RM16 remote | ||
// Brand: Metz, Model: RM17 remote | ||
// Brand: Metz, Model: RM19 remote | ||
// Brand: Metz, Model: CH610 TV | ||
|
||
#include "IRrecv.h" | ||
#include "IRsend.h" | ||
#include "IRutils.h" | ||
|
||
// Constants. | ||
const uint16_t kMetzHdrMark = 880; ///< uSeconds. | ||
const uint16_t kMetzHdrSpace = 2336; ///< uSeconds. | ||
const uint16_t kMetzBitMark = 473; ///< uSeconds. | ||
const uint16_t kMetzOneSpace = 1640; ///< uSeconds. | ||
const uint16_t kMetzZeroSpace = 940; ///< uSeconds. | ||
const uint16_t kMetzFreq = 38000; ///< Hz. | ||
const uint8_t kMetzAddressBits = 3; | ||
const uint8_t kMetzCommandBits = 6; | ||
|
||
#if SEND_METZ | ||
/// Send a Metz formatted message. | ||
/// Status: Beta / Needs testing against a real device. | ||
/// @param[in] data containing the IR command. | ||
/// @param[in] nbits Nr. of bits to send. usually kMetzBits | ||
/// @param[in] repeat Nr. of times the message is to be repeated. | ||
void IRsend::sendMetz(const uint64_t data, const uint16_t nbits, | ||
const uint16_t repeat) { | ||
sendGeneric(kMetzHdrMark, kMetzHdrSpace, // Header | ||
kMetzBitMark, kMetzOneSpace, // Data | ||
kMetzBitMark, kMetzZeroSpace, | ||
kMetzBitMark, kDefaultMessageGap, // Footer. | ||
data, nbits, // Payload | ||
kMetzFreq, true, repeat, kDutyDefault); | ||
} | ||
|
||
/// Encode a Metz address, command, and toggle bits into a code suitable | ||
/// for use with sendMetz(). | ||
/// @param[in] address A 3-bit address value. | ||
/// @param[in] command A 6-bit command value. | ||
/// @param[in] toggle Should the toggle bit be set in the result? | ||
/// @return A 19-bit value suitable for use with `sendMetz()`. | ||
uint32_t IRsend::encodeMetz(const uint8_t address, const uint8_t command, | ||
const bool toggle) { | ||
return toggle << (2 * (kMetzAddressBits + kMetzCommandBits)) | | ||
(address & 0x7) << (2 * kMetzCommandBits + kMetzAddressBits) | | ||
(~address & 0x7) << (2 * kMetzCommandBits) | | ||
(command & 0x3F) << kMetzCommandBits | | ||
(~command & 0x3F); | ||
} | ||
#endif // SEND_METZ | ||
|
||
#if DECODE_METZ | ||
/// Decode the supplied Metz message. | ||
/// Status: BETA / Probably works. | ||
/// @param[in,out] results Ptr to the data to decode & where to store the decode | ||
/// @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::decodeMetz(decode_results *results, uint16_t offset, | ||
const uint16_t nbits, const bool strict) { | ||
if (strict && nbits != kMetzBits) return false; | ||
|
||
uint64_t data = 0; | ||
|
||
// Match Header + Data + Footer | ||
if (!matchGeneric(results->rawbuf + offset, &data, | ||
results->rawlen - offset, nbits, | ||
kMetzHdrMark, kMetzHdrSpace, // Header | ||
kMetzBitMark, kMetzOneSpace, // Data | ||
kMetzBitMark, kMetzZeroSpace, | ||
kMetzBitMark, kDefaultMessageGap, // Footer | ||
true, _tolerance, 0, true)) return false; | ||
|
||
uint16_t command = GETBITS64(data, kMetzCommandBits, kMetzCommandBits); | ||
uint16_t address = GETBITS64(data, 2 * kMetzCommandBits + kMetzAddressBits, | ||
kMetzAddressBits); | ||
// Compliance | ||
if (strict) { | ||
if (command != invertBits(GETBITS64(data, 0, kMetzCommandBits), | ||
kMetzCommandBits) || | ||
address != invertBits(GETBITS64(data, 2 * kMetzCommandBits, | ||
kMetzAddressBits), | ||
kMetzAddressBits)) return false; | ||
} | ||
// Success | ||
results->decode_type = decode_type_t::METZ; | ||
results->bits = nbits; | ||
results->value = data; | ||
results->address = address; | ||
results->command = command; | ||
return true; | ||
} | ||
#endif // DECODE_METZ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
// Copyright 2020 crankyoldgit | ||
|
||
#include "IRac.h" | ||
#include "IRrecv.h" | ||
#include "IRrecv_test.h" | ||
#include "IRsend.h" | ||
#include "IRsend_test.h" | ||
#include "gtest/gtest.h" | ||
|
||
// Tests for decodeMetz(). | ||
|
||
TEST(TestDecodeMetz, RealExample) { | ||
IRsendTest irsend(kGpioUnused); | ||
IRrecv irrecv(kGpioUnused); | ||
uint16_t rawbuf[41] = { | ||
// Header 1 0 1 | ||
880, 2336, 462, 1656, 460, 952, 486, 1630, | ||
// 1 1 0 0 | ||
462, 1654, 460, 1660, 462, 948, 488, 902, | ||
// 1 0 1 0 | ||
486, 1656, 486, 926, 486, 1630, 486, 924, | ||
// 1 0 0 1 | ||
488, 1630, 460, 954, 460, 950, 512, 1606, | ||
// 0 1 0 1 | ||
460, 978, 436, 1656, 486, 926, 486, 1630, | ||
458}; | ||
irsend.begin(); | ||
irsend.reset(); | ||
irsend.sendRaw(rawbuf, 41, 38); | ||
irsend.makeDecodeResult(); | ||
|
||
ASSERT_TRUE(irrecv.decode(&irsend.capture)); | ||
ASSERT_EQ(decode_type_t::METZ, irsend.capture.decode_type); | ||
ASSERT_EQ(kMetzBits, irsend.capture.bits); | ||
EXPECT_EQ(0x5CA95, irsend.capture.value); | ||
EXPECT_EQ(0x2A, irsend.capture.command); | ||
EXPECT_EQ(0x3, irsend.capture.address); | ||
} | ||
|
||
TEST(TestDecodeMetz, SyntheticExample) { | ||
IRsendTest irsend(kGpioUnused); | ||
IRrecv irrecv(kGpioUnused); | ||
irsend.begin(); | ||
irsend.reset(); | ||
irsend.sendMetz(0x5CA95); | ||
irsend.makeDecodeResult(); | ||
|
||
ASSERT_TRUE(irrecv.decode(&irsend.capture)); | ||
EXPECT_EQ(decode_type_t::METZ, irsend.capture.decode_type); | ||
EXPECT_EQ(kMetzBits, irsend.capture.bits); | ||
EXPECT_EQ(0x5CA95, irsend.capture.value); | ||
EXPECT_EQ(0x2A, irsend.capture.command); | ||
EXPECT_EQ(0x3, irsend.capture.address); | ||
|
||
EXPECT_EQ( | ||
"f38000d50" | ||
// 880 2336 462 1656 460 952 486 1630 462 1654 460 1660 462 948 488 902 | ||
"m880s2336m473s1640m473s940m473s1640m473s1640m473s1640m473s940m473s940" | ||
// 486 1656 486 926 486 1630 486 924 488 1630 460 954 460 950 512 1606 | ||
"m473s1640m473s940m473s1640m473s940m473s1640m473s940m473s940m473s1640" | ||
// 460 978 436 1656 486 926 486 1630 | ||
"m473s940m473s1640m473s940m473s1640" | ||
// 458 | ||
"m473s100000", | ||
irsend.outputStr()); | ||
} | ||
|
||
TEST(TestEncodeMetz, BasicTests) { | ||
EXPECT_EQ(0x703F, IRsend::encodeMetz(0, 0)); | ||
EXPECT_EQ(0x703F, IRsend::encodeMetz(0, 0, false)); | ||
EXPECT_EQ(0x4703F, IRsend::encodeMetz(0, 0, true)); | ||
|
||
EXPECT_EQ(0xE0BD, IRsend::encodeMetz(1, 2, false)); | ||
EXPECT_EQ(0x4E0BD, IRsend::encodeMetz(1, 2, true)); | ||
|
||
EXPECT_EQ(0x38FC0, IRsend::encodeMetz(0b111, 0b111111, false)); | ||
EXPECT_EQ(0x78FC0, IRsend::encodeMetz(0b111, 0b111111, true)); | ||
|
||
// Out of range. | ||
EXPECT_EQ(0x38FC0, IRsend::encodeMetz(255, 255, false)); | ||
EXPECT_EQ(0x78FC0, IRsend::encodeMetz(255, 255, true)); | ||
} | ||
|
||
TEST(TestEncodeMetz, RealExamples) { | ||
EXPECT_EQ(0x5CA95, IRsend::encodeMetz(0x3, 0x2A, true)); | ||
} | ||
|
||
TEST(TestUtils, Housekeeping) { | ||
ASSERT_EQ("METZ", typeToString(decode_type_t::METZ)); | ||
ASSERT_EQ(decode_type_t::METZ, strToDecodeType("METZ")); | ||
ASSERT_FALSE(hasACState(decode_type_t::METZ)); | ||
ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::METZ)); | ||
ASSERT_EQ(kMetzBits, IRsend::defaultBits(decode_type_t::METZ)); | ||
ASSERT_EQ(kMetzMinRepeat, IRsend::minRepeats(decode_type_t::METZ)); | ||
} |