1 #include "directvprotocol.h"
3 #include "pirrx51hardware.h"
5 #include "pirexception.h"
8 // Some global communications stuff:
10 extern bool commandInFlight;
11 extern QMutex commandIFMutex;
13 // Directv is using a protocol that is novel to me: each pulse and space
14 // encodes an entire bit in an of themselves.
15 // Here are the details I've got:
16 // For a 0 bit, a duration of 600 usecs is used.
17 // For a 1 bit, the duration is 1200 usecs.
18 // The header is a 6000 usec pulse, 1200 usec space.
19 // Commands end with a trailing 600 usec pulse.
20 // Commands are repeated by re-sending the entire pulse train, except that
21 // the header pulse is cut in half to 3000 usec.
22 // There are two different sizes of gap between commands: 9000 usec and
24 // There are three different carrier frequencies: 38 kHz, 40 kHz, and 57 kHz.
26 DirectvProtocol::DirectvProtocol(
29 : PIRProtocol(guiObject, index, 9000, false)
34 void DirectvProtocol::setProtocolParms(
38 if (gap == ShortGap_Directv)
40 setGapSize(9000, false);
44 setGapSize(30000, false);
50 setCarrierFrequency(38000);
53 case MediumFreq_Directv:
54 setCarrierFrequency(40000);
57 case HighFreq_Directv: default:
58 setCarrierFrequency(57000);
64 void DirectvProtocol::startSendingCommand(
65 unsigned int threadableID,
68 // Exceptions here are problematic; I'll try to weed them out by putting the
69 // whole thing in a try/catch block:
72 // First, check if we are meant to be the recipient of this command:
73 if (threadableID != id) return;
77 KeycodeCollection::const_iterator i = keycodes.find(command);
79 // Do we even have this key defined?
80 if (i == keycodes.end())
82 QMutexLocker cifLocker(&commandIFMutex);
83 commandInFlight = false;
85 // std::string s = "Tried to send a non-existent command.\n";
86 // throw PIRException(s);
89 // construct the device:
90 PIRRX51Hardware rx51device(carrierFrequency, dutyCycle);
93 int commandDuration = 0;
94 while (repeatCount < MAX_REPEAT_COUNT)
96 // When repeating, we use a short-pulse header. Otherwise, we use
97 // a long-pulse header.
100 rx51device.addPair(3000, 1200);
101 commandDuration += 4200;
105 rx51device.addPair(6000, 1200);
106 commandDuration += 7200;
109 // Now, generate the rest of the command:
110 commandDuration += generateStandardCommand((*i).second, rx51device);
112 // Now, tell the device to send the whole command:
113 rx51device.sendCommandToDevice();
115 // sleep until the next repetition of command:
116 sleepUntilRepeat(commandDuration);
118 // Check whether we've reached the minimum required number of repetitons:
119 if (repeatCount >= minimumRepetitions)
121 // Check whether we've been asked to stop:
122 if (checkRepeatFlag())
126 QMutexLocker cifLocker(&commandIFMutex);
127 commandInFlight = false;
136 QMutexLocker cifLocker(&commandIFMutex);
137 commandInFlight = false;
139 catch (PIRException e)
142 emit commandFailed(e.getError().c_str());
147 int DirectvProtocol::generateStandardCommand(
148 const PIRKeyBits &pkb,
149 PIRRX51Hardware &rx51device)
153 // DirecTV's protocol appears to consist of four bits of address data,
154 // eight bits of command data, and four bits of checksum data.
155 // The checksum is calculated off of the command, as so: Add up:
156 // 7 * the first two bits of the command, plus
157 // 5 * the second two bits of the command, plus
158 // 3 * the third two bits of the command, plus
159 // 1 * the last two bits of the command,
160 // then just take the last four bits of this value.
162 // - "preData" will contain the address
163 // - "firstCode" will contain the command
164 duration += pushDTVBits(preData, rx51device);
165 duration += pushDTVBits(pkb.firstCode, rx51device);
167 CommandSequence checksumBits;
168 generateChecksum(pkb.firstCode, checksumBits);
169 duration += pushDTVBits(checksumBits, rx51device);
171 // Finally add the "trail":
172 rx51device.addSingle(600);
179 int DirectvProtocol::pushDTVBits(
180 const CommandSequence &bits,
181 PIRRX51Hardware &rx51device)
184 CommandSequence::const_iterator i = bits.begin();
185 while (i != bits.end())
189 // Send the value for "One":
190 rx51device.addSingle(1200);
195 // Send the value for "Zero":
196 rx51device.addSingle(600);
206 void DirectvProtocol::generateChecksum(
207 const CommandSequence &bits,
208 CommandSequence &checksumBits)
210 // We'll generate a 4-bit value based on the 8 bits of the command:
214 CommandSequence::const_iterator i = bits.begin();
216 if (i == bits.end()) return;
218 if (*i) checksumVal += 14;
222 if (i == bits.end()) return;
224 if (*i) checksumVal += 7;
228 if (i == bits.end()) return;
230 if (*i) checksumVal += 10;
234 if (i == bits.end()) return;
236 if (*i) checksumVal += 5;
240 if (i == bits.end()) return;
242 if (*i) checksumVal += 6;
246 if (i == bits.end()) return;
248 if (*i) checksumVal += 3;
252 if (i == bits.end()) return;
254 if (*i) checksumVal += 2;
258 if (i == bits.end()) return;
260 if (*i) checksumVal += 1;
262 // Push the last four bits into the command sequence:
263 if (checksumVal & 0x8)
265 checksumBits.push_back(1);
269 checksumBits.push_back(0);
272 if (checksumVal & 0x4)
274 checksumBits.push_back(1);
278 checksumBits.push_back(0);
281 if (checksumVal & 0x2)
283 checksumBits.push_back(1);
287 checksumBits.push_back(0);
290 if (checksumVal & 0x1)
292 checksumBits.push_back(1);
296 checksumBits.push_back(0);