Adding Macros!
[pierogi] / protocols / giprotocol.cpp
1 #include "giprotocol.h"
2
3 #include "pirrx51hardware.h"
4
5 #include "pirexception.h"
6
7 // Some global communications stuff:
8 #include <QMutex>
9 extern bool commandInFlight;
10 extern QMutex commandIFMutex;
11
12 // This G.I./Motorola protocol appears to have the following specifications:
13 // A "zero" is encoded with a 500 usec pulse, 2250 usec space.
14 // A "one" is encoded with a 500 usec pulse, and 4500 usec space.
15 // The header is a 9000 usec pulse, 4500 usec space.
16 // Commands end with a trailing 500 usec pulse.
17 // A repeat block is a 9000 usec pulse, 2250 usec space, then a trailing pulse.
18 // Each command runs for 100000 usec before another can be executed.
19 // The carrier frequency is 38 kHz.
20
21 GIProtocol::GIProtocol(
22   QObject *guiObject,
23   unsigned int index)
24   : SpaceProtocol(
25       guiObject, index,
26       500, 2250,
27       500, 4500,
28       9000, 4500,
29       500,
30       100000, true),
31     repeatPulse(9000),
32     repeatSpace(2250)
33 {
34 }
35
36
37 void GIProtocol::startSendingCommand(
38   unsigned int threadableID,
39   PIRKeyName command)
40 {
41   // Exceptions here are problematic; I'll try to weed them out by putting the
42   // whole thing in a try/catch block:
43   try
44   {
45     // First, check if we are meant to be the recipient of this command:
46     if (threadableID != id) return;
47
48     clearRepeatFlag();
49
50     KeycodeCollection::const_iterator i = keycodes.find(command);
51
52     // Do we even have this key defined?
53     if (i == keycodes.end())
54     {
55       QMutexLocker cifLocker(&commandIFMutex);
56       commandInFlight = false;
57       return;
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 currently repeating, send a repeat block.
70       if (repeatCount)
71       {
72         commandDuration = generateRepeatCommand(rx51device);
73       }
74       else
75       {
76         commandDuration = generateStandardCommand((*i).second, rx51device);
77       }
78
79       // Now, tell the device to send the whole command:
80       rx51device.sendCommandToDevice();
81
82       // sleep until the next repetition of command:
83       sleepUntilRepeat(commandDuration);
84
85       // Check whether we've reached the minimum required number of repetitons:
86       if (repeatCount >= minimumRepetitions)
87       {
88         // Check whether we've been asked to stop:
89         if (checkRepeatFlag())
90         {
91           break;
92 /*
93           QMutexLocker cifLocker(&commandIFMutex);
94           commandInFlight = false;
95           return;
96 */
97         }
98       }
99
100       ++repeatCount;
101     }
102
103     QMutexLocker cifLocker(&commandIFMutex);
104     commandInFlight = false;
105   }
106   catch (PIRException e)
107   {
108     // inform the gui:
109     emit commandFailed(e.getError().c_str());
110   }
111 }
112
113
114 int GIProtocol::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   // The GI protocol consists of a 4-bit device code and an 8-bit command.
125   // These are sent in reverse order.  Finally, a checksum is added at the
126   // end.  I am lacking enough information to calculate the checksum right
127   // now, so I'm going to dump all 16 bits into the "firstCode" in MSB
128   // order, and reverse them here:
129
130   duration += pushReverseBits(pkb.firstCode, rx51device);
131
132   // Finally add the "trail":
133   rx51device.addSingle(trailerPulse);
134   duration += trailerPulse;
135
136   return duration;
137 }
138
139
140 int GIProtocol::generateRepeatCommand(
141   PIRRX51Hardware &rx51device)
142 {
143   int duration = 0;
144
145   // Add the repeat pulse:
146   rx51device.addPair(repeatPulse, repeatSpace);
147   duration += (repeatPulse + repeatSpace);
148
149   // Add the trailer:
150   rx51device.addSingle(trailerPulse);
151   duration += trailerPulse;
152
153   return duration;
154 }
155