Possible Uninstall Fix, plus cleanup, more keysets
[pierogi] / protocols / necprotocol.cpp
1 #include "necprotocol.h"
2
3 #include "pirrx51hardware.h"
4
5 #include "pirexception.h"
6
7 // Some global communications stuff:
8 #include <QMutex>
9 extern bool commandInFlight;
10 extern QMutex commandIFMutex;
11
12 // The official NEC protocol, as I understand it, has the following attributes:
13 // A "zero" is encoded with a 560 usec pulse, 560 usec space.
14 // A "one" is encoded with a 560 usec pulse, and 3*560 (1680) usec space.
15 // The header is a 9000 usec pulse, 4500 usec space.
16 // Commands end with a trailing 560 usec pulse.
17 // A repeat block is a 9000 usec pulse, 2250 usec space, then trailing pulse.
18 // Each command runs for 110000 usec before another can be executed.
19
20 NECProtocol::NECProtocol(
21   QObject *guiObject,
22   unsigned int index,
23   bool extNEC,
24   bool srtRep)
25   : SpaceProtocol(
26       guiObject, index,
27       560, 560,
28       560, 1680,
29       9000, 4500,
30       560,
31       110000, true),
32     repeatPulse(9000),
33     repeatSpace(2250),
34     isExtendedNEC(extNEC),
35     isShortRepeat(srtRep)
36 {
37 }
38
39
40 void NECProtocol::startSendingCommand(
41   unsigned int threadableID,
42   PIRKeyName command)
43 {
44   // Exceptions here are problematic; I'll try to weed them out by putting the
45   // whole thing in a try/catch block:
46   try
47   {
48     // First, check if we are meant to be the recipient of this command:
49     if (threadableID != id) return;
50
51     // An object that helps keep track of the number of commands:
52 //    PIRCommandCounter commandCounter;
53
54     // Ok, we're going to lock down this method and make sure
55     // only one guy at a time passes this point:
56 //    QMutexLocker commandLocker(&commandMutex);
57
58     clearRepeatFlag();
59
60     KeycodeCollection::const_iterator i = keycodes.find(command);
61
62     // Do we even have this key defined?
63     if (i == keycodes.end())
64     {
65       std::string s = "Tried to send a non-existent command.\n";
66       throw PIRException(s);
67     }
68
69     // construct the device:
70     PIRRX51Hardware rx51device(carrierFrequency, dutyCycle);
71
72     int repeatCount = 0;
73     int commandDuration = 0;
74     while (repeatCount < MAX_REPEAT_COUNT)
75     {
76       // If we are currently repeating, and have a special "repeat signal",
77       // use that signal.  Otherwise, generate a normal command string.
78       if (isShortRepeat && repeatCount)
79       {
80         commandDuration = generateRepeatCommand(rx51device);
81       }
82       else
83       {
84         commandDuration = generateStandardCommand((*i).second, rx51device);
85       }
86
87       // Now, tell the device to send the whole command:
88       rx51device.sendCommandToDevice();
89
90       // sleep until the next repetition of command:
91       sleepUntilRepeat(commandDuration);
92
93       // Check whether we've reached the minimum required number of repetitons:
94       if (repeatCount >= minimumRepetitions)
95       {
96         // Check whether we've been asked to stop:
97         if (checkRepeatFlag())
98         {
99           QMutexLocker cifLocker(&commandIFMutex);
100           commandInFlight = false;
101           return;
102         }
103       }
104
105       ++repeatCount;
106     }
107   }
108   catch (PIRException e)
109   {
110     // inform the gui:
111     emit commandFailed(e.getError().c_str());
112   }
113
114   QMutexLocker cifLocker(&commandIFMutex);
115   commandInFlight = false;
116 }
117
118
119 int NECProtocol::generateStandardCommand(
120   const PIRKeyBits &pkb,
121   PIRRX51Hardware &rx51device)
122 {
123   int duration = 0;
124
125   // First, the "header" pulse:
126   rx51device.addPair(headerPulse, headerSpace);
127   duration += (headerPulse + headerSpace);
128
129   // Now, check the encoding format:
130   if (isExtendedNEC)
131   {
132     // In extended NEC, the address has been extended to 16 bits, and is only
133     // sent once.  The command portion stays the same.
134     // - "preData" should contain 16-bit value
135     // - "bits" should contain 8-bit value
136     duration += pushReverseBits(preData, rx51device);
137     duration += pushReverseBits(pkb.firstCode, rx51device);
138     duration += pushInvertedReverseBits(pkb.firstCode, rx51device);
139   }
140   else
141   {
142     // Standard NEC is made up of an eight-bit "address" and an eight-bit
143     // "command".  First the address bits are sent (in reverse order), then
144     // the address bits are inverted and sent again (in reverse order).
145     // Next, we do the same to the command bits.
146     // - "preData" should contain 8-bit value
147     // - "bits" should contain 8-bit value
148     duration += pushReverseBits(preData, rx51device);
149     duration += pushInvertedReverseBits(preData, rx51device);
150     duration += pushReverseBits(pkb.firstCode, rx51device);
151     duration += pushInvertedReverseBits(pkb.firstCode, rx51device);
152   }
153
154   // Finally add the "trail":
155   rx51device.addSingle(trailerPulse);
156   duration += trailerPulse;
157
158   return duration;
159 }
160
161
162 int NECProtocol::generateRepeatCommand(
163   PIRRX51Hardware &rx51device)
164 {
165   int duration = 0;
166
167   // Add the repeat pulse:
168   rx51device.addPair(repeatPulse, repeatSpace);
169   duration += (repeatPulse + repeatSpace);
170
171   // Add the trailer:
172   rx51device.addSingle(trailerPulse);
173   duration += trailerPulse;
174
175   return duration;
176 }