1 #include "necxprotocol.h"
3 #include "pirrx51hardware.h"
5 #include "pirexception.h"
7 // Some global communications stuff:
9 extern bool commandInFlight;
10 extern QMutex commandIFMutex;
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.
26 NECXProtocol::NECXProtocol(
42 void NECXProtocol::startSendingCommand(
43 unsigned int threadableID,
46 // Exceptions here are problematic; I'll try to weed them out by putting the
47 // whole thing in a try/catch block:
50 // First, check if we are meant to be the recipient of this command:
51 if (threadableID != id) return;
55 KeycodeCollection::const_iterator i = keycodes.find(command);
57 // Do we even have this key defined?
58 if (i == keycodes.end())
60 std::string s = "Tried to send a non-existent command.\n";
61 throw PIRException(s);
64 // construct the device:
65 PIRRX51Hardware rx51device(carrierFrequency, dutyCycle);
68 int commandDuration = 0;
69 while (repeatCount < MAX_REPEAT_COUNT)
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)
75 commandDuration = generateRepeatCommand(rx51device);
79 commandDuration = generateStandardCommand((*i).second, rx51device);
82 // Now, tell the device to send the whole command:
83 rx51device.sendCommandToDevice();
85 // sleep until the next repetition of command:
86 sleepUntilRepeat(commandDuration);
88 // Check whether we've reached the minimum required number of repetitons:
89 if (repeatCount >= minimumRepetitions)
91 // Check whether we've been asked to stop:
92 if (checkRepeatFlag())
94 QMutexLocker cifLocker(&commandIFMutex);
95 commandInFlight = false;
103 catch (PIRException e)
106 emit commandFailed(e.getError().c_str());
109 QMutexLocker cifLocker(&commandIFMutex);
110 commandInFlight = false;
114 int NECXProtocol::generateStandardCommand(
115 const PIRKeyBits &pkb,
116 PIRRX51Hardware &rx51device)
120 // First, the "header" pulse:
121 rx51device.addPair(headerPulse, headerSpace);
122 duration += (headerPulse + headerSpace);
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);
132 // Finally add the "trail":
133 rx51device.addSingle(trailerPulse);
134 duration += trailerPulse;
140 int NECXProtocol::generateRepeatCommand(
141 PIRRX51Hardware &rx51device)
145 // Start with the header:
146 rx51device.addPair(headerPulse, headerSpace);
147 duration += (headerPulse + headerSpace);
150 rx51device.addPair(onePulse, oneSpace);
151 duration += (onePulse + oneSpace);
154 rx51device.addSingle(trailerPulse);
155 duration += trailerPulse;