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(
24 : PIRProtocol(guiObject, index, 110000, true),
33 hasTrailerPulse(true),
37 repeatNeedsHeader(false),
38 fullHeadlessRepeat(false),
39 elevenBitToggle(false)
43 // For non-standard NEC, use this constructor:
44 NECProtocol::NECProtocol(
53 : PIRProtocol(guiObject, index, gSpace, iclflag),
59 hasTrailerPulse(false),
61 repeatNeedsHeader(false),
62 fullHeadlessRepeat(false),
63 elevenBitToggle(false)
67 void NECProtocol::setHeaderPair(
76 void NECProtocol::setTrailerPulse(
80 hasTrailerPulse = true;
83 void NECProtocol::setRepeatPair(
92 void NECProtocol::setRepeatNeedsHeader(
95 repeatNeedsHeader = flag;
98 void NECProtocol::setFullHeadlessRepeat(
101 fullHeadlessRepeat = flag;
104 void NECProtocol::setElevenBitToggle(
107 elevenBitToggle = flag;
110 void NECProtocol::startSendingCommand(
111 unsigned int threadableID,
114 // Exceptions here are problematic; I'll try to weed them out by putting the
115 // whole thing in a try/catch block:
118 // First, check if we are meant to be the recipient of this command:
119 if (threadableID != id) return;
121 // An object that helps keep track of the number of commands:
122 // PIRCommandCounter commandCounter;
124 // Ok, we're going to lock down this method and make sure
125 // only one guy at a time passes this point:
126 // QMutexLocker commandLocker(&commandMutex);
130 KeycodeCollection::const_iterator i = keycodes.find(command);
132 // Do we even have this key defined?
133 if (i == keycodes.end())
135 std::string s = "Tried to send a non-existent command.\n";
136 throw PIRException(s);
139 // construct the device:
140 PIRRX51Hardware rx51device(carrierFrequency, dutyCycle);
143 while (repeatCount < MAX_REPEAT_COUNT)
147 // If we are currently repeating, and have a special "repeat signal",
148 // use that signal. Otherwise, generate a normal command string.
149 if (hasRepeatPair && repeatCount)
151 commandDuration = generateRepeatCommand(rx51device);
153 else if (fullHeadlessRepeat && repeatCount)
155 commandDuration = generateHeadlessCommand((*i).second, rx51device);
157 else if (elevenBitToggle && (repeatCount % 2))
159 commandDuration = generateToggledCommand((*i).second, rx51device);
163 commandDuration = generateStandardCommand((*i).second, rx51device);
166 // Now, tell the device to send the whole command:
167 rx51device.sendCommandToDevice();
169 // sleep until the next repetition of command:
170 sleepUntilRepeat(commandDuration);
172 // Check whether we've reached the minimum required number of repetitons:
173 if (repeatCount >= minimumRepetitions)
175 // Check whether we've been asked to stop:
176 if (checkRepeatFlag())
178 QMutexLocker cifLocker(&commandIFMutex);
179 commandInFlight = false;
187 catch (PIRException e)
190 emit commandFailed(e.getError().c_str());
193 QMutexLocker cifLocker(&commandIFMutex);
194 commandInFlight = false;
198 int NECProtocol::generateStandardCommand(
199 const CommandSequence &bits,
200 PIRRX51Hardware &rx51device)
204 // First, the "header" pulse (if any):
207 rx51device.addPair(headerPulse, headerSpace);
208 duration += (headerPulse + headerSpace);
211 // Next, the "pre" data:
212 duration += pushBits(preData, rx51device);
214 // Next, add the actual command:
215 duration += pushBits(bits, rx51device);
217 // Next, add the "post" data:
218 duration += pushBits(postData, rx51device);
220 // Finally add the "trail":
223 rx51device.addSingle(trailerPulse);
224 duration += trailerPulse;
231 int NECProtocol::generateHeadlessCommand(
232 const CommandSequence &bits,
233 PIRRX51Hardware &rx51device)
237 // First, the "pre" data:
238 duration += pushBits(preData, rx51device);
240 // Next, add the actual command:
241 duration += pushBits(bits, rx51device);
243 // Next, add the "post" data:
244 duration += pushBits(postData, rx51device);
246 // Finally add the "trail":
249 rx51device.addSingle(trailerPulse);
250 duration += trailerPulse;
257 int NECProtocol::generateRepeatCommand(
258 PIRRX51Hardware &rx51device)
262 // Do we need the header?
263 if (repeatNeedsHeader)
265 // Do we even have a header?
268 // Ok, then add the header to the repeat:
269 rx51device.addPair(headerPulse, headerSpace);
270 duration += (headerPulse + headerSpace);
274 // Add the repeat pulse:
275 rx51device.addPair(repeatPulse, repeatSpace);
276 duration += (repeatPulse + repeatSpace);
278 // Finally add the trailer:
281 rx51device.addSingle(trailerPulse);
282 duration += trailerPulse;
289 // NOTE! The following is a special command to toggle the last eleven bits
290 // of the fifteen-bit commands used by Denon, Sharp, and a few others. It
291 // assumes the command sequence will contain all fifteen bits. If this
292 // is not the case, it will work incorrectly!
293 int NECProtocol::generateToggledCommand(
294 const CommandSequence &bits,
295 PIRRX51Hardware &rx51device)
299 CommandSequence::const_iterator i = bits.begin();
303 while ((bitcount < 4) && (i != bits.end()))
307 // Send pulse for "one":
308 rx51device.addPair(onePulse, oneSpace);
309 duration += (onePulse + oneSpace);
313 // Send pulse for "zero":
314 rx51device.addPair(zeroPulse, zeroSpace);
315 duration += (zeroPulse + zeroSpace);
321 // Now, invert the last eleven bits:
322 while (i != bits.end())
326 // Send pulse for "zero":
327 rx51device.addPair(zeroPulse, zeroSpace);
328 duration += (zeroPulse + zeroSpace);
332 // Send pulse for "one":
333 rx51device.addPair(onePulse, oneSpace);
334 duration += (onePulse + oneSpace);
342 rx51device.addSingle(trailerPulse);
343 duration += trailerPulse;
350 int NECProtocol::pushBits(
351 const CommandSequence &bits,
352 PIRRX51Hardware &rx51device)
355 CommandSequence::const_iterator i = bits.begin();
356 while (i != bits.end())
360 // Send the pulse for "One":
361 rx51device.addPair(onePulse, oneSpace);
362 duration += (onePulse + oneSpace);
366 // Send the pulse for "Zero":
367 rx51device.addPair(zeroPulse, zeroSpace);
368 duration += (zeroPulse + zeroSpace);