Fix for command overrun
[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 NECProtocol::NECProtocol(
13   QObject *guiObject,
14   unsigned int index,
15   unsigned int zPulse,
16   unsigned int zSpace,
17   unsigned int oPulse,
18   unsigned int oSpace,
19   unsigned int gSpace,
20   bool iclflag)
21   : PIRProtocol(guiObject, index, gSpace, iclflag),
22     zeroPulse(zPulse),
23     zeroSpace(zSpace),
24     onePulse(oPulse),
25     oneSpace(oSpace),
26     hasTrailerPulse(false),
27     hasHeaderPair(false),
28     hasRepeatPair(false),
29     repeatNeedsHeader(false),
30     fullHeadlessRepeat(false)
31 {
32 }
33
34 void NECProtocol::setHeaderPair(
35   unsigned int pulse,
36   unsigned int space)
37 {
38   headerPulse = pulse;
39   headerSpace = space;
40   hasHeaderPair = true;
41 }
42
43 void NECProtocol::setTrailerPulse(
44   unsigned int pulse)
45 {
46   trailerPulse = pulse;
47   hasTrailerPulse = true;
48 }
49
50 void NECProtocol::setRepeatPair(
51   unsigned int pulse,
52   unsigned int space)
53 {
54   repeatPulse = pulse;
55   repeatSpace = space;
56   hasRepeatPair = true;
57 }
58
59 void NECProtocol::setRepeatNeedsHeader(
60   bool flag)
61 {
62   repeatNeedsHeader = flag;
63 }
64
65 void NECProtocol::setFullHeadlessRepeat(
66   bool flag)
67 {
68   fullHeadlessRepeat = flag;
69 }
70
71 void NECProtocol::setPreData(
72   unsigned long data,
73   unsigned int bits)
74 {
75   appendToBitSeq(preData, data, bits);
76 }
77
78 void NECProtocol::setPostData(
79   unsigned long data,
80   unsigned int bits)
81 {
82   appendToBitSeq(postData, data, bits);
83 }
84
85 void NECProtocol::startSendingCommand(
86   unsigned int threadableID,
87   PIRKeyName command)
88 {
89   // Exceptions here are problematic; I'll try to weed them out by putting the
90   // whole thing in a try/catch block:
91   try
92   {
93     // First, check if we are meant to be the recipient of this command:
94     if (threadableID != id) return;
95
96     // An object that helps keep track of the number of commands:
97 //    PIRCommandCounter commandCounter;
98
99     // Ok, we're going to lock down this method and make sure
100     // only one guy at a time passes this point:
101 //    QMutexLocker commandLocker(&commandMutex);
102
103     clearRepeatFlag();
104
105     KeycodeCollection::const_iterator i = keycodes.find(command);
106
107     // Do we even have this key defined?
108     if (i == keycodes.end())
109     {
110       std::string s = "Tried to send a non-existent command.\n";
111       throw PIRException(s);
112     }
113
114     // construct the device:
115     PIRRX51Hardware rx51device(carrierFrequency, dutyCycle);
116
117     int repeatCount = 0;
118     while (repeatCount < MAX_REPEAT_COUNT)
119     {
120       int commandDuration;
121
122       // If we are currently repeating, and have a special "repeat signal",
123       // use that signal.  Otherwise, generate a normal command string.
124       if (hasRepeatPair && repeatCount)
125       {
126         commandDuration = generateRepeatCommand(rx51device);
127       }
128       else if (fullHeadlessRepeat && repeatCount)
129       {
130         commandDuration = generateHeadlessCommand((*i).second, rx51device);
131       }
132       else
133       {
134         commandDuration = generateStandardCommand((*i).second, rx51device);
135       }
136
137       // Now, tell the device to send the whole command:
138       rx51device.sendCommandToDevice();
139
140       // sleep until the next repetition of command:
141       sleepUntilRepeat(commandDuration);
142
143       // Check whether we've reached the minimum required number of repetitons:
144       if (repeatCount >= minimumRepetitions)
145       {
146         // Check whether we've been asked to stop:
147         if (checkRepeatFlag())
148         {
149           QMutexLocker cifLocker(&commandIFMutex);
150           commandInFlight = false;
151           return;
152         }
153       }
154
155       ++repeatCount;
156     }
157   }
158   catch (PIRException e)
159   {
160     // inform the gui:
161     emit commandFailed(e.getError().c_str());
162   }
163
164   QMutexLocker cifLocker(&commandIFMutex);
165   commandInFlight = false;
166 }
167
168
169 int NECProtocol::generateStandardCommand(
170   const CommandSequence &bits,
171   PIRRX51Hardware &rx51device)
172 {
173   int duration = 0;
174
175   // First, the "header" pulse (if any):
176   if (hasHeaderPair)
177   {
178     rx51device.addPair(headerPulse, headerSpace);
179     duration += (headerPulse + headerSpace);
180   }
181
182   // Next, the "pre" data:
183   duration += pushBits(preData, rx51device);
184
185   // Next, add the actual command:
186   duration += pushBits(bits, rx51device);
187
188   // Next, add the "post" data:
189   duration += pushBits(postData, rx51device);
190
191   // Finally add the "trail":
192   if (hasTrailerPulse)
193   {
194     rx51device.addSingle(trailerPulse);
195     duration += trailerPulse;
196   }
197
198   return duration;
199 }
200
201
202 int NECProtocol::generateHeadlessCommand(
203   const CommandSequence &bits,
204   PIRRX51Hardware &rx51device)
205 {
206   int duration = 0;
207
208   // First, the "pre" data:
209   duration += pushBits(preData, rx51device);
210
211   // Next, add the actual command:
212   duration += pushBits(bits, rx51device);
213
214   // Next, add the "post" data:
215   duration += pushBits(postData, rx51device);
216
217   // Finally add the "trail":
218   if (hasTrailerPulse)
219   {
220     rx51device.addSingle(trailerPulse);
221     duration += trailerPulse;
222   }
223
224   return duration;
225 }
226
227
228 int NECProtocol::generateRepeatCommand(
229   PIRRX51Hardware &rx51device)
230 {
231   int duration = 0;
232
233   // Do we need the header?
234   if (repeatNeedsHeader)
235   {
236     // Do we even have a header?
237     if (hasHeaderPair)
238     {
239       // Ok, then add the header to the repeat:
240       rx51device.addPair(headerPulse, headerSpace);
241       duration += (headerPulse + headerSpace);
242     }
243   }
244
245   // Add the repeat pulse:
246   rx51device.addPair(repeatPulse, repeatSpace);
247   duration += (repeatPulse + repeatSpace);
248
249   // Finally add the trailer:
250   if (hasTrailerPulse)
251   {
252     rx51device.addSingle(trailerPulse);
253     duration += trailerPulse;
254   }
255
256   return duration;
257 }
258
259
260 int NECProtocol::pushBits(
261   const CommandSequence &bits,
262   PIRRX51Hardware &rx51device)
263 {
264   int duration = 0;
265   CommandSequence::const_iterator i = bits.begin();
266   while (i != bits.end())
267   {
268     if (*i)
269     {
270       // Send the pulse for "One":
271       rx51device.addPair(onePulse, oneSpace);
272       duration += (onePulse + oneSpace);
273     }
274     else
275     {
276       // Send the pulse for "Zero":
277       rx51device.addPair(zeroPulse, zeroSpace);
278       duration += (zeroPulse + zeroSpace);
279     }
280     ++i;
281   }
282
283   return duration;
284 }