Moved Mute button, lots new keysets
[pierogi] / protocols / rcaprotocol.cpp
1 #include "rcaprotocol.h"
2
3 #include "pirrx51hardware.h"
4 #include "pirexception.h"
5
6 // Some global communications stuff:
7 #include <QMutex>
8 extern bool commandInFlight;
9 extern QMutex commandIFMutex;
10
11 // I've found no official data on the RCA protocol yet, but from available
12 // notes and guesswork I'm using the following:
13 // A "zero" is encoded with a 500 usec pulse, 500 usec space.
14 // A "one" is encoded with a 500 usec pulse, and 2000 usec space.
15 // The header is a 4000 usec pulse, 4000 usec space.
16 // Commands end with a trailing 500 usec pulse.
17 // When holding down a button, the entire command is repeated.
18 // Commands are repeated every 64000 usec.
19
20 // Each RCA word consists of 4 bits of address data and 8 bits of command data.
21 // The address is sent first, in order of most significant bit to least,
22 // followed by the command, also MSB to LSB.  Then, the same data is sent
23 // again, but with all the bits inverted.  (This is a bit different from
24 // how the NEC protocol does things.)
25
26 RCAProtocol::RCAProtocol(
27   QObject *guiObject,
28   unsigned int index)
29   : SpaceProtocol(
30       guiObject, index,
31       500, 500,
32       500, 2000,
33       4000, 4000,
34       500,
35       64000, true)
36 {
37 }
38
39
40 void RCAProtocol::startSendingCommand(
41   unsigned int threadableID,
42   PIRKeyName command)
43 {
44   // Exceptions here are problematic; I'll try to weed them out by putting the
45   // whole thing in a try/catch block:
46   try
47   {
48     // First, check if we are meant to be the recipient of this command:
49     if (threadableID != id) return;
50
51     // An object that helps keep track of the number of commands:
52 //    PIRCommandCounter commandCounter;
53
54     // Ok, we're going to lock down this method and make sure
55     // only one guy at a time passes this point:
56 //    QMutexLocker commandLocker(&commandMutex);
57
58     clearRepeatFlag();
59
60     KeycodeCollection::const_iterator i = keycodes.find(command);
61
62     // Do we even have this key defined?
63     if (i == keycodes.end())
64     {
65       std::string s = "Tried to send a non-existent command.\n";
66       throw PIRException(s);
67     }
68
69     // construct the device:
70     PIRRX51Hardware rx51device(carrierFrequency, dutyCycle);
71
72     int repeatCount = 0;
73     int commandDuration = 0;
74     while (repeatCount < MAX_REPEAT_COUNT)
75     {
76       commandDuration = generateStandardCommand((*i).second, rx51device);
77
78       // Now, tell the device to send the whole command:
79       rx51device.sendCommandToDevice();
80
81       // sleep until the next repetition of command:
82       sleepUntilRepeat(commandDuration);
83
84       // Check whether we've reached the minimum required number of repetitons:
85       if (repeatCount >= minimumRepetitions)
86       {
87         // Check whether we've been asked to stop:
88         if (checkRepeatFlag())
89         {
90           QMutexLocker cifLocker(&commandIFMutex);
91           commandInFlight = false;
92           return;
93         }
94       }
95
96       ++repeatCount;
97     }
98   }
99   catch (PIRException e)
100   {
101     // inform the gui:
102     emit commandFailed(e.getError().c_str());
103   }
104
105   QMutexLocker cifLocker(&commandIFMutex);
106   commandInFlight = false;
107 }
108
109
110 int RCAProtocol::generateStandardCommand(
111   const PIRKeyBits &pkb,
112   PIRRX51Hardware &rx51device)
113 {
114   int duration = 0;
115
116   // First, the "header" pulse:
117   rx51device.addPair(headerPulse, headerSpace);
118   duration += (headerPulse + headerSpace);
119
120   // Now, set up the address and command bits:
121   duration += pushBits(preData, rx51device);
122   duration += pushBits(pkb.firstCode, rx51device);
123   duration += pushInvertedBits(preData, rx51device);
124   duration += pushInvertedBits(pkb.firstCode, rx51device);
125
126   // Finally add the "trail":
127   rx51device.addSingle(trailerPulse);
128   duration += trailerPulse;
129
130   return duration;
131 }