| 
 | 1 | +#include "IRremote.h"  | 
 | 2 | +#include "IRremoteInt.h"  | 
 | 3 | + | 
 | 4 | +//==============================================================================  | 
 | 5 | +// L EEEEEE EEEE OOOO  | 
 | 6 | +// L E E O O  | 
 | 7 | +// L EEEE E EEE O O  | 
 | 8 | +// L E E E O O LEGO Power Functions  | 
 | 9 | +// LLLLLL EEEEEE EEEE OOOO Copyright (c) 2016 Philipp Henkel  | 
 | 10 | +//==============================================================================  | 
 | 11 | + | 
 | 12 | +// Supported Devices  | 
 | 13 | +// LEGO® Power Functions IR Receiver 8884  | 
 | 14 | + | 
 | 15 | +//+=============================================================================  | 
 | 16 | +//  | 
 | 17 | +#if SEND_LEGO_PF  | 
 | 18 | + | 
 | 19 | +class BitStreamEncoder {  | 
 | 20 | + private:  | 
 | 21 | + uint16_t data;  | 
 | 22 | + bool repeatMessage;  | 
 | 23 | + int messageBitIdx;  | 
 | 24 | + int repeatCount;  | 
 | 25 | + int messageLength;  | 
 | 26 | + | 
 | 27 | + // HIGH data bit = IR mark + high pause  | 
 | 28 | + // LOW data bit = IR mark + low pause  | 
 | 29 | + static const int LOW_BIT_DURATION = 421;  | 
 | 30 | + static const int HIGH_BIT_DURATION = 711;  | 
 | 31 | + static const int START_BIT_DURATION = 1184;  | 
 | 32 | + static const int STOP_BIT_DURATION = 1184;  | 
 | 33 | + static const int IR_MARK_DURATION = 158;  | 
 | 34 | + static const int HIGH_PAUSE_DURATION = HIGH_BIT_DURATION - IR_MARK_DURATION;  | 
 | 35 | + static const int LOW_PAUSE_DURATION = LOW_BIT_DURATION - IR_MARK_DURATION;  | 
 | 36 | + static const int START_PAUSE_DURATION = START_BIT_DURATION - IR_MARK_DURATION;  | 
 | 37 | + static const int STOP_PAUSE_DURATION = STOP_BIT_DURATION - IR_MARK_DURATION;  | 
 | 38 | + static const int MESSAGE_BITS = 18;  | 
 | 39 | + static const int MAX_MESSAGE_LENGTH = 16000;  | 
 | 40 | + | 
 | 41 | + public:  | 
 | 42 | + void reset(uint16_t data, bool repeatMessage) {  | 
 | 43 | + this->data = data;  | 
 | 44 | + this->repeatMessage = repeatMessage;  | 
 | 45 | + messageBitIdx = 0;  | 
 | 46 | + repeatCount = 0;  | 
 | 47 | + messageLength = getMessageLength();  | 
 | 48 | + }  | 
 | 49 | + | 
 | 50 | + int getChannelId() const { return 1 + ((data >> 12) & 0x3); }  | 
 | 51 | + | 
 | 52 | + int getMessageLength() const {  | 
 | 53 | + // Sum up all marks  | 
 | 54 | + int length = MESSAGE_BITS * IR_MARK_DURATION;  | 
 | 55 | + | 
 | 56 | + // Sum up all pauses  | 
 | 57 | + length += START_PAUSE_DURATION;  | 
 | 58 | + for (unsigned long mask = 1UL << 15; mask; mask >>= 1) {  | 
 | 59 | + if (data & mask) {  | 
 | 60 | + length += HIGH_PAUSE_DURATION;  | 
 | 61 | + } else {  | 
 | 62 | + length += LOW_PAUSE_DURATION;  | 
 | 63 | + }  | 
 | 64 | + }  | 
 | 65 | + length += STOP_PAUSE_DURATION;  | 
 | 66 | + return length;  | 
 | 67 | + }  | 
 | 68 | + | 
 | 69 | + boolean next() {  | 
 | 70 | + messageBitIdx++;  | 
 | 71 | + if (messageBitIdx >= MESSAGE_BITS) {  | 
 | 72 | + repeatCount++;  | 
 | 73 | + messageBitIdx = 0;  | 
 | 74 | + }  | 
 | 75 | + if (repeatCount >= 1 && !repeatMessage) {  | 
 | 76 | + return false;  | 
 | 77 | + } else if (repeatCount >= 5) {  | 
 | 78 | + return false;  | 
 | 79 | + } else {  | 
 | 80 | + return true;  | 
 | 81 | + }  | 
 | 82 | + }  | 
 | 83 | + | 
 | 84 | + int getMarkDuration() const { return IR_MARK_DURATION; }  | 
 | 85 | + | 
 | 86 | + int getPauseDuration() const {  | 
 | 87 | + if (messageBitIdx == 0)  | 
 | 88 | + return START_PAUSE_DURATION;  | 
 | 89 | + else if (messageBitIdx < MESSAGE_BITS - 1) {  | 
 | 90 | + return getDataBitPause();  | 
 | 91 | + } else {  | 
 | 92 | + return getStopPause();  | 
 | 93 | + }  | 
 | 94 | + }  | 
 | 95 | + | 
 | 96 | + private:  | 
 | 97 | + int getDataBitPause() const {  | 
 | 98 | + const int pos = MESSAGE_BITS - 2 - messageBitIdx;  | 
 | 99 | + const bool isHigh = data & (1 << pos);  | 
 | 100 | + return isHigh ? HIGH_PAUSE_DURATION : LOW_PAUSE_DURATION;  | 
 | 101 | + }  | 
 | 102 | + | 
 | 103 | + int getStopPause() const {  | 
 | 104 | + if (repeatMessage) {  | 
 | 105 | + return getRepeatStopPause();  | 
 | 106 | + } else {  | 
 | 107 | + return STOP_PAUSE_DURATION;  | 
 | 108 | + }  | 
 | 109 | + }  | 
 | 110 | + | 
 | 111 | + int getRepeatStopPause() const {  | 
 | 112 | + if (repeatCount == 0 || repeatCount == 1) {  | 
 | 113 | + return STOP_PAUSE_DURATION + 5 * MAX_MESSAGE_LENGTH - messageLength;  | 
 | 114 | + } else if (repeatCount == 2 || repeatCount == 3) {  | 
 | 115 | + return STOP_PAUSE_DURATION  | 
 | 116 | + + (6 + 2 * getChannelId()) * MAX_MESSAGE_LENGTH - messageLength;  | 
 | 117 | + } else {  | 
 | 118 | + return STOP_PAUSE_DURATION;  | 
 | 119 | + }  | 
 | 120 | + }  | 
 | 121 | +};  | 
 | 122 | + | 
 | 123 | +void IRsend::sendLegoPowerFunctions(uint16_t data, bool repeat)  | 
 | 124 | +{  | 
 | 125 | + enableIROut(38);  | 
 | 126 | + static BitStreamEncoder bitStreamEncoder;  | 
 | 127 | + bitStreamEncoder.reset(data, repeat);  | 
 | 128 | + do {  | 
 | 129 | + mark(bitStreamEncoder.getMarkDuration());  | 
 | 130 | + space(bitStreamEncoder.getPauseDuration());  | 
 | 131 | + } while (bitStreamEncoder.next());  | 
 | 132 | +}  | 
 | 133 | +#endif  | 
0 commit comments