Skip to content

Commit 34e5cd8

Browse files
committed
Add Lego Power Functions send protocol
1 parent d064c7d commit 34e5cd8

File tree

5 files changed

+173
-3
lines changed

5 files changed

+173
-3
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ env:
1919
- PLATFORMIO_CI_SRC=examples/IRtest PLATFORMIO_BUILD_FLAGS="-DSEND_NEC -DSEND_SONY -DSEND_RC5 -DSEND_RC6"
2020
- PLATFORMIO_CI_SRC=examples/IRtest2 PLATFORMIO_BUILD_FLAGS="-DSEND_NEC -DSEND_SONY -DSEND_RC5 -DSEND_RC6"
2121
- PLATFORMIO_CI_SRC=examples/JVCPanasonicSendDemo PLATFORMIO_BUILD_FLAGS="-DSEND_JVC -DSEND_PANASONIC"
22+
- PLATFORMIO_CI_SRC=examples/LegoPowerFunctionsSendDemo PLATFORMIO_BUILD_FLAGS="-DSEND_LEGO_PF"
2223
- PLATFORMIO_CI_SRC=examples/IRremoteInfo
2324

2425
install:

IRremote.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
#define SEND_AIWA_RC_T501 1
5757

5858
#define DECODE_LG 1
59-
#define SEND_LG 1
59+
#define SEND_LG 1
6060

6161
#define DECODE_SANYO 1
6262
#define SEND_SANYO 0 // NOT WRITTEN
@@ -76,6 +76,9 @@
7676
#define DECODE_PRONTO 0 // This function doe not logically make sense
7777
#define SEND_PRONTO 1
7878

79+
#define DECODE_LEGO_PF 0 // NOT WRITTEN
80+
#define SEND_LEGO_PF 1
81+
7982
//------------------------------------------------------------------------------
8083
// When sending a Pronto code we request to send either the "once" code
8184
// or the "repeat" code
@@ -115,6 +118,7 @@ typedef
115118
SHARP,
116119
DENON,
117120
PRONTO,
121+
LEGO_PF,
118122
}
119123
decode_type_t;
120124

@@ -243,6 +247,10 @@ class IRrecv
243247
# if DECODE_DENON
244248
bool decodeDenon (decode_results *results) ;
245249
# endif
250+
//......................................................................
251+
# if DECODE_LEGO_PF
252+
bool decodeLegoPowerFunctions (decode_results *results) ;
253+
# endif
246254
} ;
247255

248256
//------------------------------------------------------------------------------
@@ -327,6 +335,10 @@ class IRsend
327335
# if SEND_PRONTO
328336
void sendPronto (char* code, bool repeat, bool fallback) ;
329337
# endif
338+
//......................................................................
339+
# if SEND_LEGO_PF
340+
void sendLegoPowerFunctions (uint16_t data, bool repeat = true) ;
341+
# endif
330342
} ;
331343

332344
#endif
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* LegoPowerFunctionsSendDemo: LEGO Power Functions
3+
* Copyright (c) 2016 Philipp Henkel
4+
*/
5+
6+
#include <IRremote.h>
7+
#include <IRremoteInt.h>
8+
9+
IRsend irsend;
10+
11+
void setup() {
12+
}
13+
14+
void loop() {
15+
// Send repeated command "channel 1, blue forward, red backward"
16+
irsend.sendLegoPowerFunctions(0x197);
17+
delay(2000);
18+
19+
// Send single command "channel 1, blue forward, red backward"
20+
irsend.sendLegoPowerFunctions(0x197, false);
21+
delay(2000);
22+
}

irRecv.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ int IRrecv::decode (decode_results *results)
8080
if (decodeDenon(results)) return true ;
8181
#endif
8282

83+
#if DECODE_LEGO_PF
84+
DBG_PRINTLN("Attempting Lego Power Functions");
85+
if (decodeLegoPowerFunctions(results)) return true ;
86+
#endif
87+
8388
// decodeHash returns a hash on any input.
8489
// Thus, it needs to be last in the list.
8590
// If you add any decodes, add them before this.
@@ -145,8 +150,8 @@ void IRrecv::blink13 (int blinkflag)
145150

146151
//+=============================================================================
147152
// Return if receiving new IR signals
148-
//
149-
bool IRrecv::isIdle ( )
153+
//
154+
bool IRrecv::isIdle ( )
150155
{
151156
return (irparams.rcvstate == STATE_IDLE || irparams.rcvstate == STATE_STOP) ? true : false;
152157
}

ir_Lego_PF.cpp

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

0 commit comments

Comments
 (0)