Still fixing install, more keyset work
[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 bits)
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, bits);
67 }
68
69
70 void PIRProtocol::setCarrierFrequency(
71   unsigned int freq)
72 {
73   carrierFrequency = freq;
74 }
75
76
77 void PIRProtocol::setDutyCycle(
78   unsigned int dc)
79 {
80   dutyCycle = dc;
81 }
82
83
84 void PIRProtocol::setMinimumRepetitions(
85   unsigned int minrep)
86 {
87   minimumRepetitions = minrep;
88 }
89
90
91 void PIRProtocol::setPreData(
92   unsigned long data,
93   unsigned int bits)
94 {
95   // If the container is not empty, first clear it out:
96   if (!preData.empty())
97   {
98     preData.clear();
99   }
100
101   appendToBitSeq(preData, data, bits);
102 }
103
104
105 void PIRProtocol::setPostData(
106   unsigned long data,
107   unsigned int bits)
108 {
109   // If the container is not empty, first clear it out:
110   if (!postData.empty())
111   {
112     postData.clear();
113   }
114
115   appendToBitSeq(postData, data, bits);
116 }
117
118
119 bool PIRProtocol::isCommandSupported(
120   PIRKeyName command)
121 {
122   return (keycodes.find(command) != keycodes.end());
123 }
124
125
126 void PIRProtocol::appendToBitSeq(
127   CommandSequence &sequence,
128   unsigned int bits,
129   int significantBits)
130 {
131   if (significantBits == 0)
132   {
133     // This is bad, but just return silently for now...
134     return;
135   }
136
137   // For each bit in the char, append a 1 or a 0 into the sequence.
138   // Starting with the largest bit, move forward one bit at a time:
139   unsigned int currentBit = 1 << (significantBits - 1);
140
141   do
142   {
143     if (bits & currentBit)
144     {
145       sequence.push_back(1);
146     }
147     else
148     {
149       sequence.push_back(0);
150     }
151
152     currentBit = currentBit >> 1;
153   }
154   while (currentBit > 0);
155 }
156
157
158 void PIRProtocol::clearRepeatFlag()
159 {
160   QMutexLocker locker(&stopRepeatingMutex);
161   stopRepeatingFlag = false;
162 }
163
164
165 bool PIRProtocol::checkRepeatFlag()
166 {
167   QMutexLocker locker(&stopRepeatingMutex);
168   return stopRepeatingFlag;
169 }
170
171
172 // Note that the following routine blindly sleeps for the amount of time
173 // specified by the LIRC config file.  The extra overhead of processing
174 // each command will mean that repeated commands will overshoot the config
175 // time by some amount.  We could improve accuracy by waiting a little less
176 // than the specified time, if we could get a good handle on how long the
177 // overhead is delaying the command...
178 #define PIEROGI_OVERHEAD_HACK 13260
179
180 void PIRProtocol::sleepUntilRepeat(
181   int commandDuration)
182 {
183   int microseconds;
184
185   // If the LIRC config file specifies the flag "CONST_LENGTH", that means
186   // the "gap" value is the exact amount of time to wait between kicking off
187   // each command.  If not, then the "gap" needs to be added on to the total
188   // time of the previous command to see how long to sleep.
189
190   if (isConstantLength)
191   {
192     microseconds = (gap - commandDuration) - PIEROGI_OVERHEAD_HACK;
193   }
194   else
195   {
196     microseconds = gap - PIEROGI_OVERHEAD_HACK;
197   }
198
199   // Don't even bother sleeping if there's only a few microseconds:
200   if (microseconds < 1000)
201   {
202     return;
203   }
204
205   timespec sleeptime;
206   sleeptime.tv_sec = 0;
207   sleeptime.tv_nsec = microseconds * 1000;
208
209   timespec remainingtime;
210
211   if (nanosleep(&sleeptime, &remainingtime) == -1)
212   {
213     std::stringstream ss;
214     ss << "Problem while sleeping.\n";
215     ss << "Trying to sleep for: " << microseconds << "\n";
216     ss << "Nanosleep returned error: " << strerror(errno) << "\n";
217     throw PIRException(ss.str());
218   }
219 }