Moved Mute button, lots new keysets
[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       std::string s = "Tried to send a non-existent command.\n";
61       throw PIRException(s);
62     }
63
64     // construct the device:
65     PIRRX51Hardware rx51device(carrierFrequency, dutyCycle);
66
67     int repeatCount = 0;
68     int commandDuration = 0;
69     while (repeatCount < MAX_REPEAT_COUNT)
70     {
71       // If we are currently repeating, and have a special "repeat signal",
72       // use that signal.  Otherwise, generate a normal command string.
73       if (isShortRepeat && repeatCount)
74       {
75         commandDuration = generateRepeatCommand(rx51device);
76       }
77       else
78       {
79         commandDuration = generateStandardCommand((*i).second, rx51device);
80       }
81
82       // Now, tell the device to send the whole command:
83       rx51device.sendCommandToDevice();
84
85       // sleep until the next repetition of command:
86       sleepUntilRepeat(commandDuration);
87
88       // Check whether we've reached the minimum required number of repetitons:
89       if (repeatCount >= minimumRepetitions)
90       {
91         // Check whether we've been asked to stop:
92         if (checkRepeatFlag())
93         {
94           QMutexLocker cifLocker(&commandIFMutex);
95           commandInFlight = false;
96           return;
97         }
98       }
99
100       ++repeatCount;
101     }
102   }
103   catch (PIRException e)
104   {
105     // inform the gui:
106     emit commandFailed(e.getError().c_str());
107   }
108
109   QMutexLocker cifLocker(&commandIFMutex);
110   commandInFlight = false;
111 }
112
113
114 int NECXProtocol::generateStandardCommand(
115   const PIRKeyBits &pkb,
116   PIRRX51Hardware &rx51device)
117 {
118   int duration = 0;
119
120   // First, the "header" pulse:
121   rx51device.addPair(headerPulse, headerSpace);
122   duration += (headerPulse + headerSpace);
123
124   // In NECX, the address is 16 bits, and is only sent once.  The command
125   // portion is 8 bits, and an inverted copy is sent.
126   // - "preData" should contain 16-bit value
127   // - "bits" should contain 8-bit value
128   duration += pushReverseBits(preData, rx51device);
129   duration += pushReverseBits(pkb.firstCode, rx51device);
130   duration += pushInvertedReverseBits(pkb.firstCode, rx51device);
131
132   // Finally add the "trail":
133   rx51device.addSingle(trailerPulse);
134   duration += trailerPulse;
135
136   return duration;
137 }
138
139
140 int NECXProtocol::generateRepeatCommand(
141   PIRRX51Hardware &rx51device)
142 {
143   int duration = 0;
144
145   // Start with the header:
146   rx51device.addPair(headerPulse, headerSpace);
147   duration += (headerPulse + headerSpace);
148
149   // Add a "1":
150   rx51device.addPair(onePulse, oneSpace);
151   duration += (onePulse + oneSpace);
152
153   // Add the trailer:
154   rx51device.addSingle(trailerPulse);
155   duration += trailerPulse;
156
157   return duration;
158 }