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