d8c9e8d8291eebfbdc128f2ac317bdd37d183e54
[pierogi] / protocols / aiwaprotocol.cpp
1 #include "aiwaprotocol.h"
2
3 #include "pirrx51hardware.h"
4
5 #include "pirexception.h"
6 #include <string>
7
8 // Some global communications stuff:
9 #include <QMutex>
10 extern bool commandInFlight;
11 extern QMutex commandIFMutex;
12
13 // My information on the Aiwa protocol is that it has the following attributes:
14 // A "zero" is encoded with a 550 usec pulse, 550 usec space.
15 // A "one" is encoded with a 550 usec pulse, 1650 (3 * 550) usec space.
16 // The header has a 8800 usec pulse, 4400 usec space.
17 // There is a 550 usec trailing pulse.
18 // Repeat blocks are 8800 usec pulse, 4400 usec space, then trailing pulse.
19 // Each command lasts for 108000 usec.
20 // Carrier frequency is 38 kHz; I'm using 50% for the duty cycle, for now.
21
22 AiwaProtocol::AiwaProtocol(
23   QObject *guiObject,
24   unsigned int index)
25   : SpaceProtocol(
26       guiObject, index,
27       550, 550,
28       550, 1650,
29       8800, 4400,
30       550,
31       108000, true),
32     repeatPulse(8800),
33     repeatSpace(2250)
34 {
35   setCarrierFrequency(38000);
36   setDutyCycle(50);
37 }
38
39
40 void AiwaProtocol::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 currently repeating, send the 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           QMutexLocker cifLocker(&commandIFMutex);
92           commandInFlight = false;
93           return;
94         }
95       }
96
97       ++repeatCount;
98     }
99   }
100   catch (PIRException e)
101   {
102     // inform the gui:
103     emit commandFailed(e.getError().c_str());
104   }
105
106   QMutexLocker cifLocker(&commandIFMutex);
107   commandInFlight = false;
108 }
109
110
111 int AiwaProtocol::generateStandardCommand(
112   const PIRKeyBits &pkb,
113   PIRRX51Hardware &rx51device)
114 {
115   int duration = 0;
116
117   // First, the "header" pulse:
118   rx51device.addPair(headerPulse, headerSpace);
119   duration += (headerPulse + headerSpace);
120
121   // From the information I've got, the "address" portion of the Aiwa protocol
122   // might be split into 8-bit device and 5-bit subdevice subsections, but
123   // for now, I'm just lumping both into a single 13-bit address value.
124   // The command is an 8-bit value.
125   // As with NEC, the address is sent LSB first, then inverted LSB first,
126   // then the command is sent LSB first, then inverted LSB first.
127   duration += pushReverseBits(preData, rx51device);
128   duration += pushInvertedReverseBits(preData, rx51device);
129   duration += pushReverseBits(pkb.firstCode, rx51device);
130   duration += pushInvertedReverseBits(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 AiwaProtocol::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   // Finally add the trailer:
150   rx51device.addSingle(trailerPulse);
151   duration += trailerPulse;
152
153   return duration;
154 }