From d28b6f985c45d3958441034d4f5f89fe8b3395ec Mon Sep 17 00:00:00 2001 From: Philipp Henkel Date: Tue, 12 Jul 2016 23:14:47 +0200 Subject: [PATCH 1/9] Add Lego Power Functions tests --- .travis.yml | 1 + .../LegoPowerFunctionsTests.ino | 197 ++++++++++++++++++ ir_Lego_PF.cpp | 123 ++--------- ir_Lego_PF_BitStreamEncoder.h | 115 ++++++++++ 4 files changed, 331 insertions(+), 105 deletions(-) create mode 100644 examples/LegoPowerFunctionsTests/LegoPowerFunctionsTests.ino create mode 100644 ir_Lego_PF_BitStreamEncoder.h diff --git a/.travis.yml b/.travis.yml index ce01e805f..543a0a74b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,6 +20,7 @@ env: - PLATFORMIO_CI_SRC=examples/IRtest2 PLATFORMIO_BUILD_FLAGS="-DSEND_NEC -DSEND_SONY -DSEND_RC5 -DSEND_RC6" - PLATFORMIO_CI_SRC=examples/JVCPanasonicSendDemo PLATFORMIO_BUILD_FLAGS="-DSEND_JVC -DSEND_PANASONIC" - PLATFORMIO_CI_SRC=examples/LegoPowerFunctionsSendDemo PLATFORMIO_BUILD_FLAGS="-DSEND_LEGO_PF" + - PLATFORMIO_CI_SRC=examples/LegoPowerFunctionsTests PLATFORMIO_BUILD_FLAGS="-DSEND_LEGO_PF" - PLATFORMIO_CI_SRC=examples/IRremoteInfo install: diff --git a/examples/LegoPowerFunctionsTests/LegoPowerFunctionsTests.ino b/examples/LegoPowerFunctionsTests/LegoPowerFunctionsTests.ino new file mode 100644 index 000000000..6a2bda57d --- /dev/null +++ b/examples/LegoPowerFunctionsTests/LegoPowerFunctionsTests.ino @@ -0,0 +1,197 @@ +/* + * LegoPowerFunctionsTest: LEGO Power Functions Tests + * Copyright (c) 2016 Philipp Henkel + */ + +#include + +void setup() { + Serial.begin(9600); + delay(1000); // wait for reset triggered by serial connection + runBitStreamEncoderTests(); +} + +void loop() { +} + +void runBitStreamEncoderTests() { + Serial.println(); + Serial.println("BitStreamEncoder Tests"); + static LegoPfBitStreamEncoder bitStreamEncoder; + testStartBit(bitStreamEncoder); + testLowBit(bitStreamEncoder); + testHighBit(bitStreamEncoder); + testMessageBitCount(bitStreamEncoder); + testMessageBitCountRepeat(bitStreamEncoder); + testMessage407(bitStreamEncoder); + testMessage407Repeated(bitStreamEncoder); + testGetChannelId1(bitStreamEncoder); + testGetChannelId2(bitStreamEncoder); + testGetChannelId3(bitStreamEncoder); + testGetChannelId4(bitStreamEncoder); + testGetMessageLengthAllHigh(bitStreamEncoder); + testGetMessageLengthAllLow(bitStreamEncoder); +} + +void logTestResult(bool testPassed) { + if (testPassed) { + Serial.println("OK"); + } + else { + Serial.println("FAIL ############"); + } +} + +void testStartBit(LegoPfBitStreamEncoder& bitStreamEncoder) { + Serial.print(" testStartBit "); + bitStreamEncoder.reset(0, false); + int startMark = bitStreamEncoder.getMarkDuration(); + int startPause = bitStreamEncoder.getPauseDuration(); + logTestResult(startMark == 158 && startPause == 1184-158); +} + +void testLowBit(LegoPfBitStreamEncoder& bitStreamEncoder) { + Serial.print(" testLowBit "); + bitStreamEncoder.reset(0, false); + bitStreamEncoder.next(); + int lowMark = bitStreamEncoder.getMarkDuration(); + int lowPause = bitStreamEncoder.getPauseDuration(); + logTestResult(lowMark == 158 && lowPause == 421-158); +} + +void testHighBit(LegoPfBitStreamEncoder& bitStreamEncoder) { + Serial.print(" testHighBit "); + bitStreamEncoder.reset(0xFFFF, false); + bitStreamEncoder.next(); + int highMark = bitStreamEncoder.getMarkDuration(); + int highPause = bitStreamEncoder.getPauseDuration(); + logTestResult(highMark == 158 && highPause == 711-158); +} + +void testMessageBitCount(LegoPfBitStreamEncoder& bitStreamEncoder) { + Serial.print(" testMessageBitCount "); + bitStreamEncoder.reset(0xFFFF, false); + int bitCount = 1; + while (bitStreamEncoder.next()) { + bitCount++; + } + logTestResult(bitCount == 18); +} + +boolean check(LegoPfBitStreamEncoder& bitStreamEncoder, int markDuration, int pauseDuration) { + bool result = true; + result = result && bitStreamEncoder.getMarkDuration() == markDuration; + result = result && bitStreamEncoder.getPauseDuration() == pauseDuration; + return result; +} + +boolean checkNext(LegoPfBitStreamEncoder& bitStreamEncoder, int markDuration, int pauseDuration) { + bool result = bitStreamEncoder.next(); + result = result && check(bitStreamEncoder, markDuration, pauseDuration); + return result; +} + +boolean checkDataBitsOfMessage407(LegoPfBitStreamEncoder& bitStreamEncoder) { + bool result = true; + result = result && checkNext(bitStreamEncoder, 158, 263); + result = result && checkNext(bitStreamEncoder, 158, 263); + result = result && checkNext(bitStreamEncoder, 158, 263); + result = result && checkNext(bitStreamEncoder, 158, 263); + result = result && checkNext(bitStreamEncoder, 158, 263); + result = result && checkNext(bitStreamEncoder, 158, 263); + result = result && checkNext(bitStreamEncoder, 158, 263); + result = result && checkNext(bitStreamEncoder, 158, 553); + result = result && checkNext(bitStreamEncoder, 158, 553); + result = result && checkNext(bitStreamEncoder, 158, 263); + result = result && checkNext(bitStreamEncoder, 158, 263); + result = result && checkNext(bitStreamEncoder, 158, 553); + result = result && checkNext(bitStreamEncoder, 158, 263); + result = result && checkNext(bitStreamEncoder, 158, 553); + result = result && checkNext(bitStreamEncoder, 158, 553); + result = result && checkNext(bitStreamEncoder, 158, 553); + return result; +} + +void testMessage407(LegoPfBitStreamEncoder& bitStreamEncoder) { + Serial.print(" testMessage407 "); + bitStreamEncoder.reset(407, false); + bool result = true; + result = result && check(bitStreamEncoder, 158, 1026); + result = result && checkDataBitsOfMessage407(bitStreamEncoder); + result = result && checkNext(bitStreamEncoder, 158, 1026); + result = result && !bitStreamEncoder.next(); + logTestResult(result); +} + +void testMessage407Repeated(LegoPfBitStreamEncoder& bitStreamEncoder) { + Serial.print(" testMessage407Repeated "); + bitStreamEncoder.reset(407, true); + bool result = true; + result = result && check(bitStreamEncoder, 158, 1026); + result = result && checkDataBitsOfMessage407(bitStreamEncoder); + result = result && checkNext(bitStreamEncoder, 158, 1026 + 5 * 16000 - 10844); + result = result && checkNext(bitStreamEncoder, 158, 1026); + result = result && checkDataBitsOfMessage407(bitStreamEncoder); + result = result && checkNext(bitStreamEncoder, 158, 1026 + 5 * 16000 - 10844); + result = result && checkNext(bitStreamEncoder, 158, 1026); + result = result && checkDataBitsOfMessage407(bitStreamEncoder); + result = result && checkNext(bitStreamEncoder, 158, 1026 + 8 * 16000 - 10844); + result = result && checkNext(bitStreamEncoder, 158, 1026); + result = result && checkDataBitsOfMessage407(bitStreamEncoder); + result = result && checkNext(bitStreamEncoder, 158, 1026 + 8 * 16000 - 10844); + result = result && checkNext(bitStreamEncoder, 158, 1026); + result = result && checkDataBitsOfMessage407(bitStreamEncoder); + result = result && checkNext(bitStreamEncoder, 158, 1026); + result = result && !bitStreamEncoder.next(); + logTestResult(result); +} + +void testMessageBitCountRepeat(LegoPfBitStreamEncoder& bitStreamEncoder) { + Serial.print(" testMessageBitCountRepeat "); + bitStreamEncoder.reset(0xFFFF, true); + int bitCount = 1; + while (bitStreamEncoder.next()) { + bitCount++; + } + logTestResult(bitCount == 5*18); +} + +void testGetChannelId1(LegoPfBitStreamEncoder& bitStreamEncoder) { + Serial.print(" testGetChannelId1 "); + bitStreamEncoder.reset(407, false); + logTestResult(bitStreamEncoder.getChannelId() == 1); +} + +void testGetChannelId2(LegoPfBitStreamEncoder& bitStreamEncoder) { + Serial.print(" testGetChannelId2 "); + bitStreamEncoder.reset(4502, false); + logTestResult(bitStreamEncoder.getChannelId() == 2); +} + +void testGetChannelId3(LegoPfBitStreamEncoder& bitStreamEncoder) { + Serial.print(" testGetChannelId3 "); + bitStreamEncoder.reset(8597, false); + logTestResult(bitStreamEncoder.getChannelId() == 3); +} + +void testGetChannelId4(LegoPfBitStreamEncoder& bitStreamEncoder) { + Serial.print(" testGetChannelId4 "); + bitStreamEncoder.reset(12692, false); + logTestResult(bitStreamEncoder.getChannelId() == 4); +} + +void testGetMessageLengthAllHigh(LegoPfBitStreamEncoder& bitStreamEncoder) { + Serial.print(" testGetMessageLengthAllHigh "); + bitStreamEncoder.reset(0xFFFF, false); + logTestResult(bitStreamEncoder.getMessageLength() == 13744); +} + +void testGetMessageLengthAllLow(LegoPfBitStreamEncoder& bitStreamEncoder) { + Serial.print(" testGetMessageLengthAllLow "); + bitStreamEncoder.reset(0x0, false); + logTestResult(bitStreamEncoder.getMessageLength() == 9104); +} + + + + diff --git a/ir_Lego_PF.cpp b/ir_Lego_PF.cpp index 2196bed6f..37d507ceb 100644 --- a/ir_Lego_PF.cpp +++ b/ir_Lego_PF.cpp @@ -1,5 +1,6 @@ #include "IRremote.h" #include "IRremoteInt.h" +#include "ir_Lego_PF_BitStreamEncoder.h" //============================================================================== // L EEEEEE EEEE OOOO @@ -16,118 +17,30 @@ // #if SEND_LEGO_PF -class BitStreamEncoder { - private: - uint16_t data; - bool repeatMessage; - int messageBitIdx; - int repeatCount; - int messageLength; - - // HIGH data bit = IR mark + high pause - // LOW data bit = IR mark + low pause - static const int LOW_BIT_DURATION = 421; - static const int HIGH_BIT_DURATION = 711; - static const int START_BIT_DURATION = 1184; - static const int STOP_BIT_DURATION = 1184; - static const int IR_MARK_DURATION = 158; - static const int HIGH_PAUSE_DURATION = HIGH_BIT_DURATION - IR_MARK_DURATION; - static const int LOW_PAUSE_DURATION = LOW_BIT_DURATION - IR_MARK_DURATION; - static const int START_PAUSE_DURATION = START_BIT_DURATION - IR_MARK_DURATION; - static const int STOP_PAUSE_DURATION = STOP_BIT_DURATION - IR_MARK_DURATION; - static const int MESSAGE_BITS = 18; - static const int MAX_MESSAGE_LENGTH = 16000; - - public: - void reset(uint16_t data, bool repeatMessage) { - this->data = data; - this->repeatMessage = repeatMessage; - messageBitIdx = 0; - repeatCount = 0; - messageLength = getMessageLength(); - } - - int getChannelId() const { return 1 + ((data >> 12) & 0x3); } - - int getMessageLength() const { - // Sum up all marks - int length = MESSAGE_BITS * IR_MARK_DURATION; - - // Sum up all pauses - length += START_PAUSE_DURATION; - for (unsigned long mask = 1UL << 15; mask; mask >>= 1) { - if (data & mask) { - length += HIGH_PAUSE_DURATION; - } else { - length += LOW_PAUSE_DURATION; - } - } - length += STOP_PAUSE_DURATION; - return length; - } - - boolean next() { - messageBitIdx++; - if (messageBitIdx >= MESSAGE_BITS) { - repeatCount++; - messageBitIdx = 0; - } - if (repeatCount >= 1 && !repeatMessage) { - return false; - } else if (repeatCount >= 5) { - return false; - } else { - return true; - } - } - - int getMarkDuration() const { return IR_MARK_DURATION; } - - int getPauseDuration() const { - if (messageBitIdx == 0) - return START_PAUSE_DURATION; - else if (messageBitIdx < MESSAGE_BITS - 1) { - return getDataBitPause(); - } else { - return getStopPause(); - } - } - - private: - int getDataBitPause() const { - const int pos = MESSAGE_BITS - 2 - messageBitIdx; - const bool isHigh = data & (1 << pos); - return isHigh ? HIGH_PAUSE_DURATION : LOW_PAUSE_DURATION; - } - - int getStopPause() const { - if (repeatMessage) { - return getRepeatStopPause(); - } else { - return STOP_PAUSE_DURATION; - } - } - - int getRepeatStopPause() const { - if (repeatCount == 0 || repeatCount == 1) { - return STOP_PAUSE_DURATION + 5 * MAX_MESSAGE_LENGTH - messageLength; - } else if (repeatCount == 2 || repeatCount == 3) { - return STOP_PAUSE_DURATION - + (6 + 2 * getChannelId()) * MAX_MESSAGE_LENGTH - messageLength; - } else { - return STOP_PAUSE_DURATION; - } - } -}; +#if DEBUG +namespace { +void logFunctionParameters(uint16_t data, bool repeat) { + DBG_PRINT("sendLegoPowerFunctions(data="); + DBG_PRINT(data); + DBG_PRINT(", repeat="); + DBG_PRINTLN(repeat?"true)" : "false)"); +} +} // anonymous namespace +#endif // DEBUG void IRsend::sendLegoPowerFunctions(uint16_t data, bool repeat) { +#if DEBUG + ::logFunctionParameters(data, repeat); +#endif // DEBUG + enableIROut(38); - static BitStreamEncoder bitStreamEncoder; + static LegoPfBitStreamEncoder bitStreamEncoder; bitStreamEncoder.reset(data, repeat); do { mark(bitStreamEncoder.getMarkDuration()); space(bitStreamEncoder.getPauseDuration()); } while (bitStreamEncoder.next()); } -#endif + +#endif // SEND_LEGO_PF diff --git a/ir_Lego_PF_BitStreamEncoder.h b/ir_Lego_PF_BitStreamEncoder.h new file mode 100644 index 000000000..7689cde28 --- /dev/null +++ b/ir_Lego_PF_BitStreamEncoder.h @@ -0,0 +1,115 @@ + +//============================================================================== +// L EEEEEE EEEE OOOO +// L E E O O +// L EEEE E EEE O O +// L E E E O O LEGO Power Functions +// LLLLLL EEEEEE EEEE OOOO Copyright (c) 2016 Philipp Henkel +//============================================================================== + +//+============================================================================= +// + +class LegoPfBitStreamEncoder { + private: + uint16_t data; + bool repeatMessage; + int messageBitIdx; + int repeatCount; + int messageLength; + + // HIGH data bit = IR mark + high pause + // LOW data bit = IR mark + low pause + static const int LOW_BIT_DURATION = 421; + static const int HIGH_BIT_DURATION = 711; + static const int START_BIT_DURATION = 1184; + static const int STOP_BIT_DURATION = 1184; + static const int IR_MARK_DURATION = 158; + static const int HIGH_PAUSE_DURATION = HIGH_BIT_DURATION - IR_MARK_DURATION; + static const int LOW_PAUSE_DURATION = LOW_BIT_DURATION - IR_MARK_DURATION; + static const int START_PAUSE_DURATION = START_BIT_DURATION - IR_MARK_DURATION; + static const int STOP_PAUSE_DURATION = STOP_BIT_DURATION - IR_MARK_DURATION; + static const int MESSAGE_BITS = 18; + static const int MAX_MESSAGE_LENGTH = 16000; + + public: + void reset(uint16_t data, bool repeatMessage) { + this->data = data; + this->repeatMessage = repeatMessage; + messageBitIdx = 0; + repeatCount = 0; + messageLength = getMessageLength(); + } + + int getChannelId() const { return 1 + ((data >> 12) & 0x3); } + + int getMessageLength() const { + // Sum up all marks + int length = MESSAGE_BITS * IR_MARK_DURATION; + + // Sum up all pauses + length += START_PAUSE_DURATION; + for (unsigned long mask = 1UL << 15; mask; mask >>= 1) { + if (data & mask) { + length += HIGH_PAUSE_DURATION; + } else { + length += LOW_PAUSE_DURATION; + } + } + length += STOP_PAUSE_DURATION; + return length; + } + + boolean next() { + messageBitIdx++; + if (messageBitIdx >= MESSAGE_BITS) { + repeatCount++; + messageBitIdx = 0; + } + if (repeatCount >= 1 && !repeatMessage) { + return false; + } else if (repeatCount >= 5) { + return false; + } else { + return true; + } + } + + int getMarkDuration() const { return IR_MARK_DURATION; } + + int getPauseDuration() const { + if (messageBitIdx == 0) + return START_PAUSE_DURATION; + else if (messageBitIdx < MESSAGE_BITS - 1) { + return getDataBitPause(); + } else { + return getStopPause(); + } + } + + private: + int getDataBitPause() const { + const int pos = MESSAGE_BITS - 2 - messageBitIdx; + const bool isHigh = data & (1 << pos); + return isHigh ? HIGH_PAUSE_DURATION : LOW_PAUSE_DURATION; + } + + int getStopPause() const { + if (repeatMessage) { + return getRepeatStopPause(); + } else { + return STOP_PAUSE_DURATION; + } + } + + int getRepeatStopPause() const { + if (repeatCount == 0 || repeatCount == 1) { + return STOP_PAUSE_DURATION + 5 * MAX_MESSAGE_LENGTH - messageLength; + } else if (repeatCount == 2 || repeatCount == 3) { + return STOP_PAUSE_DURATION + + (6 + 2 * getChannelId()) * MAX_MESSAGE_LENGTH - messageLength; + } else { + return STOP_PAUSE_DURATION; + } + } +}; From ec5a82bd934079f6186e687a5b4bff17ef955125 Mon Sep 17 00:00:00 2001 From: Hans Date: Fri, 15 Jul 2016 22:20:53 +0200 Subject: [PATCH 2/9] Added ATmega48 and ATmega88 --- IRremoteInt.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/IRremoteInt.h b/IRremoteInt.h index ca18bcd97..8cd6052c2 100644 --- a/IRremoteInt.h +++ b/IRremoteInt.h @@ -219,6 +219,7 @@ EXTERN volatile irparams_t irparams; #define IR_USE_TIMER_TINY0 // tx = pin 1 // Arduino Duemilanove, Diecimila, LilyPad, Mini, Fio, Nano, etc +// ATmega48, ATmega88, ATmega168, ATmega328 #else //#define IR_USE_TIMER1 // tx = pin 9 #define IR_USE_TIMER2 // tx = pin 3 @@ -280,7 +281,7 @@ EXTERN volatile irparams_t irparams; # define TIMER_PWM_PIN 14 // MightyCore #else # define TIMER_PWM_PIN 3 // Arduino Duemilanove, Diecimila, LilyPad, etc -#endif +#endif // ATmega48, ATmega88, ATmega168, ATmega328 //--------------------------------------------------------- // Timer1 (16 bits) @@ -338,7 +339,7 @@ EXTERN volatile irparams_t irparams; # define TIMER_PWM_PIN 6 #else # define TIMER_PWM_PIN 9 // Arduino Duemilanove, Diecimila, LilyPad, etc -#endif +#endif // ATmega48, ATmega88, ATmega168, ATmega328 //--------------------------------------------------------- // Timer3 (16 bits) From 9bf00849b3ea99ad7ec8987e60e24bf316cef282 Mon Sep 17 00:00:00 2001 From: Hans Date: Fri, 15 Jul 2016 22:25:01 +0200 Subject: [PATCH 3/9] Added ATmega48 and ATmega88 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d89580692..af2f6f7a3 100644 --- a/README.md +++ b/README.md @@ -32,9 +32,9 @@ We are open to suggestions for adding support to new boards, however we highly r |--------------------------------------------------------------------------|---------------------|-------------------| | [ATtiny84](https://github.com/SpenceKonde/ATTinyCore) | **6** | **1** | | [ATtiny85](https://github.com/SpenceKonde/ATTinyCore) | **1** | **TINY0** | -| ATmega8 | **9** | **1** | +| [ATmega8](https://github.com/MCUdude/MiniCore) | **9** | **1** | | Atmega32u4 | 5, 9, **13** | 1, 3, **4** | -| ATmega168, ATmega328 | **3**, 9 | 1, **2** | +| [ATmega48, ATmega88, ATmega168, ATmega328](https://github.com/MCUdude/MiniCore) | **3**, 9 | 1, **2** | | [ATmega1284](https://github.com/MCUdude/MightyCore) | 13, 14, 6 | 1, **2**, 3 | | [ATmega164, ATmega324, ATmega644](https://github.com/MCUdude/MightyCore) | 13, **14** | 1, **2** | | [ATmega8535 ATmega16, ATmega32](https://github.com/MCUdude/MightyCore) | **13** | **1** | From 75960b95f6bb6de243a89d4b57efb1b2d459f812 Mon Sep 17 00:00:00 2001 From: Hans Date: Fri, 15 Jul 2016 22:27:57 +0200 Subject: [PATCH 4/9] Added ATmega48 and ATmega88 --- examples/IRremoteInfo/IRremoteInfo.ino | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/IRremoteInfo/IRremoteInfo.ino b/examples/IRremoteInfo/IRremoteInfo.ino index b44097767..2a269d948 100644 --- a/examples/IRremoteInfo/IRremoteInfo.ino +++ b/examples/IRremoteInfo/IRremoteInfo.ino @@ -117,8 +117,12 @@ void dumpPlatform() { Serial.println(F("ATmega164")); #elif defined(__AVR_ATmega128__) Serial.println(F("ATmega128")); +#elif defined(__AVR_ATmega88__) || defined(__AVR_ATmega88P__) + Serial.println(F("ATmega88")); #elif defined(__AVR_ATmega64__) Serial.println(F("ATmega64")); +#elif defined(__AVR_ATmega48__) || defined(__AVR_ATmega48P__) + Serial.println(F("ATmega48")); #elif defined(__AVR_ATmega32__) Serial.println(F("ATmega32")); #elif defined(__AVR_ATmega16__) From 76e23159f2edb74580a67aaf66e983f8d3f63422 Mon Sep 17 00:00:00 2001 From: Hans Date: Fri, 15 Jul 2016 22:30:02 +0200 Subject: [PATCH 5/9] Added myself! --- Contributors.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Contributors.md b/Contributors.md index 1b559fea8..cabd0654e 100644 --- a/Contributors.md +++ b/Contributors.md @@ -16,5 +16,6 @@ These are the active contributors of this project that you may contact if there - [lumbric](https://github.com/lumbric): Contributor - [ElectricRCAircraftGuy](https://github.com/electricrcaircraftguy): Active Contributor - [henkel](https://github.com/henkel): Contributor +- [MCUdude](https://github.com/MCUdude): Contributor Note: This list is being updated constantly so please let [z3t0](https://github.com/z3t0) know if you have been missed. From b27398de74f798a7f1d200f31ddbadcdb3acd329 Mon Sep 17 00:00:00 2001 From: Hans Date: Fri, 22 Jul 2016 19:31:14 +0200 Subject: [PATCH 6/9] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index af2f6f7a3..7c473528c 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,9 @@ Check [here](http://z3t0.github.io/Arduino-IRremote/) for tutorials and more inf - Arduino Uno / Mega / Leonardo / Duemilanove / Diecimila / LilyPad / Mini / Fio / Nano etc. - Teensy 1.0 / 1.0++ / 2.0 / 2++ / 3.0 / 3.1 / Teensy-LC; Credits: @PaulStoffregen (Teensy Team) - Sanguino -- Atmega8535, 8, 16, 32, 164, 324, 644, 1284, 64, 128 +- ATmega8, 48, 88, 168, 328 +- ATmega8535, 16, 32, 164, 324, 644, 1284, +- ATmega64, 128 - ATtiny 84 / 85 We are open to suggestions for adding support to new boards, however we highly recommend you contact your supplier first and ask them to provide support from their side. From 8a767328dfdbab035e76c3001d93f36913b0a1fc Mon Sep 17 00:00:00 2001 From: Hans Meine Date: Mon, 25 Jul 2016 12:42:48 +0200 Subject: [PATCH 7/9] rephrase sentence linking to (to-do) tutorials --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7c473528c..77ccf7d1e 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ This library enables you to send and receive using infra-red signals on an Arduino. -Check [here](http://z3t0.github.io/Arduino-IRremote/) for tutorials and more information. +Tutorials and more information will be made available on [the official homepage](http://z3t0.github.io/Arduino-IRremote/). ## Version - 2.2.0 From a9385b92d8a566780eed8e4c93c89130edb4ed3f Mon Sep 17 00:00:00 2001 From: Philipp Henkel Date: Tue, 12 Jul 2016 23:14:47 +0200 Subject: [PATCH 8/9] Add Lego Power Functions tests --- .travis.yml | 1 + .../LegoPowerFunctionsTests.ino | 197 ++++++++++++++++++ ir_Lego_PF.cpp | 123 ++--------- ir_Lego_PF_BitStreamEncoder.h | 115 ++++++++++ 4 files changed, 331 insertions(+), 105 deletions(-) create mode 100644 examples/LegoPowerFunctionsTests/LegoPowerFunctionsTests.ino create mode 100644 ir_Lego_PF_BitStreamEncoder.h diff --git a/.travis.yml b/.travis.yml index ce01e805f..543a0a74b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,6 +20,7 @@ env: - PLATFORMIO_CI_SRC=examples/IRtest2 PLATFORMIO_BUILD_FLAGS="-DSEND_NEC -DSEND_SONY -DSEND_RC5 -DSEND_RC6" - PLATFORMIO_CI_SRC=examples/JVCPanasonicSendDemo PLATFORMIO_BUILD_FLAGS="-DSEND_JVC -DSEND_PANASONIC" - PLATFORMIO_CI_SRC=examples/LegoPowerFunctionsSendDemo PLATFORMIO_BUILD_FLAGS="-DSEND_LEGO_PF" + - PLATFORMIO_CI_SRC=examples/LegoPowerFunctionsTests PLATFORMIO_BUILD_FLAGS="-DSEND_LEGO_PF" - PLATFORMIO_CI_SRC=examples/IRremoteInfo install: diff --git a/examples/LegoPowerFunctionsTests/LegoPowerFunctionsTests.ino b/examples/LegoPowerFunctionsTests/LegoPowerFunctionsTests.ino new file mode 100644 index 000000000..6a2bda57d --- /dev/null +++ b/examples/LegoPowerFunctionsTests/LegoPowerFunctionsTests.ino @@ -0,0 +1,197 @@ +/* + * LegoPowerFunctionsTest: LEGO Power Functions Tests + * Copyright (c) 2016 Philipp Henkel + */ + +#include + +void setup() { + Serial.begin(9600); + delay(1000); // wait for reset triggered by serial connection + runBitStreamEncoderTests(); +} + +void loop() { +} + +void runBitStreamEncoderTests() { + Serial.println(); + Serial.println("BitStreamEncoder Tests"); + static LegoPfBitStreamEncoder bitStreamEncoder; + testStartBit(bitStreamEncoder); + testLowBit(bitStreamEncoder); + testHighBit(bitStreamEncoder); + testMessageBitCount(bitStreamEncoder); + testMessageBitCountRepeat(bitStreamEncoder); + testMessage407(bitStreamEncoder); + testMessage407Repeated(bitStreamEncoder); + testGetChannelId1(bitStreamEncoder); + testGetChannelId2(bitStreamEncoder); + testGetChannelId3(bitStreamEncoder); + testGetChannelId4(bitStreamEncoder); + testGetMessageLengthAllHigh(bitStreamEncoder); + testGetMessageLengthAllLow(bitStreamEncoder); +} + +void logTestResult(bool testPassed) { + if (testPassed) { + Serial.println("OK"); + } + else { + Serial.println("FAIL ############"); + } +} + +void testStartBit(LegoPfBitStreamEncoder& bitStreamEncoder) { + Serial.print(" testStartBit "); + bitStreamEncoder.reset(0, false); + int startMark = bitStreamEncoder.getMarkDuration(); + int startPause = bitStreamEncoder.getPauseDuration(); + logTestResult(startMark == 158 && startPause == 1184-158); +} + +void testLowBit(LegoPfBitStreamEncoder& bitStreamEncoder) { + Serial.print(" testLowBit "); + bitStreamEncoder.reset(0, false); + bitStreamEncoder.next(); + int lowMark = bitStreamEncoder.getMarkDuration(); + int lowPause = bitStreamEncoder.getPauseDuration(); + logTestResult(lowMark == 158 && lowPause == 421-158); +} + +void testHighBit(LegoPfBitStreamEncoder& bitStreamEncoder) { + Serial.print(" testHighBit "); + bitStreamEncoder.reset(0xFFFF, false); + bitStreamEncoder.next(); + int highMark = bitStreamEncoder.getMarkDuration(); + int highPause = bitStreamEncoder.getPauseDuration(); + logTestResult(highMark == 158 && highPause == 711-158); +} + +void testMessageBitCount(LegoPfBitStreamEncoder& bitStreamEncoder) { + Serial.print(" testMessageBitCount "); + bitStreamEncoder.reset(0xFFFF, false); + int bitCount = 1; + while (bitStreamEncoder.next()) { + bitCount++; + } + logTestResult(bitCount == 18); +} + +boolean check(LegoPfBitStreamEncoder& bitStreamEncoder, int markDuration, int pauseDuration) { + bool result = true; + result = result && bitStreamEncoder.getMarkDuration() == markDuration; + result = result && bitStreamEncoder.getPauseDuration() == pauseDuration; + return result; +} + +boolean checkNext(LegoPfBitStreamEncoder& bitStreamEncoder, int markDuration, int pauseDuration) { + bool result = bitStreamEncoder.next(); + result = result && check(bitStreamEncoder, markDuration, pauseDuration); + return result; +} + +boolean checkDataBitsOfMessage407(LegoPfBitStreamEncoder& bitStreamEncoder) { + bool result = true; + result = result && checkNext(bitStreamEncoder, 158, 263); + result = result && checkNext(bitStreamEncoder, 158, 263); + result = result && checkNext(bitStreamEncoder, 158, 263); + result = result && checkNext(bitStreamEncoder, 158, 263); + result = result && checkNext(bitStreamEncoder, 158, 263); + result = result && checkNext(bitStreamEncoder, 158, 263); + result = result && checkNext(bitStreamEncoder, 158, 263); + result = result && checkNext(bitStreamEncoder, 158, 553); + result = result && checkNext(bitStreamEncoder, 158, 553); + result = result && checkNext(bitStreamEncoder, 158, 263); + result = result && checkNext(bitStreamEncoder, 158, 263); + result = result && checkNext(bitStreamEncoder, 158, 553); + result = result && checkNext(bitStreamEncoder, 158, 263); + result = result && checkNext(bitStreamEncoder, 158, 553); + result = result && checkNext(bitStreamEncoder, 158, 553); + result = result && checkNext(bitStreamEncoder, 158, 553); + return result; +} + +void testMessage407(LegoPfBitStreamEncoder& bitStreamEncoder) { + Serial.print(" testMessage407 "); + bitStreamEncoder.reset(407, false); + bool result = true; + result = result && check(bitStreamEncoder, 158, 1026); + result = result && checkDataBitsOfMessage407(bitStreamEncoder); + result = result && checkNext(bitStreamEncoder, 158, 1026); + result = result && !bitStreamEncoder.next(); + logTestResult(result); +} + +void testMessage407Repeated(LegoPfBitStreamEncoder& bitStreamEncoder) { + Serial.print(" testMessage407Repeated "); + bitStreamEncoder.reset(407, true); + bool result = true; + result = result && check(bitStreamEncoder, 158, 1026); + result = result && checkDataBitsOfMessage407(bitStreamEncoder); + result = result && checkNext(bitStreamEncoder, 158, 1026 + 5 * 16000 - 10844); + result = result && checkNext(bitStreamEncoder, 158, 1026); + result = result && checkDataBitsOfMessage407(bitStreamEncoder); + result = result && checkNext(bitStreamEncoder, 158, 1026 + 5 * 16000 - 10844); + result = result && checkNext(bitStreamEncoder, 158, 1026); + result = result && checkDataBitsOfMessage407(bitStreamEncoder); + result = result && checkNext(bitStreamEncoder, 158, 1026 + 8 * 16000 - 10844); + result = result && checkNext(bitStreamEncoder, 158, 1026); + result = result && checkDataBitsOfMessage407(bitStreamEncoder); + result = result && checkNext(bitStreamEncoder, 158, 1026 + 8 * 16000 - 10844); + result = result && checkNext(bitStreamEncoder, 158, 1026); + result = result && checkDataBitsOfMessage407(bitStreamEncoder); + result = result && checkNext(bitStreamEncoder, 158, 1026); + result = result && !bitStreamEncoder.next(); + logTestResult(result); +} + +void testMessageBitCountRepeat(LegoPfBitStreamEncoder& bitStreamEncoder) { + Serial.print(" testMessageBitCountRepeat "); + bitStreamEncoder.reset(0xFFFF, true); + int bitCount = 1; + while (bitStreamEncoder.next()) { + bitCount++; + } + logTestResult(bitCount == 5*18); +} + +void testGetChannelId1(LegoPfBitStreamEncoder& bitStreamEncoder) { + Serial.print(" testGetChannelId1 "); + bitStreamEncoder.reset(407, false); + logTestResult(bitStreamEncoder.getChannelId() == 1); +} + +void testGetChannelId2(LegoPfBitStreamEncoder& bitStreamEncoder) { + Serial.print(" testGetChannelId2 "); + bitStreamEncoder.reset(4502, false); + logTestResult(bitStreamEncoder.getChannelId() == 2); +} + +void testGetChannelId3(LegoPfBitStreamEncoder& bitStreamEncoder) { + Serial.print(" testGetChannelId3 "); + bitStreamEncoder.reset(8597, false); + logTestResult(bitStreamEncoder.getChannelId() == 3); +} + +void testGetChannelId4(LegoPfBitStreamEncoder& bitStreamEncoder) { + Serial.print(" testGetChannelId4 "); + bitStreamEncoder.reset(12692, false); + logTestResult(bitStreamEncoder.getChannelId() == 4); +} + +void testGetMessageLengthAllHigh(LegoPfBitStreamEncoder& bitStreamEncoder) { + Serial.print(" testGetMessageLengthAllHigh "); + bitStreamEncoder.reset(0xFFFF, false); + logTestResult(bitStreamEncoder.getMessageLength() == 13744); +} + +void testGetMessageLengthAllLow(LegoPfBitStreamEncoder& bitStreamEncoder) { + Serial.print(" testGetMessageLengthAllLow "); + bitStreamEncoder.reset(0x0, false); + logTestResult(bitStreamEncoder.getMessageLength() == 9104); +} + + + + diff --git a/ir_Lego_PF.cpp b/ir_Lego_PF.cpp index 2196bed6f..37d507ceb 100644 --- a/ir_Lego_PF.cpp +++ b/ir_Lego_PF.cpp @@ -1,5 +1,6 @@ #include "IRremote.h" #include "IRremoteInt.h" +#include "ir_Lego_PF_BitStreamEncoder.h" //============================================================================== // L EEEEEE EEEE OOOO @@ -16,118 +17,30 @@ // #if SEND_LEGO_PF -class BitStreamEncoder { - private: - uint16_t data; - bool repeatMessage; - int messageBitIdx; - int repeatCount; - int messageLength; - - // HIGH data bit = IR mark + high pause - // LOW data bit = IR mark + low pause - static const int LOW_BIT_DURATION = 421; - static const int HIGH_BIT_DURATION = 711; - static const int START_BIT_DURATION = 1184; - static const int STOP_BIT_DURATION = 1184; - static const int IR_MARK_DURATION = 158; - static const int HIGH_PAUSE_DURATION = HIGH_BIT_DURATION - IR_MARK_DURATION; - static const int LOW_PAUSE_DURATION = LOW_BIT_DURATION - IR_MARK_DURATION; - static const int START_PAUSE_DURATION = START_BIT_DURATION - IR_MARK_DURATION; - static const int STOP_PAUSE_DURATION = STOP_BIT_DURATION - IR_MARK_DURATION; - static const int MESSAGE_BITS = 18; - static const int MAX_MESSAGE_LENGTH = 16000; - - public: - void reset(uint16_t data, bool repeatMessage) { - this->data = data; - this->repeatMessage = repeatMessage; - messageBitIdx = 0; - repeatCount = 0; - messageLength = getMessageLength(); - } - - int getChannelId() const { return 1 + ((data >> 12) & 0x3); } - - int getMessageLength() const { - // Sum up all marks - int length = MESSAGE_BITS * IR_MARK_DURATION; - - // Sum up all pauses - length += START_PAUSE_DURATION; - for (unsigned long mask = 1UL << 15; mask; mask >>= 1) { - if (data & mask) { - length += HIGH_PAUSE_DURATION; - } else { - length += LOW_PAUSE_DURATION; - } - } - length += STOP_PAUSE_DURATION; - return length; - } - - boolean next() { - messageBitIdx++; - if (messageBitIdx >= MESSAGE_BITS) { - repeatCount++; - messageBitIdx = 0; - } - if (repeatCount >= 1 && !repeatMessage) { - return false; - } else if (repeatCount >= 5) { - return false; - } else { - return true; - } - } - - int getMarkDuration() const { return IR_MARK_DURATION; } - - int getPauseDuration() const { - if (messageBitIdx == 0) - return START_PAUSE_DURATION; - else if (messageBitIdx < MESSAGE_BITS - 1) { - return getDataBitPause(); - } else { - return getStopPause(); - } - } - - private: - int getDataBitPause() const { - const int pos = MESSAGE_BITS - 2 - messageBitIdx; - const bool isHigh = data & (1 << pos); - return isHigh ? HIGH_PAUSE_DURATION : LOW_PAUSE_DURATION; - } - - int getStopPause() const { - if (repeatMessage) { - return getRepeatStopPause(); - } else { - return STOP_PAUSE_DURATION; - } - } - - int getRepeatStopPause() const { - if (repeatCount == 0 || repeatCount == 1) { - return STOP_PAUSE_DURATION + 5 * MAX_MESSAGE_LENGTH - messageLength; - } else if (repeatCount == 2 || repeatCount == 3) { - return STOP_PAUSE_DURATION - + (6 + 2 * getChannelId()) * MAX_MESSAGE_LENGTH - messageLength; - } else { - return STOP_PAUSE_DURATION; - } - } -}; +#if DEBUG +namespace { +void logFunctionParameters(uint16_t data, bool repeat) { + DBG_PRINT("sendLegoPowerFunctions(data="); + DBG_PRINT(data); + DBG_PRINT(", repeat="); + DBG_PRINTLN(repeat?"true)" : "false)"); +} +} // anonymous namespace +#endif // DEBUG void IRsend::sendLegoPowerFunctions(uint16_t data, bool repeat) { +#if DEBUG + ::logFunctionParameters(data, repeat); +#endif // DEBUG + enableIROut(38); - static BitStreamEncoder bitStreamEncoder; + static LegoPfBitStreamEncoder bitStreamEncoder; bitStreamEncoder.reset(data, repeat); do { mark(bitStreamEncoder.getMarkDuration()); space(bitStreamEncoder.getPauseDuration()); } while (bitStreamEncoder.next()); } -#endif + +#endif // SEND_LEGO_PF diff --git a/ir_Lego_PF_BitStreamEncoder.h b/ir_Lego_PF_BitStreamEncoder.h new file mode 100644 index 000000000..7689cde28 --- /dev/null +++ b/ir_Lego_PF_BitStreamEncoder.h @@ -0,0 +1,115 @@ + +//============================================================================== +// L EEEEEE EEEE OOOO +// L E E O O +// L EEEE E EEE O O +// L E E E O O LEGO Power Functions +// LLLLLL EEEEEE EEEE OOOO Copyright (c) 2016 Philipp Henkel +//============================================================================== + +//+============================================================================= +// + +class LegoPfBitStreamEncoder { + private: + uint16_t data; + bool repeatMessage; + int messageBitIdx; + int repeatCount; + int messageLength; + + // HIGH data bit = IR mark + high pause + // LOW data bit = IR mark + low pause + static const int LOW_BIT_DURATION = 421; + static const int HIGH_BIT_DURATION = 711; + static const int START_BIT_DURATION = 1184; + static const int STOP_BIT_DURATION = 1184; + static const int IR_MARK_DURATION = 158; + static const int HIGH_PAUSE_DURATION = HIGH_BIT_DURATION - IR_MARK_DURATION; + static const int LOW_PAUSE_DURATION = LOW_BIT_DURATION - IR_MARK_DURATION; + static const int START_PAUSE_DURATION = START_BIT_DURATION - IR_MARK_DURATION; + static const int STOP_PAUSE_DURATION = STOP_BIT_DURATION - IR_MARK_DURATION; + static const int MESSAGE_BITS = 18; + static const int MAX_MESSAGE_LENGTH = 16000; + + public: + void reset(uint16_t data, bool repeatMessage) { + this->data = data; + this->repeatMessage = repeatMessage; + messageBitIdx = 0; + repeatCount = 0; + messageLength = getMessageLength(); + } + + int getChannelId() const { return 1 + ((data >> 12) & 0x3); } + + int getMessageLength() const { + // Sum up all marks + int length = MESSAGE_BITS * IR_MARK_DURATION; + + // Sum up all pauses + length += START_PAUSE_DURATION; + for (unsigned long mask = 1UL << 15; mask; mask >>= 1) { + if (data & mask) { + length += HIGH_PAUSE_DURATION; + } else { + length += LOW_PAUSE_DURATION; + } + } + length += STOP_PAUSE_DURATION; + return length; + } + + boolean next() { + messageBitIdx++; + if (messageBitIdx >= MESSAGE_BITS) { + repeatCount++; + messageBitIdx = 0; + } + if (repeatCount >= 1 && !repeatMessage) { + return false; + } else if (repeatCount >= 5) { + return false; + } else { + return true; + } + } + + int getMarkDuration() const { return IR_MARK_DURATION; } + + int getPauseDuration() const { + if (messageBitIdx == 0) + return START_PAUSE_DURATION; + else if (messageBitIdx < MESSAGE_BITS - 1) { + return getDataBitPause(); + } else { + return getStopPause(); + } + } + + private: + int getDataBitPause() const { + const int pos = MESSAGE_BITS - 2 - messageBitIdx; + const bool isHigh = data & (1 << pos); + return isHigh ? HIGH_PAUSE_DURATION : LOW_PAUSE_DURATION; + } + + int getStopPause() const { + if (repeatMessage) { + return getRepeatStopPause(); + } else { + return STOP_PAUSE_DURATION; + } + } + + int getRepeatStopPause() const { + if (repeatCount == 0 || repeatCount == 1) { + return STOP_PAUSE_DURATION + 5 * MAX_MESSAGE_LENGTH - messageLength; + } else if (repeatCount == 2 || repeatCount == 3) { + return STOP_PAUSE_DURATION + + (6 + 2 * getChannelId()) * MAX_MESSAGE_LENGTH - messageLength; + } else { + return STOP_PAUSE_DURATION; + } + } +}; From b26b64f87126afd573b12d7bd5a2ec3008182659 Mon Sep 17 00:00:00 2001 From: Philipp Henkel Date: Wed, 27 Jul 2016 07:25:52 +0200 Subject: [PATCH 9/9] Update changelog and version info --- README.md | 2 +- changelog.md | 3 +++ library.json | 2 +- library.properties | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 77ccf7d1e..48ddfc986 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ This library enables you to send and receive using infra-red signals on an Ardui Tutorials and more information will be made available on [the official homepage](http://z3t0.github.io/Arduino-IRremote/). -## Version - 2.2.0 +## Version - 2.2.1 ## Installation 1. Navigate to the [Releases](https://github.com/z3t0/Arduino-IRremote/releases) page. diff --git a/changelog.md b/changelog.md index 297ffd479..fbe70b457 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,6 @@ +## 2.2.1 - 2016/07/27 +- Added tests for Lego Power Functions Protocol [PR #336](https://github.com/z3t0/Arduino-IRremote/pull/336) + ## 2.2.0 - 2016/06/28 - Added support for ATmega8535 - Added support for ATmega16 diff --git a/library.json b/library.json index b62b0de37..090578d10 100644 --- a/library.json +++ b/library.json @@ -7,7 +7,7 @@ "type": "git", "url": "https://github.com/z3t0/Arduino-IRremote.git" }, - "version": "2.1.0", + "version": "2.2.1", "frameworks": "arduino", "platforms": "atmelavr", "authors" : diff --git a/library.properties b/library.properties index 3553dc1fc..15aabee44 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=IRremote -version=2.0.1 +version=2.2.1 author=shirriff maintainer=shirriff sentence=Send and receive infrared signals with multiple protocols