1 #include "dishprotocol.h"
3 #include "pirrx51hardware.h"
5 #include "pirexception.h"
7 // Some global communications stuff:
9 extern bool commandInFlight;
10 extern QMutex commandIFMutex;
12 // Dish Network, or now just "Dish", has a unique protocol. It uses "space"
13 // encoding, but otherwise is unlike just about anything else out there.
14 // Here's what I've got on it:
15 // A "zero" is encoded with a 400 usec pulse, 2800 usec space.
16 // A "one" is encoded with a 400 usec pulse, 1600 usec space.
17 // The header is a 400 usec pulse, 6000 usec space.
18 // Commands end with a trailing 400 usec pulse.
19 // Commands are repeated without the header (or, if you like, you can consider
20 // the trailing pulse to be the header for the next repetition).
21 // There is a 6000 usec gap between repetitions.
22 // The carrier frequency is apparently 57600 kHz, or thereabouts.
23 // The duty cycle is 1/3.
25 DishProtocol::DishProtocol(
36 setCarrierFrequency(57600);
41 void DishProtocol::startSendingCommand(
42 unsigned int threadableID,
45 // Exceptions here are problematic; I'll try to weed them out by putting the
46 // whole thing in a try/catch block:
49 // First, check if we are meant to be the recipient of this command:
50 if (threadableID != id) return;
54 KeycodeCollection::const_iterator i = keycodes.find(command);
56 // Do we even have this key defined?
57 if (i == keycodes.end())
59 QMutexLocker cifLocker(&commandIFMutex);
60 commandInFlight = false;
62 // std::string s = "Tried to send a non-existent command.\n";
63 // throw PIRException(s);
66 // construct the device:
67 PIRRX51Hardware rx51device(carrierFrequency, dutyCycle);
70 int commandDuration = 0;
71 while (repeatCount < MAX_REPEAT_COUNT)
73 // If this is not a repetition, we need to add the initial header:
76 rx51device.addPair(headerPulse, headerSpace);
77 commandDuration += (headerPulse + headerSpace);
80 // generate the rest of the command:
81 commandDuration += generateStandardCommand(i->second, rx51device);
83 // Now, tell the device to send the whole command:
84 rx51device.sendCommandToDevice();
86 // sleep until the next repetition of command:
87 sleepUntilRepeat(commandDuration);
89 // Check whether we've reached the minimum required number of repetitons:
90 if (repeatCount >= minimumRepetitions)
92 // Check whether we've been asked to stop:
93 if (checkRepeatFlag())
97 QMutexLocker cifLocker(&commandIFMutex);
98 commandInFlight = false;
107 QMutexLocker cifLocker(&commandIFMutex);
108 commandInFlight = false;
110 catch (PIRException e)
113 emit commandFailed(e.getError().c_str());
118 int DishProtocol::generateStandardCommand(
119 const PIRKeyBits &pkb,
120 PIRRX51Hardware &rx51device)
124 // In the Dish protocol, the pulse train consists of 6 bits of command
125 // data followed by 10 bits of, uhm, other stuff. I know that at least the
126 // first four bits of these ten can be used for pairing purposes. It looks
127 // like the last five bits can be used as additional command data. For
128 // now, I'm going to split this into 5 "address" and 5 "more command" bits.
130 // The command data is sent MSB-first (I know that at least the first
131 // 6 bits are, I'll represent the last 5 that way as well).
132 // The pairing data is sent LSB-first, god knows why.
133 // - "firstCode" should contain 6-bit value
134 // - "preData" should contain 5 bits of pairing data
135 // - "secondCode" should contain the last 5 bits.
136 duration += pushBits(pkb.firstCode, rx51device);
137 duration += pushReverseBits(postData, rx51device);
138 duration += pushBits(pkb.secondCode, rx51device);
140 // Finally add the "trail":
141 rx51device.addSingle(trailerPulse);
142 duration += trailerPulse;