//============================================================================== // 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, 2017 Philipp Henkel //============================================================================== //+============================================================================= // class LegoPfBitStreamEncoder { private: uint16_t data; bool repeatMessage; uint8_t messageBitIdx; uint8_t repeatCount; uint16_t messageLength; public: // HIGH data bit = IR mark + high pause // LOW data bit = IR mark + low pause static const uint16_t LOW_BIT_DURATION = 421; static const uint16_t HIGH_BIT_DURATION = 711; static const uint16_t START_BIT_DURATION = 1184; static const uint16_t STOP_BIT_DURATION = 1184; static const uint8_t IR_MARK_DURATION = 158; static const uint16_t HIGH_PAUSE_DURATION = HIGH_BIT_DURATION - IR_MARK_DURATION; static const uint16_t LOW_PAUSE_DURATION = LOW_BIT_DURATION - IR_MARK_DURATION; static const uint16_t START_PAUSE_DURATION = START_BIT_DURATION - IR_MARK_DURATION; static const uint16_t STOP_PAUSE_DURATION = STOP_BIT_DURATION - IR_MARK_DURATION; static const uint8_t MESSAGE_BITS = 18; static const uint16_t MAX_MESSAGE_LENGTH = 16000; 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); } uint16_t getMessageLength() const { // Sum up all marks uint16_t 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; } } uint8_t getMarkDuration() const { return IR_MARK_DURATION; } uint32_t getPauseDuration() const { if (messageBitIdx == 0) return START_PAUSE_DURATION; else if (messageBitIdx < MESSAGE_BITS - 1) { return getDataBitPause(); } else { return getStopPause(); } } private: uint16_t getDataBitPause() const { const int pos = MESSAGE_BITS - 2 - messageBitIdx; const bool isHigh = data & (1 << pos); return isHigh ? HIGH_PAUSE_DURATION : LOW_PAUSE_DURATION; } uint32_t getStopPause() const { if (repeatMessage) { return getRepeatStopPause(); } else { return STOP_PAUSE_DURATION; } } uint32_t getRepeatStopPause() const { if (repeatCount == 0 || repeatCount == 1) { return STOP_PAUSE_DURATION + (uint32_t)5 * MAX_MESSAGE_LENGTH - messageLength; } else if (repeatCount == 2 || repeatCount == 3) { return STOP_PAUSE_DURATION + (uint32_t)(6 + 2 * getChannelId()) * MAX_MESSAGE_LENGTH - messageLength; } else { return STOP_PAUSE_DURATION; } } };