1 #include "necprotocol.h"
3 #include "pirexception.h"
7 // Some global communications stuff:
9 extern bool commandInFlight;
10 extern QMutex commandIFMutex;
12 // The official NEC protocol, as I understand it, has the following attributes:
13 // A "zero" is encoded with a 560 usec pulse, 560 usec space.
14 // A "one" is encoded with a 560 usec pulse, and 3*560 (1680) usec space.
15 // The header is a 9000 usec pulse, 4500 usec space.
16 // Commands end with a trailing 560 usec pulse.
17 // A repeat block is a 9000 usec pulse, 2250 usec space, then trailing pulse.
18 // Each command runs for 110000 usec before another can be executed.
20 // For standard NEC, use this constructor:
21 NECProtocol::NECProtocol(
25 : PIRProtocol(guiObject, index, 110000, true),
34 hasTrailerPulse(true),
38 repeatNeedsHeader(false),
39 fullHeadlessRepeat(false),
40 elevenBitToggle(false),
45 // For non-standard NEC, use this constructor:
46 NECProtocol::NECProtocol(
56 : PIRProtocol(guiObject, index, gSpace, iclflag),
62 hasTrailerPulse(false),
64 repeatNeedsHeader(false),
65 fullHeadlessRepeat(false),
66 elevenBitToggle(false),
71 void NECProtocol::setHeaderPair(
80 void NECProtocol::setTrailerPulse(
84 hasTrailerPulse = true;
87 void NECProtocol::setRepeatPair(
96 void NECProtocol::setRepeatNeedsHeader(
99 repeatNeedsHeader = flag;
102 void NECProtocol::setFullHeadlessRepeat(
105 fullHeadlessRepeat = flag;
108 void NECProtocol::setElevenBitToggle(
111 elevenBitToggle = flag;
114 void NECProtocol::startSendingCommand(
115 unsigned int threadableID,
118 // Exceptions here are problematic; I'll try to weed them out by putting the
119 // whole thing in a try/catch block:
122 // First, check if we are meant to be the recipient of this command:
123 if (threadableID != id) return;
125 // An object that helps keep track of the number of commands:
126 // PIRCommandCounter commandCounter;
128 // Ok, we're going to lock down this method and make sure
129 // only one guy at a time passes this point:
130 // QMutexLocker commandLocker(&commandMutex);
134 KeycodeCollection::const_iterator i = keycodes.find(command);
136 // Do we even have this key defined?
137 if (i == keycodes.end())
139 std::string s = "Tried to send a non-existent command.\n";
140 throw PIRException(s);
143 // construct the device:
144 PIRRX51Hardware rx51device(carrierFrequency, dutyCycle);
147 int commandDuration = 0;
148 while (repeatCount < MAX_REPEAT_COUNT)
150 // If we are currently repeating, and have a special "repeat signal",
151 // use that signal. Otherwise, generate a normal command string.
152 if (hasRepeatPair && repeatCount)
154 commandDuration = generateRepeatCommand(rx51device);
156 else if (fullHeadlessRepeat && repeatCount)
158 commandDuration = generateHeadlessCommand((*i).second, rx51device);
160 else if (elevenBitToggle && (repeatCount % 2))
162 commandDuration = generateToggledCommand((*i).second, rx51device);
166 commandDuration = generateStandardCommand((*i).second, rx51device);
169 // Now, tell the device to send the whole command:
170 rx51device.sendCommandToDevice();
172 // sleep until the next repetition of command:
173 sleepUntilRepeat(commandDuration);
175 // Check whether we've reached the minimum required number of repetitons:
176 if (repeatCount >= minimumRepetitions)
178 // Check whether we've been asked to stop:
179 if (checkRepeatFlag())
181 QMutexLocker cifLocker(&commandIFMutex);
182 commandInFlight = false;
190 catch (PIRException e)
193 emit commandFailed(e.getError().c_str());
196 QMutexLocker cifLocker(&commandIFMutex);
197 commandInFlight = false;
201 int NECProtocol::generateStandardCommand(
202 const CommandSequence &bits,
203 PIRRX51Hardware &rx51device)
207 // First, the "header" pulse (if any):
210 rx51device.addPair(headerPulse, headerSpace);
211 duration += (headerPulse + headerSpace);
214 // Now, check the encoding format:
215 switch(encodingFormat)
218 // Standard NEC is made up of an eight-bit "address" and an eight-bit
219 // "command". First the address bits are sent (in reverse order), then
220 // the address bits are inverted and sent again (in reverse order).
221 // Next, we do the same to the command bits.
222 // - "preData" should contain 8-bit value
223 // - "bits" should contain 8-bit value
224 duration += pushReverseBits(preData, rx51device);
225 duration += pushInvertedReverseBits(preData, rx51device);
226 duration += pushReverseBits(bits, rx51device);
227 duration += pushInvertedReverseBits(bits, rx51device);
230 // In extended NEC, the address has been extended to 16 bits, but only
231 // the reversed bits are sent, not inverted. The command portion stays
233 // - "preData" should contain 16-bit value
234 // - "bits" should contain 8-bit value
235 duration += pushReverseBits(preData, rx51device);
236 duration += pushReverseBits(bits, rx51device);
237 duration += pushInvertedReverseBits(bits, rx51device);
239 case LIRC_NEC: default:
240 // In this case, we just dump the raw bits into the device:
241 duration += pushBits(preData, rx51device);
242 duration += pushBits(bits, rx51device);
243 duration += pushBits(postData, rx51device);
247 // Finally add the "trail":
250 rx51device.addSingle(trailerPulse);
251 duration += trailerPulse;
258 int NECProtocol::generateHeadlessCommand(
259 const CommandSequence &bits,
260 PIRRX51Hardware &rx51device)
264 // First, the "pre" data:
265 duration += pushBits(preData, rx51device);
267 // Next, add the actual command:
268 duration += pushBits(bits, rx51device);
270 // Next, add the "post" data:
271 duration += pushBits(postData, rx51device);
273 // Finally add the "trail":
276 rx51device.addSingle(trailerPulse);
277 duration += trailerPulse;
284 int NECProtocol::generateRepeatCommand(
285 PIRRX51Hardware &rx51device)
289 // Do we need the header?
290 if (repeatNeedsHeader)
292 // Do we even have a header?
295 // Ok, then add the header to the repeat:
296 rx51device.addPair(headerPulse, headerSpace);
297 duration += (headerPulse + headerSpace);
301 // Add the repeat pulse:
302 rx51device.addPair(repeatPulse, repeatSpace);
303 duration += (repeatPulse + repeatSpace);
305 // Finally add the trailer:
308 rx51device.addSingle(trailerPulse);
309 duration += trailerPulse;
316 // NOTE! The following is a special command to toggle the last eleven bits
317 // of the fifteen-bit commands used by Denon, Sharp, and a few others. It
318 // assumes the command sequence will contain all fifteen bits. If this
319 // is not the case, it will work incorrectly!
320 int NECProtocol::generateToggledCommand(
321 const CommandSequence &bits,
322 PIRRX51Hardware &rx51device)
326 CommandSequence::const_iterator i = bits.begin();
330 while ((bitcount < 4) && (i != bits.end()))
334 // Send pulse for "one":
335 rx51device.addPair(onePulse, oneSpace);
336 duration += (onePulse + oneSpace);
340 // Send pulse for "zero":
341 rx51device.addPair(zeroPulse, zeroSpace);
342 duration += (zeroPulse + zeroSpace);
348 // Now, invert the last eleven bits:
349 while (i != bits.end())
353 // Send pulse for "zero":
354 rx51device.addPair(zeroPulse, zeroSpace);
355 duration += (zeroPulse + zeroSpace);
359 // Send pulse for "one":
360 rx51device.addPair(onePulse, oneSpace);
361 duration += (onePulse + oneSpace);
369 rx51device.addSingle(trailerPulse);
370 duration += trailerPulse;
377 int NECProtocol::pushBits(
378 const CommandSequence &bits,
379 PIRRX51Hardware &rx51device)
382 CommandSequence::const_iterator i = bits.begin();
383 while (i != bits.end())
387 // Send the pulse for "One":
388 rx51device.addPair(onePulse, oneSpace);
389 duration += (onePulse + oneSpace);
393 // Send the pulse for "Zero":
394 rx51device.addPair(zeroPulse, zeroSpace);
395 duration += (zeroPulse + zeroSpace);
404 int NECProtocol::pushReverseBits(
405 const CommandSequence &bits,
406 PIRRX51Hardware &rx51device)
409 CommandSequence::const_reverse_iterator i = bits.rbegin();
410 while (i != bits.rend())
414 // Send the pulse for "One":
415 rx51device.addPair(onePulse, oneSpace);
416 duration += (onePulse + oneSpace);
420 // Send the pulse for "Zero":
421 rx51device.addPair(zeroPulse, zeroSpace);
422 duration += (zeroPulse + zeroSpace);
431 int NECProtocol::pushInvertedReverseBits(
432 const CommandSequence &bits,
433 PIRRX51Hardware &rx51device)
436 CommandSequence::const_reverse_iterator i = bits.rbegin();
437 while (i != bits.rend())
441 // Send the pulse for "Zero":
442 rx51device.addPair(zeroPulse, zeroSpace);
443 duration += (zeroPulse + zeroSpace);
447 // Send the pulse for "One":
448 rx51device.addPair(onePulse, oneSpace);
449 duration += (onePulse + oneSpace);