PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

116 lines
3.5KB

  1. //==============================================================================
  2. // L EEEEEE EEEE OOOO
  3. // L E E O O
  4. // L EEEE E EEE O O
  5. // L E E E O O LEGO Power Functions
  6. // LLLLLL EEEEEE EEEE OOOO Copyright (c) 2016, 2017 Philipp Henkel
  7. //==============================================================================
  8. //+=============================================================================
  9. //
  10. class LegoPfBitStreamEncoder {
  11. private:
  12. uint16_t data;
  13. bool repeatMessage;
  14. uint8_t messageBitIdx;
  15. uint8_t repeatCount;
  16. uint16_t messageLength;
  17. public:
  18. // HIGH data bit = IR mark + high pause
  19. // LOW data bit = IR mark + low pause
  20. static const uint16_t LOW_BIT_DURATION = 421;
  21. static const uint16_t HIGH_BIT_DURATION = 711;
  22. static const uint16_t START_BIT_DURATION = 1184;
  23. static const uint16_t STOP_BIT_DURATION = 1184;
  24. static const uint8_t IR_MARK_DURATION = 158;
  25. static const uint16_t HIGH_PAUSE_DURATION = HIGH_BIT_DURATION - IR_MARK_DURATION;
  26. static const uint16_t LOW_PAUSE_DURATION = LOW_BIT_DURATION - IR_MARK_DURATION;
  27. static const uint16_t START_PAUSE_DURATION = START_BIT_DURATION - IR_MARK_DURATION;
  28. static const uint16_t STOP_PAUSE_DURATION = STOP_BIT_DURATION - IR_MARK_DURATION;
  29. static const uint8_t MESSAGE_BITS = 18;
  30. static const uint16_t MAX_MESSAGE_LENGTH = 16000;
  31. void reset(uint16_t data, bool repeatMessage) {
  32. this->data = data;
  33. this->repeatMessage = repeatMessage;
  34. messageBitIdx = 0;
  35. repeatCount = 0;
  36. messageLength = getMessageLength();
  37. }
  38. int getChannelId() const { return 1 + ((data >> 12) & 0x3); }
  39. uint16_t getMessageLength() const {
  40. // Sum up all marks
  41. uint16_t length = MESSAGE_BITS * IR_MARK_DURATION;
  42. // Sum up all pauses
  43. length += START_PAUSE_DURATION;
  44. for (unsigned long mask = 1UL << 15; mask; mask >>= 1) {
  45. if (data & mask) {
  46. length += HIGH_PAUSE_DURATION;
  47. } else {
  48. length += LOW_PAUSE_DURATION;
  49. }
  50. }
  51. length += STOP_PAUSE_DURATION;
  52. return length;
  53. }
  54. boolean next() {
  55. messageBitIdx++;
  56. if (messageBitIdx >= MESSAGE_BITS) {
  57. repeatCount++;
  58. messageBitIdx = 0;
  59. }
  60. if (repeatCount >= 1 && !repeatMessage) {
  61. return false;
  62. } else if (repeatCount >= 5) {
  63. return false;
  64. } else {
  65. return true;
  66. }
  67. }
  68. uint8_t getMarkDuration() const { return IR_MARK_DURATION; }
  69. uint32_t getPauseDuration() const {
  70. if (messageBitIdx == 0)
  71. return START_PAUSE_DURATION;
  72. else if (messageBitIdx < MESSAGE_BITS - 1) {
  73. return getDataBitPause();
  74. } else {
  75. return getStopPause();
  76. }
  77. }
  78. private:
  79. uint16_t getDataBitPause() const {
  80. const int pos = MESSAGE_BITS - 2 - messageBitIdx;
  81. const bool isHigh = data & (1 << pos);
  82. return isHigh ? HIGH_PAUSE_DURATION : LOW_PAUSE_DURATION;
  83. }
  84. uint32_t getStopPause() const {
  85. if (repeatMessage) {
  86. return getRepeatStopPause();
  87. } else {
  88. return STOP_PAUSE_DURATION;
  89. }
  90. }
  91. uint32_t getRepeatStopPause() const {
  92. if (repeatCount == 0 || repeatCount == 1) {
  93. return STOP_PAUSE_DURATION + (uint32_t)5 * MAX_MESSAGE_LENGTH - messageLength;
  94. } else if (repeatCount == 2 || repeatCount == 3) {
  95. return STOP_PAUSE_DURATION
  96. + (uint32_t)(6 + 2 * getChannelId()) * MAX_MESSAGE_LENGTH - messageLength;
  97. } else {
  98. return STOP_PAUSE_DURATION;
  99. }
  100. }
  101. };