Improved to "half-way usable" (version 0.5)
[pierogi] / pirprotocol.cpp
1 #include "pirprotocol.h"
2
3 #include <QMutex>
4 #include <QMetaType>
5
6 #include <time.h>
7 #include <sstream>
8 #include <errno.h>
9 #include "pirexception.h"
10
11 // A flag for communicating with the main thread:
12 extern bool stopRepeatingFlag;
13 extern QMutex stopRepeatingMutex;
14
15 // Total of all running commands
16 extern bool commandInFlight;
17 extern QMutex commandIFMutex;
18
19 // From what I understand (mostly from reading LIRC config files), NEC
20 // protocol based remotes mostly use a frequency of 38000 units and a
21 // duty cycle of 50%.  They'll be set to these defaults here, and overridden
22 // as needed by child classes.
23
24 PIRProtocol::PIRProtocol(
25   QObject *guiObject,
26   unsigned int index,
27   unsigned int gSpace,
28   bool iclflag)
29   : carrierFrequency(38000),
30     dutyCycle(50),
31     isConstantLength(iclflag),
32     gap(gSpace),
33     minimumRepetitions(0),
34     id(index)
35 {
36   qRegisterMetaType<PIRKeyName>("PIRKeyName");
37
38   QObject::connect(
39     guiObject,
40     SIGNAL(buttonPressed(unsigned int, PIRKeyName)),
41     this,
42     SLOT(startSendingCommand(unsigned int, PIRKeyName)),
43     Qt::QueuedConnection);
44
45   QObject::connect(
46     this,
47     SIGNAL(commandFailed(const char *)),
48     guiObject,
49     SLOT(receivedExternalWarning(const char *)),
50     Qt::QueuedConnection);
51 }
52
53
54 void PIRProtocol::addKey(
55   PIRKeyName key,
56   unsigned long command,
57   unsigned int size)
58 {
59   // First, if key already exists, clear it out:
60   KeycodeCollection::iterator i = keycodes.find(key);
61   if (i != keycodes.end())
62   {
63     i->second.clear();
64   }
65
66   appendToBitSeq(keycodes[key], command, size);
67 }
68
69
70 void PIRProtocol::addSIRCKey(
71   PIRKeyName key,
72   unsigned int addressData,
73   unsigned int size,
74   unsigned int commandData)
75 {
76   // First, if key already exists, clear it out:
77   KeycodeCollection::iterator i = keycodes.find(key);
78   if (i != keycodes.end())
79   {
80     i->second.clear();
81   }
82
83   // First, append the address data:
84   appendToBitSeq(keycodes[key], addressData, size);
85
86   // Next, the command data.  The size is always 7 bits:
87   appendToBitSeq(keycodes[key], commandData, 7);
88 }
89
90
91 void PIRProtocol::addSIRC20Key(
92   PIRKeyName key,
93   unsigned int secondaryAddressData,
94   unsigned int primaryAddressData,
95   unsigned int commandData)
96 {
97   // First, if key already exists, clear it out:
98   KeycodeCollection::iterator i = keycodes.find(key);
99   if (i != keycodes.end())
100   {
101     i->second.clear();
102   }
103
104   // First, append the secondary address data:
105   appendToBitSeq(keycodes[key], secondaryAddressData, 8);
106
107   // Next, the primary address data:
108   appendToBitSeq(keycodes[key], primaryAddressData, 5);
109
110   // Next, the command data.  The size is always 7 bits:
111   appendToBitSeq(keycodes[key], commandData, 7);
112 }
113
114
115 void PIRProtocol::addSharpKey(
116   PIRKeyName key,
117   unsigned int addressData,
118   unsigned int commandData)
119 {
120   // First, if key already exists, clear it out:
121   KeycodeCollection::iterator i = keycodes.find(key);
122   if (i != keycodes.end())
123   {
124     i->second.clear();
125   }
126
127   // Sharp commands are all 5 bit address, 8 bit command:
128   appendToBitSeq(keycodes[key], addressData, 5);
129   appendToBitSeq(keycodes[key], commandData, 8);
130 }
131
132
133 void PIRProtocol::setCarrierFrequency(
134   unsigned int freq)
135 {
136   carrierFrequency = freq;
137 }
138
139
140 void PIRProtocol::setDutyCycle(
141   unsigned int dc)
142 {
143   dutyCycle = dc;
144 }
145
146
147 void PIRProtocol::setMinimumRepetitions(
148   unsigned int minrep)
149 {
150   minimumRepetitions = minrep;
151 }
152
153
154 void PIRProtocol::setPreData(
155   unsigned long data,
156   unsigned int bits)
157 {
158   // If the container is not empty, first clear it out:
159   if (!preData.empty())
160   {
161     preData.clear();
162   }
163
164   appendToBitSeq(preData, data, bits);
165 }
166
167
168 void PIRProtocol::setPostData(
169   unsigned long data,
170   unsigned int bits)
171 {
172   // If the container is not empty, first clear it out:
173   if (!postData.empty())
174   {
175     postData.clear();
176   }
177
178   appendToBitSeq(postData, data, bits);
179 }
180
181
182 bool PIRProtocol::isCommandSupported(
183   PIRKeyName command)
184 {
185   return (keycodes.find(command) != keycodes.end());
186 }
187
188
189 void PIRProtocol::appendToBitSeq(
190   CommandSequence &sequence,
191   unsigned int bits,
192   int size)
193 {
194   if (size == 0)
195   {
196     // This is bad, but just return silently for now...
197     return;
198   }
199
200   // For each bit in the char, append a 1 or a 0 into the sequence.
201   // Starting with the largest bit, move forward one bit at a time:
202   unsigned int currentBit = 1 << (size - 1);
203
204   do
205   {
206     if (bits & currentBit)
207     {
208       sequence.push_back(1);
209     }
210     else
211     {
212       sequence.push_back(0);
213     }
214
215     currentBit = currentBit >> 1;
216   }
217   while (currentBit > 0);
218 }
219
220
221 void PIRProtocol::clearRepeatFlag()
222 {
223   QMutexLocker locker(&stopRepeatingMutex);
224   stopRepeatingFlag = false;
225 }
226
227
228 bool PIRProtocol::checkRepeatFlag()
229 {
230   QMutexLocker locker(&stopRepeatingMutex);
231   return stopRepeatingFlag;
232 }
233
234
235 // Note that the following routine blindly sleeps for the amount of time
236 // specified by the LIRC config file.  The extra overhead of processing
237 // each command will mean that repeated commands will overshoot the config
238 // time by some amount.  We could improve accuracy by waiting a little less
239 // than the specified time, if we could get a good handle on how long the
240 // overhead is delaying the command...
241 #define PIEROGI_OVERHEAD_HACK 13260
242
243 void PIRProtocol::sleepUntilRepeat(
244   int commandDuration)
245 {
246   int microseconds;
247
248   // If the LIRC config file specifies the flag "CONST_LENGTH", that means
249   // the "gap" value is the exact amount of time to wait between kicking off
250   // each command.  If not, then the "gap" needs to be added on to the total
251   // time of the previous command to see how long to sleep.
252
253   if (isConstantLength)
254   {
255     microseconds = (gap - commandDuration) - PIEROGI_OVERHEAD_HACK;
256   }
257   else
258   {
259     microseconds = gap - PIEROGI_OVERHEAD_HACK;
260   }
261
262 /*
263   // Don't even bother sleeping if there's only a few microseconds:
264   if (microseconds < 1000)
265   {
266     return;
267   }
268 */
269   // For now, I'm going to enforce a minimum sleep of 10 ms, so that we
270   // don't get runaway commands:
271   if (microseconds < 10000)
272   {
273     microseconds = 10000;
274   }
275
276   timespec sleeptime;
277   sleeptime.tv_sec = 0;
278   sleeptime.tv_nsec = microseconds * 1000;
279
280   timespec remainingtime;
281
282   if (nanosleep(&sleeptime, &remainingtime) == -1)
283   {
284     std::stringstream ss;
285     ss << "Problem while sleeping.\n";
286     ss << "Trying to sleep for: " << microseconds << "\n";
287     ss << "Nanosleep returned error: " << strerror(errno) << "\n";
288     throw PIRException(ss.str());
289   }
290 }