1 #include "rc6skyprotocol.h"
3 #include "pirrx51hardware.h"
5 #include "pirexception.h"
8 extern bool commandInFlight;
9 extern QMutex commandIFMutex;
11 // These defines might need to be turned into variables, for odd devices.
12 #define HEADER_PULSE 2666
13 #define HEADER_SPACE 888
14 #define TRAILER_BIPHASE 888
16 // This version of Mode 6 RC6 is used in Sky and Sky+ receivers. It seems to
17 // be pretty close to vanilla RC6.
18 // The biphase unit of time is 444 usec.
19 // The RC6 header block starts with the normal 2666 usec pulse, 888 usec space.
20 // The next bit is fixed as a "1", as usual.
21 // The next three bits are 110, marking this as a mode 6 protocol.
22 // The trailer bit has an 888 usec biphase. It is a toggle bit.
23 // Next comes 8 bits of address, 4 bits I don't know about (subdevice?),
24 // and finally 8 bits of command.
25 // A space of (at least) 2666 usec must follow any command.
26 // The carrier frequency is 36 kHZ, duty cycle between 25 and 50 %.
28 RC6SkyProtocol::RC6SkyProtocol(
31 : PIRProtocol(guiObject, index, 2666, false),
36 setCarrierFrequency(36000);
40 void RC6SkyProtocol::startSendingCommand(
41 unsigned int threadableID,
46 // Is this command meant for us?
47 if (threadableID != id) return;
51 KeycodeCollection::const_iterator i = keycodes.find(command);
54 if (i == keycodes.end())
56 std::string s = "Tried to send a non-existent command.\n";
57 throw PIRException(s);
60 PIRRX51Hardware rx51device(carrierFrequency, dutyCycle);
64 while (repeatCount < MAX_REPEAT_COUNT)
66 bufferContainsSpace = false;
67 bufferContainsPulse = false;
68 // First, construct the "Header" segment of the pulse train.
70 // The header involves:
71 // a) a "lead" of 2666 us pulse, 888 us space;
72 // b) a "start bit", value 1 (so 444 us pulse, 444 us space)
73 // c) three control bits, set to "110" (i.e., mode "6")
74 // d) the double-sized "trailer" bit, set based on the keypress count:
76 rx51device.addSingle(HEADER_PULSE); // lead pulse
77 duration += HEADER_PULSE;
78 rx51device.addSingle(HEADER_SPACE); // lead space
79 duration += HEADER_SPACE;
80 rx51device.addSingle(biphaseUnit); // start bit pulse
81 duration += biphaseUnit;
82 rx51device.addSingle(biphaseUnit); // start bit space
83 duration += biphaseUnit;
84 rx51device.addSingle(biphaseUnit); // bit 1 pulse;
85 duration += biphaseUnit;
86 rx51device.addSingle(biphaseUnit); // bit 1 space;
87 duration += biphaseUnit;
88 rx51device.addSingle(biphaseUnit); // bit 2 pulse;
89 duration += biphaseUnit;
90 rx51device.addSingle(2 * biphaseUnit); // bit 2 space + bit 3 space;
91 duration += 2 * biphaseUnit;
93 if (keypressCount % 2)
95 rx51device.addSingle(biphaseUnit); // bit 3 pulse;
96 duration += biphaseUnit;
97 rx51device.addSingle(2 * biphaseUnit); // trailer space
98 duration += 2 * biphaseUnit;
99 buffer = 2 * biphaseUnit; // trailer pulse goes into the buffer
100 bufferContainsPulse = true;
104 rx51device.addSingle(3 * biphaseUnit); // bit 3 + trailer pulses
105 duration += 3 * biphaseUnit;
106 buffer = 2 * biphaseUnit; // trailer space goes into the buffer
107 bufferContainsSpace = true;
110 // Now, we can start the normal buffering process:
112 // push the address data:
113 duration += pushBits(preData, rx51device);
115 // push the command data:
116 duration += pushBits((*i).second.firstCode, rx51device);
118 // Flush out the buffer, if necessary:
121 rx51device.addSingle(buffer);
126 // Actually send out the command:
127 rx51device.sendCommandToDevice();
129 // Sleep for an amount of time. (RC6 demands an addtional 6 unit space
130 // at the end of any command...)
131 sleepUntilRepeat(duration + 6 * biphaseUnit);
133 // Have we been told to stop yet?
134 if (checkRepeatFlag())
136 // Yes, we can now quit repeating:
138 QMutexLocker ciflocker(&commandIFMutex);
139 commandInFlight = false;
144 catch (PIRException e)
146 emit commandFailed(e.getError().c_str());
150 QMutexLocker cifLocker(&commandIFMutex);
151 commandInFlight = false;
155 int RC6SkyProtocol::pushBits(
156 const CommandSequence &bits,
157 PIRRX51Hardware &rx51device)
161 CommandSequence::const_iterator i = bits.begin();
163 while (i != bits.end())
167 duration += pushOne(rx51device);
171 duration += pushZero(rx51device);
181 // This should be part of a general RC6 parent maybe?
182 int RC6SkyProtocol::pushZero(
183 PIRRX51Hardware &rx51device)
185 // Need to add a space, then a pulse.
188 if (bufferContainsSpace)
190 // Merge this space and the previous one, and send to device:
191 rx51device.addSingle(buffer + biphaseUnit);
192 duration += (buffer + biphaseUnit);
194 bufferContainsSpace = false;
198 if (bufferContainsPulse)
200 // Flush out the buffer:
201 rx51device.addSingle(buffer);
204 bufferContainsPulse = false;
207 // push a space onto the device:
208 rx51device.addSingle(biphaseUnit);
209 duration += biphaseUnit;
212 // Put a pulse into the buffer to wait:
213 buffer = biphaseUnit;
214 bufferContainsPulse = true;
220 int RC6SkyProtocol::pushOne(
221 PIRRX51Hardware &rx51device)
223 // Need to add a pulse, then a space.
227 if (bufferContainsPulse)
229 rx51device.addSingle(buffer + biphaseUnit);
230 duration += (buffer + biphaseUnit);
232 bufferContainsPulse = false;
236 if (bufferContainsSpace)
239 rx51device.addSingle(buffer);
242 bufferContainsSpace = false;
244 // Now, add the pulse:
245 rx51device.addSingle(biphaseUnit);
246 duration += biphaseUnit;
249 // Next, push a space onto the buffer:
250 buffer = biphaseUnit;
251 bufferContainsSpace = true;