Advanced Settings Panel
[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, 1000 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, 1000,
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       QMutexLocker cifLocker(&commandIFMutex);
66       commandInFlight = false;
67       return;
68 //      std::string s = "Tried to send a non-existent command.\n";
69 //      throw PIRException(s);
70     }
71
72     // construct the device:
73     PIRRX51Hardware rx51device(carrierFrequency, dutyCycle);
74
75     int repeatCount = 0;
76     int commandDuration = 0;
77     while (repeatCount < MAX_REPEAT_COUNT)
78     {
79       commandDuration = generateStandardCommand((*i).second, rx51device);
80
81       // Now, tell the device to send the whole command:
82       rx51device.sendCommandToDevice();
83
84       // sleep until the next repetition of command:
85       sleepUntilRepeat(commandDuration);
86
87       // Check whether we've reached the minimum required number of repetitons:
88       if (repeatCount >= minimumRepetitions)
89       {
90         // Check whether we've been asked to stop:
91         if (checkRepeatFlag())
92         {
93           break;
94 /*
95           QMutexLocker cifLocker(&commandIFMutex);
96           commandInFlight = false;
97           return;
98 */
99         }
100       }
101
102       ++repeatCount;
103     }
104
105     QMutexLocker cifLocker(&commandIFMutex);
106     commandInFlight = false;
107   }
108   catch (PIRException e)
109   {
110     // inform the gui:
111     emit commandFailed(e.getError().c_str());
112   }
113 }
114
115
116 int RCAProtocol::generateStandardCommand(
117   const PIRKeyBits &pkb,
118   PIRRX51Hardware &rx51device)
119 {
120   int duration = 0;
121
122   // First, the "header" pulse:
123   rx51device.addPair(headerPulse, headerSpace);
124   duration += (headerPulse + headerSpace);
125
126   // Now, set up the address and command bits:
127   duration += pushBits(preData, rx51device);
128   duration += pushBits(pkb.firstCode, rx51device);
129   duration += pushInvertedBits(preData, rx51device);
130   duration += pushInvertedBits(pkb.firstCode, rx51device);
131
132   // Finally add the "trail":
133   rx51device.addSingle(trailerPulse);
134   duration += trailerPulse;
135
136   return duration;
137 }