Search for Power Button Panel
[pierogi] / protocols / necxprotocol.cpp
1 #include "necxprotocol.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 NECX protocol is a slight variation of the NEC protocol.  It features
13 // a slightly different header and a slightly different repeat mechanism.
14 // Most of them use the "extended" address form, so I'll just assume that all
15 // of them do.  (It won't hurt anything.)
16 // Otherwise it is nearly identical:
17 // A "zero" is encoded with a 560 usec pulse, 560 usec space.
18 // A "one" is encoded with a 560 usec pulse, and 3*560 (1680) usec space.
19 // The header is a 4500 usec pulse, 4500 usec space.
20 // Commands end with a trailing 560 usec pulse.
21 // A repeat block (if used) is a 4500 usec pulse, 4500 usec space, then a 1
22 // (560 usec pulse, 1680 usec space), then the trailing pulse.
23 // Each command runs for 110000 usec before another can be executed.
24 // The carrier frequency is 38 kHz.
25
26 NECXProtocol::NECXProtocol(
27   QObject *guiObject,
28   unsigned int index,
29   bool srtRep)
30   : SpaceProtocol(
31       guiObject, index,
32       560, 560,
33       560, 1680,
34       4500, 4500,
35       560,
36       110000, true),
37     isShortRepeat(srtRep)
38 {
39 }
40
41
42 void NECXProtocol::startSendingCommand(
43   unsigned int threadableID,
44   PIRKeyName command)
45 {
46   // Exceptions here are problematic; I'll try to weed them out by putting the
47   // whole thing in a try/catch block:
48   try
49   {
50     // First, check if we are meant to be the recipient of this command:
51     if (threadableID != id) return;
52
53     clearRepeatFlag();
54
55     KeycodeCollection::const_iterator i = keycodes.find(command);
56
57     // Do we even have this key defined?
58     if (i == keycodes.end())
59     {
60       QMutexLocker cifLocker(&commandIFMutex);
61       commandInFlight = false;
62       return;
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           break;
98 /*
99           QMutexLocker cifLocker(&commandIFMutex);
100           commandInFlight = false;
101           return;
102 */
103         }
104       }
105
106       ++repeatCount;
107     }
108
109     QMutexLocker cifLocker(&commandIFMutex);
110     commandInFlight = false;
111   }
112   catch (PIRException e)
113   {
114     // inform the gui:
115     emit commandFailed(e.getError().c_str());
116   }
117 }
118
119
120 int NECXProtocol::generateStandardCommand(
121   const PIRKeyBits &pkb,
122   PIRRX51Hardware &rx51device)
123 {
124   int duration = 0;
125
126   // First, the "header" pulse:
127   rx51device.addPair(headerPulse, headerSpace);
128   duration += (headerPulse + headerSpace);
129
130   // In NECX, the address is 16 bits, and is only sent once.  The command
131   // portion is 8 bits, and an inverted copy is sent.
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   // Finally add the "trail":
139   rx51device.addSingle(trailerPulse);
140   duration += trailerPulse;
141
142   return duration;
143 }
144
145
146 int NECXProtocol::generateRepeatCommand(
147   PIRRX51Hardware &rx51device)
148 {
149   int duration = 0;
150
151   // Start with the header:
152   rx51device.addPair(headerPulse, headerSpace);
153   duration += (headerPulse + headerSpace);
154
155   // Add a "1":
156   rx51device.addPair(onePulse, oneSpace);
157   duration += (onePulse + oneSpace);
158
159   // Add the trailer:
160   rx51device.addSingle(trailerPulse);
161   duration += trailerPulse;
162
163   return duration;
164 }