Search for Power Button Panel
[pierogi] / protocols / nokia32protocol.cpp
1 #include "nokia32protocol.h"
2
3 #include "pirrx51hardware.h"
4
5 #include "pirexception.h"
6
7 // Some global communications stuff:
8 #include <QMutex>
9 extern bool commandInFlight;
10 extern QMutex commandIFMutex;
11
12 // The Nokia 32 protocol has a 2-bit space encoding system, and appears to
13 // work like this:
14 // A "zero" is encoded with a 164 usec pulse, 276 usec space.
15 // A "one" is encoded with a 164 usec pulse, 445 usec space.
16 // A "two" is encoded with a 164 usec pulse, 614 usec space.
17 // A "three" is encoded with a 164 usec pulse, 783 usec space.
18 // The header is a 412 usec pulse, 276 usec space.
19 // Commands end with a trailing 164 usec pulse.
20 // The entire pulse train is re-sent when repeating.
21 // There is a 100000 usec gap between commands. (? not sure here)
22 // The carrier frequency is presumably 36 kHz.
23 // The duty cycle is presumably 1/3.
24
25 Nokia32Protocol::Nokia32Protocol(
26   QObject *guiObject,
27   unsigned int index)
28   : PIRProtocol(guiObject, index, 100000, false),
29     zeroPulse(164),
30     zeroSpace(276),
31     onePulse(164),
32     oneSpace(445),
33     twoPulse(164),
34     twoSpace(614),
35     threePulse(164),
36     threeSpace(783),
37     headerPulse(412),
38     headerSpace(276),
39     trailerPulse(164),
40     keypressCount(0)
41 {
42 }
43
44
45 void Nokia32Protocol::startSendingCommand(
46   unsigned int threadableID,
47   PIRKeyName command)
48 {
49   // Exceptions here are problematic; I'll try to weed them out by putting the
50   // whole thing in a try/catch block:
51   try
52   {
53     // First, check if we are meant to be the recipient of this command:
54     if (threadableID != id) return;
55
56     clearRepeatFlag();
57
58     KeycodeCollection::const_iterator i = keycodes.find(command);
59
60     // Do we even have this key defined?
61     if (i == keycodes.end())
62     {
63       QMutexLocker cifLocker(&commandIFMutex);
64       commandInFlight = false;
65       return;
66 //      std::string s = "Tried to send a non-existent command.\n";
67 //      throw PIRException(s);
68     }
69
70     // construct the device:
71     PIRRX51Hardware rx51device(carrierFrequency, dutyCycle);
72
73     int repeatCount = 0;
74     int commandDuration = 0;
75     while (repeatCount < MAX_REPEAT_COUNT)
76     {
77       commandDuration = generateStandardCommand((*i).second, rx51device);
78
79       // Now, tell the device to send the whole command:
80       rx51device.sendCommandToDevice();
81
82       // sleep until the next repetition of command:
83       sleepUntilRepeat(commandDuration);
84
85       // Check whether we've reached the minimum required number of repetitons:
86       if (repeatCount >= minimumRepetitions)
87       {
88         // Check whether we've been asked to stop:
89         if (checkRepeatFlag())
90         {
91           break;
92 /*
93           ++keypressCount;
94           QMutexLocker cifLocker(&commandIFMutex);
95           commandInFlight = false;
96           return;
97 */
98         }
99       }
100
101       ++repeatCount;
102     }
103
104     ++keypressCount;
105     QMutexLocker cifLocker(&commandIFMutex);
106     commandInFlight = false;
107   }
108   catch (PIRException e)
109   {
110     // inform the gui:
111     emit commandFailed(e.getError().c_str());
112   }
113 }
114
115
116 int Nokia32Protocol::generateStandardCommand(
117   const PIRKeyBits &pkb,
118   PIRRX51Hardware &rx51device)
119 {
120   int duration = 0;
121
122   // First, the "header" pulse:
123   rx51device.addPair(headerPulse, headerSpace);
124   duration += (headerPulse + headerSpace);
125
126   // The layout of the Nokia 32 protocol is as follows:
127   // 1) an 8-bit "device code"
128   // 2) an 8-bit "sub-device code"
129   // 3) one toggle bit
130   // 4) seven more bits somehow associated with the device
131   // 5) an 8-bit command code.
132   // All are sent in MSB order.
133
134   // It's a bit of a hack, but I'll store the first 16 bits of address in the
135   // preData, the next 7 bits of address in the postData, and the 8 bits
136   // of command in the firstCode:
137
138   duration += pushBits(preData, rx51device);
139   duration += pushToggleAndBits(postData, rx51device);
140   duration += pushBits(pkb.firstCode, rx51device);
141
142   // Finally add the "trail":
143   rx51device.addSingle(trailerPulse);
144   duration += trailerPulse;
145
146   return duration;
147 }
148
149
150 int Nokia32Protocol::pushBits(
151   const CommandSequence &bits,
152   PIRRX51Hardware &rx51device)
153 {
154   int duration = 0;
155   bool firstBit;
156   bool secondBit;
157
158   CommandSequence::const_iterator i = bits.begin();
159   while (i != bits.end())
160   {
161     firstBit = *i;
162     ++i;
163     if (i == bits.end()) break;
164     secondBit = *i;
165
166     duration += pushDoubleBit(firstBit, secondBit, rx51device);
167
168     ++i;
169   }
170
171   return duration;
172 }
173
174
175 int Nokia32Protocol::pushToggleAndBits(
176   const CommandSequence &bits,
177   PIRRX51Hardware &rx51device)
178 {
179   int duration = 0;
180   bool firstBit;
181   bool secondBit;
182
183   // The first bit is the toggle bit:
184   if (keypressCount % 2)
185   {
186     firstBit = 1;
187   }
188   else
189   {
190     firstBit = 0;
191   }
192
193   CommandSequence::const_iterator i = bits.begin();
194   if (i == bits.end()) return 0;
195
196   secondBit = *i;
197
198   duration += pushDoubleBit(firstBit, secondBit, rx51device);
199
200   ++i;
201
202   while (i != bits.end())
203   {
204     firstBit = *i;
205     ++i;
206     if (i == bits.end()) break;
207     secondBit = *i;
208
209     duration += pushDoubleBit(firstBit, secondBit, rx51device);
210
211     ++i;
212   }
213
214   return duration;
215 }
216
217
218 int Nokia32Protocol::pushDoubleBit(
219   bool firstBit,
220   bool secondBit,
221   PIRRX51Hardware &rx51device)
222 {
223   int duration = 0;
224
225   if (firstBit == 0)
226   {
227     if (secondBit == 0)
228     {
229       // Send the pulse for "Zero":
230       rx51device.addPair(zeroPulse, zeroSpace);
231       duration += (zeroPulse + zeroSpace);
232     }
233     else
234     {
235       // Send the pulse for "One":
236       rx51device.addPair(onePulse, oneSpace);
237       duration += (onePulse + oneSpace);
238     }
239   }
240   else
241   {
242     if (secondBit == 0)
243     {
244       // Send the pulse for "Two":
245       rx51device.addPair(twoPulse, twoSpace);
246       duration += (twoPulse + twoSpace);
247     }
248     else
249     {
250       // Send the pulse for "Three":
251       rx51device.addPair(threePulse, threeSpace);
252       duration += (threePulse + threeSpace);
253     }
254   }
255
256   return duration;
257 }