Improved to "half-way usable" (version 0.5)
[pierogi] / sharpprotocol.cpp
1 #include "sharpprotocol.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 // Sharp's protocol should have the following attributes:
13 // A "zero" is encoded with a 320 usec pulse, 680 usec space.
14 // A "one" is encoded with a 320 usec pulse, and 1680 usec space.
15 // There is no header pulse.
16 // The pulse train ends with a trailing 320 usec pulse.
17 // For repeating, the entire train is re-sent, except that the command
18 // section (and the last two bits) are inverted in each odd repeat.
19 // There is a 40000 usec delay between the end of one command and the start
20 // of the next.
21 // The command should be repeated at least once.
22 // The carrier frequency is 38 kHz, duty cycle is 1/3.
23
24 SharpProtocol::SharpProtocol(
25   QObject *guiObject,
26   unsigned int index,
27   bool expBit)
28   : PIRProtocol(guiObject, index, 40000, false),
29     zeroPulse(320),
30     zeroSpace(680),
31     onePulse(320),
32     oneSpace(1680),
33     trailerPulse(320),
34     expansionBit(expBit)
35 {
36   setCarrierFrequency(38000);
37   setDutyCycle(33);
38 }
39
40
41 void SharpProtocol::startSendingCommand(
42   unsigned int threadableID,
43   PIRKeyName command)
44 {
45   // Exceptions here are problematic; I'll try to weed them out by putting the
46   // whole thing in a try/catch block:
47   try
48   {
49     // First, check if we are meant to be the recipient of this command:
50     if (threadableID != id) return;
51
52     clearRepeatFlag();
53
54     KeycodeCollection::const_iterator i = keycodes.find(command);
55
56     // Do we even have this key defined?
57     if (i == keycodes.end())
58     {
59       std::string s = "Tried to send a non-existent command.\n";
60       throw PIRException(s);
61     }
62
63     // construct the device:
64     PIRRX51Hardware rx51device(carrierFrequency, dutyCycle);
65
66     int repeatCount = 0;
67     int commandDuration = 0;
68     while (repeatCount < MAX_REPEAT_COUNT)
69     {
70       // Every other repeat count, we invert everything but the address:
71       if (repeatCount % 2)
72       {
73         commandDuration = generateToggledCommand((*i).second, rx51device);
74       }
75       else
76       {
77         commandDuration = generateStandardCommand((*i).second, rx51device);
78       }
79
80       // Now, tell the device to send the whole command:
81       rx51device.sendCommandToDevice();
82
83       // sleep until the next repetition of command:
84       sleepUntilRepeat(commandDuration);
85
86       // Check whether we've reached the minimum required number of repetitons:
87 //      if (repeatCount >= minimumRepetitions)
88       if (repeatCount >= 1)
89       {
90         // Check whether we've been asked to stop:
91         if (checkRepeatFlag())
92         {
93           QMutexLocker cifLocker(&commandIFMutex);
94           commandInFlight = false;
95           return;
96         }
97       }
98
99       ++repeatCount;
100     }
101   }
102   catch (PIRException e)
103   {
104     // inform the gui:
105     emit commandFailed(e.getError().c_str());
106   }
107
108   QMutexLocker cifLocker(&commandIFMutex);
109   commandInFlight = false;
110 }
111
112
113 int SharpProtocol::generateStandardCommand(
114   const CommandSequence &bits,
115   PIRRX51Hardware &rx51device)
116 {
117   int duration = 0;
118
119   // Right now, I've got both the 5-bit address and the 8-bit command
120   // smushed together into the command sequence.  Need to pick each of
121   // these out and reverse their bits:
122
123   // First, push the address:
124
125   CommandSequence::const_reverse_iterator addressStart = bits.rbegin();
126   // Move past the command's 8 bits:
127   addressStart += 8;
128   duration += pushBits(addressStart, bits.rend(), rx51device);
129
130   // Next, push the command:
131   CommandSequence::const_reverse_iterator commandEnd = bits.rbegin();
132   // Again, move past the commands's 8 bits:
133   commandEnd += 8;
134   duration += pushBits(bits.rbegin(), commandEnd, rx51device);
135
136   // Next, there is an "expansion" bit and a "check" bit.  Not entirely sure
137   // what these two do.  The check bit is fixed at "1".
138   if (expansionBit)
139   {
140     rx51device.addPair(onePulse, oneSpace);
141     duration += (onePulse + oneSpace);
142   }
143   else
144   {
145     rx51device.addPair(zeroPulse, zeroSpace);
146     duration += (zeroPulse + zeroSpace);
147   }
148
149   rx51device.addPair(zeroPulse, zeroSpace);
150   duration += (zeroPulse + zeroSpace);
151
152   // Finally add the "trail":
153   rx51device.addSingle(trailerPulse);
154   duration += trailerPulse;
155
156   return duration;
157 }
158
159
160 // This is the same as the standard command, except all bits but the address
161 // are inverted:
162 int SharpProtocol::generateToggledCommand(
163   const CommandSequence &bits,
164   PIRRX51Hardware &rx51device)
165 {
166   int duration = 0;
167
168   CommandSequence::const_reverse_iterator addressStart = bits.rbegin();
169   addressStart += 8;
170   duration += pushBits(addressStart, bits.rend(), rx51device);
171
172   CommandSequence::const_reverse_iterator commandEnd = bits.rbegin();
173   commandEnd += 8;
174   // This time we invert the bits:
175   duration += pushInvertedBits(bits.rbegin(), commandEnd, rx51device);
176
177   // We'll also invert the two administrative bits here:
178   if (expansionBit)
179   {
180     rx51device.addPair(zeroPulse, zeroSpace);
181     duration += (zeroPulse + zeroSpace);
182   }
183   else
184   {
185     rx51device.addPair(onePulse, oneSpace);
186     duration += (onePulse + oneSpace);
187   }
188
189   rx51device.addPair(onePulse, oneSpace);
190   duration += (onePulse + oneSpace);
191
192   // Add trail on end:
193   rx51device.addSingle(trailerPulse);
194   duration += trailerPulse;
195
196   return duration;
197 }
198
199
200 int SharpProtocol::pushBits(
201   CommandSequence::const_reverse_iterator i,
202   CommandSequence::const_reverse_iterator end,
203   PIRRX51Hardware &rx51device)
204 {
205   int duration = 0;
206
207   while (i != end);
208   {
209     if (*i)
210     {
211       // Send the pulse for "One":
212       rx51device.addPair(onePulse, oneSpace);
213       duration += (onePulse + oneSpace);
214     }
215     else
216     {
217       // Send the pulse for "Zero":
218       rx51device.addPair(zeroPulse, zeroSpace);
219       duration += (zeroPulse + zeroSpace);
220     }
221     ++i;
222   }
223
224   return duration;
225 }
226
227
228 int SharpProtocol::pushInvertedBits(
229   CommandSequence::const_reverse_iterator i,
230   CommandSequence::const_reverse_iterator end,
231   PIRRX51Hardware &rx51device)
232 {
233   int duration = 0;
234
235   while (i != end)
236   {
237     if (*i)
238     {
239       // Send the pulse for "Zero":
240       rx51device.addPair(zeroPulse, zeroSpace);
241       duration += (zeroPulse + zeroSpace);
242     }
243     else
244     {
245       // Send the pulse for "One":
246       rx51device.addPair(onePulse, oneSpace);
247       duration += (onePulse + oneSpace);
248     }
249     ++i;
250   }
251
252   return duration;
253 }