Add Lego Power Functions tests

This commit is contained in:
Philipp Henkel
2016-07-12 23:14:47 +02:00
parent 9095dddbfe
commit 749125db09
4 changed files with 331 additions and 105 deletions

View File

@@ -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:

View File

@@ -0,0 +1,197 @@
/*
* LegoPowerFunctionsTest: LEGO Power Functions Tests
* Copyright (c) 2016 Philipp Henkel
*/
#include <ir_Lego_PF_BitStreamEncoder.h>
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);
}

View File

@@ -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

View File

@@ -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;
}
}
};