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