98d8ebbb8e34273dbcb79a5cf183fc7f42438a86
[pierogi] / rc5protocol.cpp
1 #include "rc5protocol.h"
2
3 #include "pirexception.h"
4
5 #include <QMutex>
6 extern bool commandInFlight;
7 extern QMutex commandIFMutex;
8
9 RC5Protocol::RC5Protocol(
10   QObject *guiObject,
11   unsigned int index,
12   unsigned int bPulse,
13   unsigned int bSpace,
14   unsigned int lPulse,
15   unsigned int gSpace,
16   bool iclflag)
17   : PIRProtocol(guiObject, index, gSpace, iclflag),
18     biphasePulse(bPulse),
19     biphaseSpace(bSpace),
20     leadPulse(lPulse),
21     buffer(0),
22     keypressCount(0)
23 {
24 }
25
26
27 void RC5Protocol::setHeaderPair(
28   unsigned int pulse,
29   unsigned int space)
30 {
31   headerPulse = pulse;
32   headerSpace = space;
33   hasHeaderPair = true;
34 }
35
36
37 void RC5Protocol::setPreData(
38   unsigned long data,
39   unsigned int bits)
40 {
41   appendToBitSeq(preData, data, bits);
42 }
43
44
45 void RC5Protocol::setToggleBit(
46   unsigned int bit)
47 {
48   toggleBit = bit;
49 }
50
51
52 void RC5Protocol::startSendingCommand(
53   unsigned int threadableID,
54   PIRKeyName command)
55 {
56   // Dumping entire method inside of try/catch, to deal with cross-thread
57   // exception handling:
58   try
59   {
60     // Check if this command is meant for us:
61     if (threadableID != id) return;
62
63     clearRepeatFlag();
64
65     KeycodeCollection::const_iterator i = keycodes.find(command);
66
67     // Sanity check, make sure command exists first:
68     if (i == keycodes.end())
69     {
70       std::string s = "Tried to send a non-existent command.\n";
71       throw PIRException(s);
72     }
73
74     // Construct the object that communicates with the device driver:
75     PIRRX51Hardware rx51device(carrierFrequency, dutyCycle);
76
77     int repeatCount = 0;
78     while (repeatCount < MAX_REPEAT_COUNT)
79     {
80       int commandDuration = 0;
81
82       // Now, throw together an RC5 protocol command string:
83       buffer = 0;
84       bufferContainsPulse = false;
85       bufferContainsSpace = false;
86   
87       // Start off the first pulse with the lead, if any:
88       if (leadPulse)
89       {
90         buffer = leadPulse;
91         bufferContainsPulse = true;
92       }
93
94       // Encode the bits:
95       commandDuration += pushBits((*i).second, rx51device);
96
97       // Clear out the buffer, if necessary:
98       if (buffer)
99       {
100         rx51device.addSingle(buffer);
101         commandDuration += buffer;
102         buffer = 0;
103         bufferContainsSpace = false;
104         bufferContainsPulse = false;
105       }
106
107       // Now, tell the device to send the whole command:
108       rx51device.sendCommandToDevice();
109
110       // Sleep for an amount of time.  (Need to make this interruptable!)
111       sleepUntilRepeat(commandDuration);
112
113       // Have we satisfied the minimum number of repetitions?
114       if (repeatCount >= minimumRepetitions)
115       {
116         // Have we been told to stop yet?
117         if (checkRepeatFlag())
118         {
119           // Ok, then we can quit now:
120           ++keypressCount;
121           QMutexLocker cifLocker(&commandIFMutex);
122           commandInFlight = false;
123           return;
124         }
125       }
126
127       ++repeatCount;
128     }
129   }
130   catch (PIRException e)
131   {
132     emit commandFailed(e.getError().c_str());
133   }
134
135   ++keypressCount;
136   QMutexLocker cifLocker(&commandIFMutex);
137   commandInFlight = false;
138 }
139
140
141 int RC5Protocol::pushBits(
142   const CommandSequence &bits,
143   PIRRX51Hardware &rx51device)
144 {
145   int bitsDuration = 0;
146
147   // Rather than encoding a 0 or 1 through the timing of a pulse, RC5 encodes
148   // a bit by swapping the order of pulses and spaces.  (This is called
149   // "biphase".)
150
151   CommandSequence::const_iterator i = bits.begin();
152   int bitCount = 1;
153   bool bitValue;
154
155   while (i != bits.end())
156   {
157     bitValue = *i;
158
159     if (bitCount == toggleBit)  // are we on a toggled bit?
160     {
161       if (keypressCount % 2)  // is it time to toggle?
162       {
163         bitValue = !bitValue;  // then flip the bit
164       }
165     }
166
167     if (bitValue)
168     {
169       // We've got a "1".  First add a space, then a pulse.
170       if (bufferContainsSpace)
171       {
172         // Merge our space with the previous space, and send them to
173         // the device.
174         rx51device.addSingle(buffer + biphaseSpace);
175         bitsDuration += (buffer + biphaseSpace);
176         buffer = 0;
177         bufferContainsSpace = false;
178       }
179       else
180       {
181         if (bufferContainsPulse)
182         {
183           // Flush the buffer:
184           rx51device.addSingle(buffer);
185           bitsDuration += buffer;
186           buffer = 0;
187           bufferContainsPulse = false;
188         }
189         // Add a space:
190         rx51device.addSingle(biphaseSpace);
191         bitsDuration += biphaseSpace;
192       }
193
194       // Put a pulse into the buffer to wait.
195       buffer = biphasePulse;
196       bufferContainsPulse = true;
197     }
198     else
199     {
200       // We've got a "0".  First add a pulse, then a space.
201       if (bufferContainsPulse)
202       {
203         // Merge our pulse with the previous one, and send them to the device:
204         rx51device.addSingle(buffer + biphasePulse);
205         bitsDuration += (buffer + biphasePulse);
206         buffer = 0;
207         bufferContainsPulse = false;
208       }
209       else
210       {
211         if (bufferContainsSpace)
212         {
213           // Flush out the buffer:
214           rx51device.addSingle(buffer);
215           bitsDuration += buffer;
216           buffer = 0;
217           bufferContainsSpace = false;
218         }
219
220         // Add a pulse:
221         rx51device.addSingle(biphasePulse);
222         bitsDuration += biphasePulse;
223       }
224
225       // Put a space into the buffer to wait:
226       buffer = biphaseSpace;
227       bufferContainsSpace = true;
228     }
229
230     ++i;
231     ++bitCount;
232   }
233
234   return bitsDuration;
235 }