Improved to "half-way usable" (version 0.5)
[pierogi] / jvcprotocol.cpp
1 #include "jvcprotocol.h"
2
3 #include "pirexception.h"
4 #include <string>
5 //#include <iostream>
6
7 // Some global communications stuff:
8 #include <QMutex>
9 extern bool commandInFlight;
10 extern QMutex commandIFMutex;
11
12 // The JVC protocol should have the following attributes:
13 // A "zero" is encoded with a 526 usec pulse, 52626 usec space.
14 // A "one" is encoded with a 526 usec pulse, and 3*526 (1578) usec space.
15 // The header is a 8400 usec pulse, 4200 usec space.
16 // Commands end with a trailing 526 usec pulse.
17 // Commands are repeated by re-sending entire command without the header.
18 // Repeats are broadcast every 60000 usec.
19 // The carrier frequency is 38 kHz, duty cycle is 1/3.
20
21 JVCProtocol::JVCProtocol(
22   QObject *guiObject,
23   unsigned int index)
24   : PIRProtocol(guiObject, index, 60000, true),
25     zeroPulse(526),
26     zeroSpace(526),
27     onePulse(526),
28     oneSpace(1578),
29     headerPulse(8400),
30     headerSpace(4200),
31     trailerPulse(526)
32 {
33   setCarrierFrequency(38000);
34   setDutyCycle(33);
35 }
36
37
38 void JVCProtocol::startSendingCommand(
39   unsigned int threadableID,
40   PIRKeyName command)
41 {
42   // Exceptions here are problematic; I'll try to weed them out by putting the
43   // whole thing in a try/catch block:
44   try
45   {
46     // First, check if we are meant to be the recipient of this command:
47     if (threadableID != id) return;
48
49     clearRepeatFlag();
50
51     KeycodeCollection::const_iterator i = keycodes.find(command);
52
53     // Do we even have this key defined?
54     if (i == keycodes.end())
55     {
56       std::string s = "Tried to send a non-existent command.\n";
57       throw PIRException(s);
58     }
59
60     // construct the device:
61     PIRRX51Hardware rx51device(carrierFrequency, dutyCycle);
62
63     int repeatCount = 0;
64     int commandDuration = 0;
65     while (repeatCount < MAX_REPEAT_COUNT)
66     {
67       // If we are currently repeating, and have a special "repeat signal",
68       // use that signal.  Otherwise, generate a normal command string.
69       if (repeatCount)
70       {
71         commandDuration = generateHeadlessCommand((*i).second, rx51device);
72       }
73       else
74       {
75         commandDuration = generateStandardCommand((*i).second, rx51device);
76       }
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 // JVC data is sent in reverse order, i.e., the least signficant bit is
111 // sent first.
112 int JVCProtocol::generateStandardCommand(
113   const CommandSequence &bits,
114   PIRRX51Hardware &rx51device)
115 {
116   int duration = 0;
117
118   // First, the "header" pulse:
119   rx51device.addPair(headerPulse, headerSpace);
120   duration += (headerPulse + headerSpace);
121
122   // Now, push the actual data:
123   duration += pushReverseBits(preData, rx51device);
124   duration += pushReverseBits(bits, rx51device);
125
126   // Finally add the "trail":
127   rx51device.addSingle(trailerPulse);
128   duration += trailerPulse;
129
130   return duration;
131 }
132
133
134 int JVCProtocol::generateHeadlessCommand(
135   const CommandSequence &bits,
136   PIRRX51Hardware &rx51device)
137 {
138   int duration = 0;
139
140   // Push the actual data:
141   duration += pushReverseBits(preData, rx51device);
142   duration += pushReverseBits(bits, rx51device);
143
144   // Finally add the "trail":
145   rx51device.addSingle(trailerPulse);
146   duration += trailerPulse;
147
148   return duration;
149 }
150
151
152 int JVCProtocol::pushReverseBits(
153   const CommandSequence &bits,
154   PIRRX51Hardware &rx51device)
155 {
156   int duration = 0;
157   CommandSequence::const_reverse_iterator i = bits.rbegin();
158   while (i != bits.rend())
159   {
160     if (*i)
161     {
162       // Send the pulse for "One":
163       rx51device.addPair(onePulse, oneSpace);
164       duration += (onePulse + oneSpace);
165     }
166     else
167     {
168       // Send the pulse for "Zero":
169       rx51device.addPair(zeroPulse, zeroSpace);
170       duration += (zeroPulse + zeroSpace);
171     }
172     ++i;
173   }
174
175   return duration;
176 }
177