Search for Power Button Panel
[pierogi] / protocols / rc6protocol.cpp
1 #include "rc6protocol.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 // These defines might need to be turned into variables, for odd devices.
12 #define HEADER_PULSE 2666
13 #define HEADER_SPACE 889
14 #define TRAILER_PULSE 889
15 #define TRAILER_SPACE 889
16
17 // I'm requiring standard RC6 initialization to include the 8-bit control
18 // section:
19 RC6Protocol::RC6Protocol(
20   QObject *guiObject,
21   unsigned int index,
22   unsigned int eightBitControl)
23   : PIRProtocol(guiObject, index, 108000, true),
24     biphaseUnit(444),
25     buffer(0),
26     keypressCount(0)
27 {
28   setCarrierFrequency(36000);
29   setPreData(eightBitControl, 8);
30 }
31
32
33 void RC6Protocol::startSendingCommand(
34   unsigned int threadableID,
35   PIRKeyName command)
36 {
37   try
38   {
39     // Is this command meant for us?
40     if (threadableID != id) return;
41
42     clearRepeatFlag();
43
44     KeycodeCollection::const_iterator i = keycodes.find(command);
45
46     // Sanity check:
47     if (i == keycodes.end())
48     {
49       QMutexLocker cifLocker(&commandIFMutex);
50       commandInFlight = false;
51       return;
52 //      std::string s = "Tried to send a non-existent command.\n";
53 //      throw PIRException(s);
54     }
55
56     PIRRX51Hardware rx51device(carrierFrequency, dutyCycle);
57
58     int repeatCount = 0;
59     int duration = 0;
60     while (repeatCount < MAX_REPEAT_COUNT)
61     {
62       // First, construct the "Header" segment of the pulse train.  For now,
63       // I'm only supporting the "consumer electronics mode" of RC6; this code
64       // must be changed if we want to support more than that!
65       //
66       // The header involves:
67       // a) a "lead" of 2666 us pulse, 889 us space;
68       // b) a "start bit", value 1 (so 444 us pulse, 444 us space)
69       // c) three control bits, always set to 0 (so 444 us space,
70       //    444 us pulse each)
71       // d) the double-sized "trailer" bit, toggled on each keypress (so
72       //    either 889 pulse 889 space, or 889 space 889 pulse)
73
74       rx51device.addSingle(HEADER_PULSE); // lead pulse
75       duration += HEADER_PULSE;
76       rx51device.addSingle(HEADER_SPACE); // lead space
77       duration += HEADER_SPACE;
78       rx51device.addSingle(biphaseUnit); // start bit pulse
79       duration += biphaseUnit;
80
81       // start bit space + control bit 1 space:
82       rx51device.addSingle(2 * biphaseUnit);
83       duration += 2 * biphaseUnit;
84       rx51device.addSingle(biphaseUnit); // bit 1 pulse;
85       duration += biphaseUnit;
86       rx51device.addSingle(biphaseUnit); // bit 2 space;
87       duration += biphaseUnit;
88       rx51device.addSingle(biphaseUnit); // bit 2 pulse;
89       duration += biphaseUnit;
90       rx51device.addSingle(biphaseUnit); // bit 3 space;
91       duration += biphaseUnit;
92
93       // Next, need to check whether we should toggle or not:
94       if (keypressCount % 2)
95       {
96         // bit 3 pulse plus long trailer bit pulse:
97         rx51device.addSingle(3 * biphaseUnit);
98         duration += 3 * biphaseUnit;
99
100         // load the trailer bit space onto the buffer:
101         buffer = 2 * biphaseUnit;
102         bufferContainsSpace = true;
103         bufferContainsPulse = false;
104       }
105       else
106       {
107         rx51device.addSingle(biphaseUnit); // bit three pulse
108         duration += biphaseUnit;
109         rx51device.addSingle(2 * biphaseUnit); // trailer bit space
110         duration += 2 * biphaseUnit;
111
112         // load the trailer bit pulse onto the buffer:
113         buffer = 2 * biphaseUnit;
114         bufferContainsPulse = true;
115         bufferContainsSpace = false;
116       }
117
118       // Now, we can start the normal buffering process:
119
120       // push any pre-data onto the device:
121       duration += pushBits(preData, rx51device);
122
123       // push the actual command:
124       duration += pushBits((*i).second.firstCode, rx51device);
125
126       // Flush out the buffer, if necessary:
127       if (buffer)
128       {
129         rx51device.addSingle(buffer);
130         duration += buffer;
131         buffer = 0;
132       }
133
134       // Actually send out the command:
135       rx51device.sendCommandToDevice();
136
137       // Sleep for an amount of time.  (RC6 demands an addtional 6 unit space
138       // at the end of any command...)
139       sleepUntilRepeat(duration + 6 * biphaseUnit);
140
141       // Have we been told to stop yet?
142       if (checkRepeatFlag())
143       {
144         break;
145 /*
146         // Yes, we can now quit repeating:
147         ++keypressCount;
148         QMutexLocker ciflocker(&commandIFMutex);
149         commandInFlight = false;
150         return;
151 */
152       }
153     }
154
155     ++keypressCount;
156     QMutexLocker cifLocker(&commandIFMutex);
157     commandInFlight = false;
158   }
159   catch (PIRException e)
160   {
161     emit commandFailed(e.getError().c_str());
162   }
163 }
164
165
166 int RC6Protocol::pushBits(
167   const CommandSequence &bits,
168   PIRRX51Hardware &rx51device)
169 {
170   int bitsDuration = 0;
171
172   CommandSequence::const_iterator i = bits.begin();
173   bool bitValue;
174
175   while (i != bits.end())
176   {
177     bitValue = *i;
178
179     // In RC6, a "0" is represented by a space followed by a pulse,
180     // and a "1" is represented by a pulse followed by a space.
181     if (bitValue)
182     {
183       // This is a 1, so add a pulse, then a space.
184       // First, the pulse:
185       if (bufferContainsPulse)
186       {
187         rx51device.addSingle(buffer + biphaseUnit);
188         bitsDuration += (buffer + biphaseUnit);
189         buffer = 0;
190         bufferContainsPulse = false;
191       }
192       else
193       {
194         if (bufferContainsSpace)
195         {
196           // Flush the buffer:
197           rx51device.addSingle(buffer);
198           bitsDuration += buffer;
199           buffer = 0;
200           bufferContainsSpace = false;
201         }
202         // Now, add the pulse:
203         rx51device.addSingle(biphaseUnit);
204         bitsDuration += biphaseUnit;
205       }
206
207       // Next, push a space onto the buffer:
208       buffer = biphaseUnit;
209       bufferContainsSpace = true;
210     }
211     else
212     {
213       // This is a 0, so add a space, then a pulse.
214       if (bufferContainsSpace)
215       {
216         // Merge this space and the previous one, and send to device:
217         rx51device.addSingle(buffer + biphaseUnit);
218         bitsDuration += (buffer + biphaseUnit);
219         buffer = 0;
220         bufferContainsSpace = false;
221       }
222       else
223       {
224         if (bufferContainsPulse)
225         {
226           // Flush out the buffer:
227           rx51device.addSingle(buffer);
228           bitsDuration += buffer;
229           buffer = 0;
230           bufferContainsPulse = false;
231         }
232
233         // push a space onto the device:
234         rx51device.addSingle(biphaseUnit);
235         bitsDuration += biphaseUnit;
236       }
237
238       // Put a pulse into the buffer to wait:
239       buffer = biphaseUnit;
240       bufferContainsPulse = true;
241     }
242
243     ++i;
244   }
245
246   return bitsDuration;
247 }