Advanced Settings Panel
[pierogi] / protocols / tdcprotocol.cpp
1 #include "tdcprotocol.h"
2
3 #include "pirrx51hardware.h"
4
5 #include "pirexception.h"
6
7 #include <QMutex>
8 extern bool commandInFlight;
9 extern QMutex commandIFMutex;
10
11
12 // There are apparently two forms of TDC protocol; I'm just focussing on one
13 // for now.  As with the Philips protocols, this one is "shift encoded".
14 // The unit biphase pulse length is 315 usec; each command contains 18 bits,
15 // and is followed by an 89000 usec space.  The entire pulse train is
16 // re-sent when repeating.  The carrier frequency is 38 kHz (the Pierogi
17 // default value).
18
19 // I'm going to count both the "device" and "subdevice" bits as pre-data.
20 // (Both are 5 bits in length.)  This may need to be changed...
21
22 TDCProtocol::TDCProtocol(
23   QObject *guiObject,
24   unsigned int index,
25   unsigned int deviceBits,
26   unsigned int subdeviceBits)
27   : PIRProtocol(guiObject, index, 89000, false),
28     biphaseUnit(315),
29     buffer(0)
30 {
31   // Bit of a hack to get the device and subdevice data in:
32   setPreData(deviceBits, 5);
33   setPostData(subdeviceBits, 5);
34 }
35
36
37 void TDCProtocol::startSendingCommand(
38   unsigned int threadableID,
39   PIRKeyName command)
40 {
41   // Catch any exceptions here before they go up any further:
42   try
43   {
44     // Check that this command is meant for us:
45     if (threadableID != id) return;
46
47     clearRepeatFlag();
48
49     KeycodeCollection::const_iterator i = keycodes.find(command);
50
51     // Sanity check:
52     if (i == keycodes.end())
53     {
54       QMutexLocker cifLocker(&commandIFMutex);
55       commandInFlight = false;
56       return;
57 //      std::string s = "Tried to send a non-existent command.\n";
58 //      throw PIRException(s);
59     }
60
61     // Construct the object that communicates with the device driver:
62     PIRRX51Hardware rx51device(carrierFrequency, dutyCycle);
63
64     int repeatCount = 0;
65     int commandDuration = 0;
66     while (repeatCount < MAX_REPEAT_COUNT)
67     {
68       // Construct the actual command string.
69       // The string always starts with a constant "1" bit:
70       commandDuration += pushBit(true, rx51device);
71
72       // Next, the device bits:
73       commandDuration += pushBits(preData, rx51device);
74
75       // Then, the subdevice bits:
76       commandDuration += pushBits(postData, rx51device);
77
78       // Finally, the command bits:
79       commandDuration += pushBits((*i).second.firstCode, rx51device);
80
81       // Clear out the buffer, if needed:
82       if (buffer)
83       {
84         rx51device.addSingle(buffer);
85         commandDuration += buffer;
86
87         buffer = 0;
88         bufferContainsSpace = false;
89         bufferContainsPulse = false;
90       }
91
92       // Send the command:
93       rx51device.sendCommandToDevice();
94
95       // Sleep for the required amount of time.
96       sleepUntilRepeat(commandDuration);
97
98       // Check whether we've been told to stop:
99       if (checkRepeatFlag())
100       {
101         // We shall stop:
102         break;
103 /*
104         QMutexLocker cifLocker(&commandIFMutex);
105         commandInFlight = false;
106         return;
107 */
108       }
109
110       ++repeatCount;
111     }
112
113     QMutexLocker cifLocker(&commandIFMutex);
114     commandInFlight = false;
115   }
116   catch (PIRException e)
117   {
118     emit commandFailed(e.getError().c_str());
119   }
120 }
121
122
123 int TDCProtocol::pushBits(
124   const CommandSequence &bits,
125   PIRRX51Hardware &rx51device)
126 {
127   int duration = 0;
128
129   CommandSequence::const_iterator i = bits.begin();
130
131   while (i != bits.end())
132   {
133     duration += pushBit(*i, rx51device);
134     ++i;
135   }
136
137   return duration;
138 }
139
140
141 int TDCProtocol::pushBit(
142   bool bitValue,
143   PIRRX51Hardware &device)
144 {
145   unsigned int duration = 0;
146   // TDC encodes a "0" by using a space followed by a pulse,
147   // and a "1" by using a pulse followed by a space.
148
149   if (bitValue)
150   {
151     // We've got a "1".  First add a pulse, then a space.
152     if (bufferContainsPulse)
153     {
154       // Merge our pulse with the previous one, and send them to the device:
155       device.addSingle(buffer + biphaseUnit);
156       duration += (buffer + biphaseUnit);
157       buffer = 0;
158       bufferContainsPulse = false;
159     }
160     else
161     {
162       if (bufferContainsSpace)
163       {
164         // Flush out the buffer:
165         device.addSingle(buffer);
166         duration += buffer;
167         buffer = 0;
168         bufferContainsSpace = false;
169       }
170
171       // Add a pulse:
172       device.addSingle(biphaseUnit);
173       duration += biphaseUnit;
174     }
175
176     // Put a space into the buffer to wait:
177     buffer = biphaseUnit;
178     bufferContainsSpace = true;
179   }
180   else
181   {
182     // We've got a "0".  First add a space, then a pulse.
183     if (bufferContainsSpace)
184     {
185       // Merge our space with the previous space, and send them to
186       // the device.
187       device.addSingle(buffer + biphaseUnit);
188       duration += (buffer + biphaseUnit);
189       buffer = 0;
190       bufferContainsSpace = false;
191     }
192     else
193     {
194       if (bufferContainsPulse)
195       {
196         // Flush the buffer:
197         device.addSingle(buffer);
198         duration += buffer;
199         buffer = 0;
200         bufferContainsPulse = false;
201       }
202       // Add a space:
203       device.addSingle(biphaseUnit);
204       duration += biphaseUnit;
205     }
206
207     // Put a pulse into the buffer to wait.
208     buffer = biphaseUnit;
209     bufferContainsPulse = true;
210   }
211
212   return duration;
213 }