Still fixing install, more keyset work
[pierogi] / necprotocol.cpp
1 #include "necprotocol.h"
2
3 #include "pirexception.h"
4 #include <string>
5 //#include <iostream>
6
7 // Some global communications stuff:
8 #include <QMutex>
9 extern bool commandInFlight;
10 extern QMutex commandIFMutex;
11
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.
19
20 // For standard NEC, use this constructor:
21 NECProtocol::NECProtocol(
22   QObject *guiObject,
23   unsigned int index)
24   : PIRProtocol(guiObject, index, 110000, true),
25     zeroPulse(560),
26     zeroSpace(560),
27     onePulse(560),
28     oneSpace(1680),
29     headerPulse(9000),
30     headerSpace(4500),
31     hasHeaderPair(true),
32     trailerPulse(560),
33     hasTrailerPulse(true),
34     repeatPulse(9000),
35     repeatSpace(2250),
36     hasRepeatPair(true),
37     repeatNeedsHeader(false),
38     fullHeadlessRepeat(false),
39     elevenBitToggle(false)
40 {
41 }
42
43 // For non-standard NEC, use this constructor:
44 NECProtocol::NECProtocol(
45   QObject *guiObject,
46   unsigned int index,
47   unsigned int zPulse,
48   unsigned int zSpace,
49   unsigned int oPulse,
50   unsigned int oSpace,
51   unsigned int gSpace,
52   bool iclflag)
53   : PIRProtocol(guiObject, index, gSpace, iclflag),
54     zeroPulse(zPulse),
55     zeroSpace(zSpace),
56     onePulse(oPulse),
57     oneSpace(oSpace),
58     hasHeaderPair(false),
59     hasTrailerPulse(false),
60     hasRepeatPair(false),
61     repeatNeedsHeader(false),
62     fullHeadlessRepeat(false),
63     elevenBitToggle(false)
64 {
65 }
66
67 void NECProtocol::setHeaderPair(
68   unsigned int pulse,
69   unsigned int space)
70 {
71   headerPulse = pulse;
72   headerSpace = space;
73   hasHeaderPair = true;
74 }
75
76 void NECProtocol::setTrailerPulse(
77   unsigned int pulse)
78 {
79   trailerPulse = pulse;
80   hasTrailerPulse = true;
81 }
82
83 void NECProtocol::setRepeatPair(
84   unsigned int pulse,
85   unsigned int space)
86 {
87   repeatPulse = pulse;
88   repeatSpace = space;
89   hasRepeatPair = true;
90 }
91
92 void NECProtocol::setRepeatNeedsHeader(
93   bool flag)
94 {
95   repeatNeedsHeader = flag;
96 }
97
98 void NECProtocol::setFullHeadlessRepeat(
99   bool flag)
100 {
101   fullHeadlessRepeat = flag;
102 }
103
104 void NECProtocol::setElevenBitToggle(
105   bool flag)
106 {
107   elevenBitToggle = flag;
108 }
109
110 void NECProtocol::startSendingCommand(
111   unsigned int threadableID,
112   PIRKeyName command)
113 {
114   // Exceptions here are problematic; I'll try to weed them out by putting the
115   // whole thing in a try/catch block:
116   try
117   {
118     // First, check if we are meant to be the recipient of this command:
119     if (threadableID != id) return;
120
121     // An object that helps keep track of the number of commands:
122 //    PIRCommandCounter commandCounter;
123
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);
127
128     clearRepeatFlag();
129
130     KeycodeCollection::const_iterator i = keycodes.find(command);
131
132     // Do we even have this key defined?
133     if (i == keycodes.end())
134     {
135       std::string s = "Tried to send a non-existent command.\n";
136       throw PIRException(s);
137     }
138
139     // construct the device:
140     PIRRX51Hardware rx51device(carrierFrequency, dutyCycle);
141
142     int repeatCount = 0;
143     while (repeatCount < MAX_REPEAT_COUNT)
144     {
145       int commandDuration;
146
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)
150       {
151         commandDuration = generateRepeatCommand(rx51device);
152       }
153       else if (fullHeadlessRepeat && repeatCount)
154       {
155         commandDuration = generateHeadlessCommand((*i).second, rx51device);
156       }
157       else if (elevenBitToggle && (repeatCount % 2))
158       {
159         commandDuration = generateToggledCommand((*i).second, rx51device);
160       }
161       else
162       {
163         commandDuration = generateStandardCommand((*i).second, rx51device);
164       }
165
166       // Now, tell the device to send the whole command:
167       rx51device.sendCommandToDevice();
168
169       // sleep until the next repetition of command:
170       sleepUntilRepeat(commandDuration);
171
172       // Check whether we've reached the minimum required number of repetitons:
173       if (repeatCount >= minimumRepetitions)
174       {
175         // Check whether we've been asked to stop:
176         if (checkRepeatFlag())
177         {
178           QMutexLocker cifLocker(&commandIFMutex);
179           commandInFlight = false;
180           return;
181         }
182       }
183
184       ++repeatCount;
185     }
186   }
187   catch (PIRException e)
188   {
189     // inform the gui:
190     emit commandFailed(e.getError().c_str());
191   }
192
193   QMutexLocker cifLocker(&commandIFMutex);
194   commandInFlight = false;
195 }
196
197
198 int NECProtocol::generateStandardCommand(
199   const CommandSequence &bits,
200   PIRRX51Hardware &rx51device)
201 {
202   int duration = 0;
203
204   // First, the "header" pulse (if any):
205   if (hasHeaderPair)
206   {
207     rx51device.addPair(headerPulse, headerSpace);
208     duration += (headerPulse + headerSpace);
209   }
210
211   // Next, the "pre" data:
212   duration += pushBits(preData, rx51device);
213
214   // Next, add the actual command:
215   duration += pushBits(bits, rx51device);
216
217   // Next, add the "post" data:
218   duration += pushBits(postData, rx51device);
219
220   // Finally add the "trail":
221   if (hasTrailerPulse)
222   {
223     rx51device.addSingle(trailerPulse);
224     duration += trailerPulse;
225   }
226
227   return duration;
228 }
229
230
231 int NECProtocol::generateHeadlessCommand(
232   const CommandSequence &bits,
233   PIRRX51Hardware &rx51device)
234 {
235   int duration = 0;
236
237   // First, the "pre" data:
238   duration += pushBits(preData, rx51device);
239
240   // Next, add the actual command:
241   duration += pushBits(bits, rx51device);
242
243   // Next, add the "post" data:
244   duration += pushBits(postData, rx51device);
245
246   // Finally add the "trail":
247   if (hasTrailerPulse)
248   {
249     rx51device.addSingle(trailerPulse);
250     duration += trailerPulse;
251   }
252
253   return duration;
254 }
255
256
257 int NECProtocol::generateRepeatCommand(
258   PIRRX51Hardware &rx51device)
259 {
260   int duration = 0;
261
262   // Do we need the header?
263   if (repeatNeedsHeader)
264   {
265     // Do we even have a header?
266     if (hasHeaderPair)
267     {
268       // Ok, then add the header to the repeat:
269       rx51device.addPair(headerPulse, headerSpace);
270       duration += (headerPulse + headerSpace);
271     }
272   }
273
274   // Add the repeat pulse:
275   rx51device.addPair(repeatPulse, repeatSpace);
276   duration += (repeatPulse + repeatSpace);
277
278   // Finally add the trailer:
279   if (hasTrailerPulse)
280   {
281     rx51device.addSingle(trailerPulse);
282     duration += trailerPulse;
283   }
284
285   return duration;
286 }
287
288
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)
296 {
297   int duration = 0;
298
299   CommandSequence::const_iterator i = bits.begin();
300
301   int bitcount = 0;
302   // First 4 bits:
303   while ((bitcount < 4) && (i != bits.end()))
304   {
305     if (*i)
306     {
307       // Send pulse for "one":
308       rx51device.addPair(onePulse, oneSpace);
309       duration += (onePulse + oneSpace);
310     }
311     else
312     {
313       // Send pulse for "zero":
314       rx51device.addPair(zeroPulse, zeroSpace);
315       duration += (zeroPulse + zeroSpace);
316     }
317     ++i;
318     ++bitcount;
319   }
320
321   // Now, invert the last eleven bits:
322   while (i != bits.end())
323   {
324     if (*i)
325     {
326       // Send pulse for "zero":
327       rx51device.addPair(zeroPulse, zeroSpace);
328       duration += (zeroPulse + zeroSpace);
329     }
330     else
331     {
332       // Send pulse for "one":
333       rx51device.addPair(onePulse, oneSpace);
334       duration += (onePulse + oneSpace);
335     }
336     ++i;
337   }
338
339   // Add trail on end:
340   if (hasTrailerPulse)
341   {
342     rx51device.addSingle(trailerPulse);
343     duration += trailerPulse;
344   }
345
346   return duration;
347 }
348
349
350 int NECProtocol::pushBits(
351   const CommandSequence &bits,
352   PIRRX51Hardware &rx51device)
353 {
354   int duration = 0;
355   CommandSequence::const_iterator i = bits.begin();
356   while (i != bits.end())
357   {
358     if (*i)
359     {
360       // Send the pulse for "One":
361       rx51device.addPair(onePulse, oneSpace);
362       duration += (onePulse + oneSpace);
363     }
364     else
365     {
366       // Send the pulse for "Zero":
367       rx51device.addPair(zeroPulse, zeroSpace);
368       duration += (zeroPulse + zeroSpace);
369     }
370     ++i;
371   }
372
373   return duration;
374 }