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/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. 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) diff --git a/README.md b/README.md index d89580692..48ddfc986 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,9 @@ 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 +## Version - 2.2.1 ## Installation 1. Navigate to the [Releases](https://github.com/z3t0/Arduino-IRremote/releases) page. @@ -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. @@ -32,9 +34,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** | 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/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__) 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; + } + } +}; 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