Possible Uninstall Fix, plus cleanup, more keysets
[pierogi] / protocols / rc5protocol.cpp
1 #include "rc5protocol.h"
2
3 #include "pirrx51hardware.h"
4
5 #include "pirexception.h"
6
7 #include <QMutex>
8 extern bool commandInFlight;
9 extern QMutex commandIFMutex;
10
11 RC5Protocol::RC5Protocol(
12   QObject *guiObject,
13   unsigned int index,
14   unsigned int sevenBitControl)
15   : PIRProtocol(guiObject, index, 114000, true),
16     biphaseUnit(889),
17     buffer(0),
18     keypressCount(0)
19 {
20   setCarrierFrequency(36000);
21   setPreData(sevenBitControl, 7);
22 }
23
24
25 RC5Protocol::RC5Protocol(
26   QObject *guiObject,
27   unsigned int index)
28   : PIRProtocol(guiObject, index, 114000, true),
29     biphaseUnit(889),
30     buffer(0),
31     keypressCount(0)
32 {
33   setCarrierFrequency(36000);
34 }
35
36
37 void RC5Protocol::startSendingCommand(
38   unsigned int threadableID,
39   PIRKeyName command)
40 {
41   // Dumping entire method inside of try/catch, to deal with cross-thread
42   // exception handling:
43   try
44   {
45     // Check if this command is meant for us:
46     if (threadableID != id) return;
47
48     clearRepeatFlag();
49
50     KeycodeCollection::const_iterator i = keycodes.find(command);
51
52     // Sanity check, make sure command exists first:
53     if (i == keycodes.end())
54     {
55       std::string s = "Tried to send a non-existent command.\n";
56       throw PIRException(s);
57     }
58
59     // Construct the object that communicates with the device driver:
60     PIRRX51Hardware rx51device(carrierFrequency, dutyCycle);
61
62     int repeatCount = 0;
63     int commandDuration = 0;
64     while (repeatCount < MAX_REPEAT_COUNT)
65     {
66       // Now, throw together an RC5 protocol command string.
67
68       if (!preData.empty())
69       {
70         // For standard RC5, the "pre-data" contains the control portion,
71         // and the key contains only the 6-bit command portion.
72
73         // First, construct the control portion:
74         commandDuration += pushControlBits(rx51device);
75
76         // Next, the key-command portion:
77         commandDuration += pushKeyCommandBits((*i).second, rx51device);
78       }
79       else
80       {
81         // For non-standard RC5, the entire 13 bits are stuffed into the
82         // key portion, as all of them can vary:
83         commandDuration += pushNonStandardRC5((*i).second, rx51device);
84       }
85
86       // Clear out the buffer, if necessary:
87       if (buffer)
88       {
89         rx51device.addSingle(buffer);
90         commandDuration += buffer;
91
92         // probably unnecessary cleanup of buffer:
93         buffer = 0;
94         bufferContainsSpace = false;
95         bufferContainsPulse = false;
96       }
97
98       // Now, tell the device to send the whole command:
99       rx51device.sendCommandToDevice();
100
101       // Sleep for an amount of time.  (Need to make this interruptable!)
102       sleepUntilRepeat(commandDuration);
103
104       // Have we been told to stop yet?
105       if (checkRepeatFlag())
106       {
107         // Ok, then we can quit now:
108         ++keypressCount;
109         QMutexLocker cifLocker(&commandIFMutex);
110         commandInFlight = false;
111         return;
112       }
113
114       ++repeatCount;
115     }
116   }
117   catch (PIRException e)
118   {
119     emit commandFailed(e.getError().c_str());
120   }
121
122   ++keypressCount;
123   QMutexLocker cifLocker(&commandIFMutex);
124   commandInFlight = false;
125 }
126
127
128 int RC5Protocol::pushControlBits(
129   PIRRX51Hardware &rx51device)
130 {
131   int duration = 0;
132
133   // Start off by pushing the lead pulse onto the buffer:
134   buffer = biphaseUnit;
135   bufferContainsPulse = true;
136   bufferContainsSpace = false;
137
138   CommandSequence::const_iterator i = preData.begin();
139
140   // Push the first bit:
141   if (i != preData.end())
142   {
143     duration += pushBit(*i, rx51device);
144     ++i;
145   }
146
147   // Toggle the second bit, if it is time to do so:
148   if (i != preData.end())
149   {
150     if (keypressCount % 2)
151     {
152       duration += pushBit(!(*i), rx51device);
153     }
154     else
155     {
156       duration += pushBit(*i, rx51device);
157     }
158
159     ++i;
160   }
161
162   // Simply push the rest of the bits:
163   while (i != preData.end())
164   {
165     pushBit(*i, rx51device);
166     ++i;
167   }
168
169   return duration;
170 }
171
172
173 int RC5Protocol::pushKeyCommandBits(
174   const PIRKeyBits &pkb,
175   PIRRX51Hardware &rx51device)
176 {
177   int duration = 0;
178
179   // Just push all the bits:
180   CommandSequence::const_iterator i = pkb.firstCode.begin();
181   while (i != pkb.firstCode.end())
182   {
183     duration += pushBit(*i, rx51device);
184     ++i;
185   }
186
187   return duration;
188 }
189
190
191 int RC5Protocol::pushNonStandardRC5(
192   const PIRKeyBits &pkb,
193   PIRRX51Hardware &rx51device)
194 {
195   int duration = 0;
196
197   // Start off by pushing the lead pulse onto the buffer:
198   buffer = biphaseUnit;
199   bufferContainsPulse = true;
200   bufferContainsSpace = false;
201
202   CommandSequence::const_iterator i = pkb.firstCode.begin();
203
204   // Push the first bit:
205   if (i != pkb.firstCode.end())
206   {
207     duration += pushBit(*i, rx51device);
208     ++i;
209   }
210
211   // Toggle the second bit, if it is time to do so:
212   if (i != pkb.firstCode.end())
213   {
214     if (keypressCount % 2)
215     {
216       duration += pushBit(!(*i), rx51device);
217     }
218     else
219     {
220       duration += pushBit(*i, rx51device);
221     }
222
223     ++i;
224   }
225
226   // Simply push the rest of the bits:
227   while (i != pkb.firstCode.end())
228   {
229     pushBit(*i, rx51device);
230     ++i;
231   }
232
233   return duration;
234 }
235
236
237 int RC5Protocol::pushBit(
238   bool bitValue,
239   PIRRX51Hardware &device)
240 {
241   unsigned int duration = 0;
242   // RC5 encodes a "0" by using a pulse followed by a space,
243   // and a "1" by using a space followed by a pulse.
244
245   if (bitValue)
246   {
247     // We've got a "1".  First add a space, then a pulse.
248     if (bufferContainsSpace)
249     {
250       // Merge our space with the previous space, and send them to
251       // the device.
252       device.addSingle(buffer + biphaseUnit);
253       duration += (buffer + biphaseUnit);
254       buffer = 0;
255       bufferContainsSpace = false;
256     }
257     else
258     {
259       if (bufferContainsPulse)
260       {
261         // Flush the buffer:
262         device.addSingle(buffer);
263         duration += buffer;
264         buffer = 0;
265         bufferContainsPulse = false;
266       }
267       // Add a space:
268       device.addSingle(biphaseUnit);
269       duration += biphaseUnit;
270     }
271
272     // Put a pulse into the buffer to wait.
273     buffer = biphaseUnit;
274     bufferContainsPulse = true;
275   }
276   else
277   {
278     // We've got a "0".  First add a pulse, then a space.
279     if (bufferContainsPulse)
280     {
281       // Merge our pulse with the previous one, and send them to the device:
282       device.addSingle(buffer + biphaseUnit);
283       duration += (buffer + biphaseUnit);
284       buffer = 0;
285       bufferContainsPulse = false;
286     }
287     else
288     {
289       if (bufferContainsSpace)
290       {
291         // Flush out the buffer:
292         device.addSingle(buffer);
293         duration += buffer;
294         buffer = 0;
295         bufferContainsSpace = false;
296       }
297
298       // Add a pulse:
299       device.addSingle(biphaseUnit);
300       duration += biphaseUnit;
301     }
302
303     // Put a space into the buffer to wait:
304     buffer = biphaseUnit;
305     bufferContainsSpace = true;
306   }
307
308   return duration;
309 }