Keyset update
[pierogi] / protocols / pioneerprotocol.cpp
1 #include "pioneerprotocol.h"
2
3 #include "pirrx51hardware.h"
4
5 #include "pirexception.h"
6 #include <string>
7 //#include <iostream>
8
9 // Some global communications stuff:
10 #include <QMutex>
11 extern bool commandInFlight;
12 extern QMutex commandIFMutex;
13
14 // Pioneer's protocol seems almost the same as standard NEC protocol, but
15 // a few details are slightly different.  (Can't seem to find exact details.)
16 // A "zero" is encoded with a 530 usec pulse, 530 usec space.
17 // A "one" is encoded with a 530 usec pulse, and 3*530 (1590) usec space.
18 // The header is a 8500 usec pulse, 4250 usec space.
19 // Commands end with a trailing 530 usec pulse.
20 // Commands are repeated by re-sending the entire pulse train.
21 // Each command is separated by 25000 usec.
22 // The carrier frequency is probably 40 kHz, duty cycle probably 50%.
23
24 PioneerProtocol::PioneerProtocol(
25   QObject *guiObject,
26   unsigned int index)
27   : SpaceProtocol(
28       guiObject, index,
29       530, 530,
30       530, 1590,
31       8500, 4250,
32       530,
33       25000, false)
34 {
35   setCarrierFrequency(40000);
36   setDutyCycle(50);
37 }
38
39
40 void PioneerProtocol::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     clearRepeatFlag();
52
53     KeycodeCollection::const_iterator i = keycodes.find(command);
54
55     // Do we even have this key defined?
56     if (i == keycodes.end())
57     {
58       std::string s = "Tried to send a non-existent command.\n";
59       throw PIRException(s);
60     }
61
62     // construct the device:
63     PIRRX51Hardware rx51device(carrierFrequency, dutyCycle);
64
65     int repeatCount = 0;
66     int commandDuration = 0;
67     while (repeatCount < MAX_REPEAT_COUNT)
68     {
69       // If we are on an odd repetition, and we have a secondary keycode,
70       // we'll generate the secondary command for this key.  Otherwise,
71       // we always generate a standard command.
72       if ((repeatCount % 2) && (!(i->second.thirdCode.empty())))
73       {
74         commandDuration = generateSecondaryCommand(i->second, rx51device);
75       }
76       else
77       {
78         commandDuration = generateStandardCommand(i->second, rx51device);
79       }
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       if (repeatCount >= 3)
90       {
91         // Check whether we've been asked to stop:
92         if (checkRepeatFlag())
93         {
94           QMutexLocker cifLocker(&commandIFMutex);
95           commandInFlight = false;
96           return;
97         }
98       }
99
100       ++repeatCount;
101     }
102   }
103   catch (PIRException e)
104   {
105     // inform the gui:
106     emit commandFailed(e.getError().c_str());
107   }
108
109   QMutexLocker cifLocker(&commandIFMutex);
110   commandInFlight = false;
111 }
112
113
114 int PioneerProtocol::generateStandardCommand(
115   const PIRKeyBits &pkb,
116   PIRRX51Hardware &rx51device)
117 {
118   int duration = 0;
119
120   // First, the "header" pulse:
121   rx51device.addPair(headerPulse, headerSpace);
122   duration += (headerPulse + headerSpace);
123
124   // Now, the data, following standard NEC rules.  (Note that we are not
125   // using the "preData" value here, most Pioneer devices require more than
126   // one address value.  Therefore, I'm requiring all keys to explicitly
127   // load the address value into the "firstCode" member.)
128   duration += pushReverseBits(pkb.firstCode, rx51device);
129   duration += pushInvertedReverseBits(pkb.firstCode, rx51device);
130   duration += pushReverseBits(pkb.secondCode, rx51device);
131   duration += pushInvertedReverseBits(pkb.secondCode, rx51device);
132
133   // Finally add the "trail":
134   rx51device.addSingle(trailerPulse);
135   duration += trailerPulse;
136
137   return duration;
138 }
139
140
141 int PioneerProtocol::generateSecondaryCommand(
142   const PIRKeyBits &pkb,
143   PIRRX51Hardware &rx51device)
144 {
145   int duration = 0;
146
147   // First, the "header" pulse:
148   rx51device.addPair(headerPulse, headerSpace);
149   duration += (headerPulse + headerSpace);
150
151   // Now, the data, following standard NEC rules.  (The secondary command
152   // uses the third and fourth key codes.)
153   duration += pushReverseBits(pkb.thirdCode, rx51device);
154   duration += pushInvertedReverseBits(pkb.thirdCode, rx51device);
155   duration += pushReverseBits(pkb.fourthCode, rx51device);
156   duration += pushInvertedReverseBits(pkb.fourthCode, rx51device);
157
158   // Finally add the "trail":
159   rx51device.addSingle(trailerPulse);
160   duration += trailerPulse;
161
162   return duration;
163 }