1 #include "mceprotocol.h"
3 #include "pirrx51hardware.h"
5 #include "pirexception.h"
8 extern bool commandInFlight;
9 extern QMutex commandIFMutex;
11 // These defines might need to be turned into variables, for odd devices.
12 #define HEADER_PULSE 2666
13 #define HEADER_SPACE 888
14 #define TRAILER_BIPHASE 888
16 // Ok, what I've got on MCE protocol is this:
17 // It is based on RC6 mode 6A, with a few odd tweaks.
18 // The biphase unit of time is 444 usec.
19 // The RC6 header block starts with the normal 2666 usec pulse, 888 usec space.
20 // The next bit is fixed as a "1", as usual.
21 // The next three bits are 110, marking this as a mode 6 protocol.
22 // The trailer bit has an 888 usec biphase, is set to 0, and is _not_ toggled!
23 // The next 16 bits I'm not sure about. Hopefully they will be a fixed value
24 // for any given device...
25 // Then, the next bit is the new toggle bit.
26 // Following this, there are seven "device address" bits, and then eight
28 // A space of (at least) 2666 usec must follow any command.
29 // The carrier frequency is 36 kHZ, duty cycle between 25 and 50 %.
31 MCEProtocol::MCEProtocol(
35 : PIRProtocol(guiObject, index, 2666, false),
40 setCarrierFrequency(36000);
41 appendToBitSeq(oemBits, oemData, 16);
45 void MCEProtocol::startSendingCommand(
46 unsigned int threadableID,
51 // Is this command meant for us?
52 if (threadableID != id) return;
56 KeycodeCollection::const_iterator i = keycodes.find(command);
59 if (i == keycodes.end())
61 QMutexLocker cifLocker(&commandIFMutex);
62 commandInFlight = false;
64 // std::string s = "Tried to send a non-existent command.\n";
65 // throw PIRException(s);
68 PIRRX51Hardware rx51device(carrierFrequency, dutyCycle);
72 while (repeatCount < MAX_REPEAT_COUNT)
74 bufferContainsSpace = false;
75 bufferContainsPulse = false;
76 // First, construct the "Header" segment of the pulse train.
78 // The header involves:
79 // a) a "lead" of 2666 us pulse, 888 us space;
80 // b) a "start bit", value 1 (so 444 us pulse, 444 us space)
81 // c) three control bits, set to "110" (i.e., mode "6")
82 // d) the double-sized "trailer" bit, set to 0.
84 rx51device.addSingle(HEADER_PULSE); // lead pulse
85 duration += HEADER_PULSE;
86 rx51device.addSingle(HEADER_SPACE); // lead space
87 duration += HEADER_SPACE;
88 rx51device.addSingle(biphaseUnit); // start bit pulse
89 duration += biphaseUnit;
90 rx51device.addSingle(biphaseUnit); // start bit space
91 duration += biphaseUnit;
92 rx51device.addSingle(biphaseUnit); // bit 1 pulse;
93 duration += biphaseUnit;
94 rx51device.addSingle(biphaseUnit); // bit 1 space;
95 duration += biphaseUnit;
96 rx51device.addSingle(biphaseUnit); // bit 2 pulse;
97 duration += biphaseUnit;
98 rx51device.addSingle(2 * biphaseUnit); // bit 2 space + bit 3 space;
99 duration += 2 * biphaseUnit;
100 rx51device.addSingle(biphaseUnit); // bit 3 pulse;
101 duration += biphaseUnit;
102 rx51device.addSingle(2 * biphaseUnit); // trailer space
103 duration += 2 * biphaseUnit;
104 buffer = 2 * biphaseUnit; // trailer pulse goes into the buffer
105 bufferContainsPulse = true;
107 // Now, we can start the normal buffering process:
109 // push the "OEM" data:
110 duration += pushBits(oemBits, rx51device);
112 // The next bit is the MCE toggle bit:
113 if (keypressCount % 2)
119 pushZero(rx51device);
122 // push the device address data:
123 duration += pushBits(preData, rx51device);
125 // push the command data:
126 duration += pushBits((*i).second.firstCode, rx51device);
128 // Flush out the buffer, if necessary:
131 rx51device.addSingle(buffer);
136 // Actually send out the command:
137 rx51device.sendCommandToDevice();
139 // Sleep for an amount of time. (RC6 demands an addtional 6 unit space
140 // at the end of any command...)
141 sleepUntilRepeat(duration + 6 * biphaseUnit);
143 // Have we been told to stop yet?
144 if (checkRepeatFlag())
146 // Yes, we can now quit repeating:
150 QMutexLocker ciflocker(&commandIFMutex);
151 commandInFlight = false;
158 QMutexLocker cifLocker(&commandIFMutex);
159 commandInFlight = false;
161 catch (PIRException e)
163 emit commandFailed(e.getError().c_str());
168 int MCEProtocol::pushBits(
169 const CommandSequence &bits,
170 PIRRX51Hardware &rx51device)
174 CommandSequence::const_iterator i = bits.begin();
176 while (i != bits.end())
180 duration += pushOne(rx51device);
184 duration += pushZero(rx51device);
194 // This should be part of a general RC6 parent maybe?
195 int MCEProtocol::pushZero(
196 PIRRX51Hardware &rx51device)
198 // Need to add a space, then a pulse.
201 if (bufferContainsSpace)
203 // Merge this space and the previous one, and send to device:
204 rx51device.addSingle(buffer + biphaseUnit);
205 duration += (buffer + biphaseUnit);
207 bufferContainsSpace = false;
211 if (bufferContainsPulse)
213 // Flush out the buffer:
214 rx51device.addSingle(buffer);
217 bufferContainsPulse = false;
220 // push a space onto the device:
221 rx51device.addSingle(biphaseUnit);
222 duration += biphaseUnit;
225 // Put a pulse into the buffer to wait:
226 buffer = biphaseUnit;
227 bufferContainsPulse = true;
233 int MCEProtocol::pushOne(
234 PIRRX51Hardware &rx51device)
236 // Need to add a pulse, then a space.
240 if (bufferContainsPulse)
242 rx51device.addSingle(buffer + biphaseUnit);
243 duration += (buffer + biphaseUnit);
245 bufferContainsPulse = false;
249 if (bufferContainsSpace)
252 rx51device.addSingle(buffer);
255 bufferContainsSpace = false;
257 // Now, add the pulse:
258 rx51device.addSingle(biphaseUnit);
259 duration += biphaseUnit;
262 // Next, push a space onto the buffer:
263 buffer = biphaseUnit;
264 bufferContainsSpace = true;