A couple of UI additions
[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       std::string s = "Tried to send a non-existent command.\n";
64       throw PIRException(s);
65     }
66
67     // construct the device:
68     PIRRX51Hardware rx51device(carrierFrequency, dutyCycle);
69
70     int repeatCount = 0;
71     int commandDuration = 0;
72     while (repeatCount < MAX_REPEAT_COUNT)
73     {
74       commandDuration = generateStandardCommand((*i).second, rx51device);
75
76       // Now, tell the device to send the whole command:
77       rx51device.sendCommandToDevice();
78
79       // sleep until the next repetition of command:
80       sleepUntilRepeat(commandDuration);
81
82       // Check whether we've reached the minimum required number of repetitons:
83       if (repeatCount >= minimumRepetitions)
84       {
85         // Check whether we've been asked to stop:
86         if (checkRepeatFlag())
87         {
88           QMutexLocker cifLocker(&commandIFMutex);
89           commandInFlight = false;
90           ++keypressCount;
91           return;
92         }
93       }
94
95       ++repeatCount;
96     }
97   }
98   catch (PIRException e)
99   {
100     // inform the gui:
101     emit commandFailed(e.getError().c_str());
102   }
103
104   QMutexLocker cifLocker(&commandIFMutex);
105   commandInFlight = false;
106   ++keypressCount;
107 }
108
109
110 int Nokia32Protocol::generateStandardCommand(
111   const PIRKeyBits &pkb,
112   PIRRX51Hardware &rx51device)
113 {
114   int duration = 0;
115
116   // First, the "header" pulse:
117   rx51device.addPair(headerPulse, headerSpace);
118   duration += (headerPulse + headerSpace);
119
120   // The layout of the Nokia 32 protocol is as follows:
121   // 1) an 8-bit "device code"
122   // 2) an 8-bit "sub-device code"
123   // 3) one toggle bit
124   // 4) seven more bits somehow associated with the device
125   // 5) an 8-bit command code.
126   // All are sent in MSB order.
127
128   // It's a bit of a hack, but I'll store the first 16 bits of address in the
129   // preData, the next 7 bits of address in the postData, and the 8 bits
130   // of command in the firstCode:
131
132   duration += pushBits(preData, rx51device);
133   duration += pushToggleAndBits(postData, rx51device);
134   duration += pushBits(pkb.firstCode, rx51device);
135
136   // Finally add the "trail":
137   rx51device.addSingle(trailerPulse);
138   duration += trailerPulse;
139
140   return duration;
141 }
142
143
144 int Nokia32Protocol::pushBits(
145   const CommandSequence &bits,
146   PIRRX51Hardware &rx51device)
147 {
148   int duration = 0;
149   bool firstBit;
150   bool secondBit;
151
152   CommandSequence::const_iterator i = bits.begin();
153   while (i != bits.end())
154   {
155     firstBit = *i;
156     ++i;
157     if (i == bits.end()) break;
158     secondBit = *i;
159
160     duration += pushDoubleBit(firstBit, secondBit, rx51device);
161
162     ++i;
163   }
164
165   return duration;
166 }
167
168
169 int Nokia32Protocol::pushToggleAndBits(
170   const CommandSequence &bits,
171   PIRRX51Hardware &rx51device)
172 {
173   int duration = 0;
174   bool firstBit;
175   bool secondBit;
176
177   // The first bit is the toggle bit:
178   if (keypressCount % 2)
179   {
180     firstBit = 1;
181   }
182   else
183   {
184     firstBit = 0;
185   }
186
187   CommandSequence::const_iterator i = bits.begin();
188   if (i == bits.end()) return 0;
189
190   secondBit = *i;
191
192   duration += pushDoubleBit(firstBit, secondBit, rx51device);
193
194   ++i;
195
196   while (i != bits.end())
197   {
198     firstBit = *i;
199     ++i;
200     if (i == bits.end()) break;
201     secondBit = *i;
202
203     duration += pushDoubleBit(firstBit, secondBit, rx51device);
204
205     ++i;
206   }
207
208   return duration;
209 }
210
211
212 int Nokia32Protocol::pushDoubleBit(
213   bool firstBit,
214   bool secondBit,
215   PIRRX51Hardware &rx51device)
216 {
217   int duration = 0;
218
219   if (firstBit == 0)
220   {
221     if (secondBit == 0)
222     {
223       // Send the pulse for "Zero":
224       rx51device.addPair(zeroPulse, zeroSpace);
225       duration += (zeroPulse + zeroSpace);
226     }
227     else
228     {
229       // Send the pulse for "One":
230       rx51device.addPair(onePulse, oneSpace);
231       duration += (onePulse + oneSpace);
232     }
233   }
234   else
235   {
236     if (secondBit == 0)
237     {
238       // Send the pulse for "Two":
239       rx51device.addPair(twoPulse, twoSpace);
240       duration += (twoPulse + twoSpace);
241     }
242     else
243     {
244       // Send the pulse for "Three":
245       rx51device.addPair(threePulse, threeSpace);
246       duration += (threePulse + threeSpace);
247     }
248   }
249
250   return duration;
251 }