Advanced Settings Panel
[pierogi] / protocols / irobotprotocol.cpp
1 #include "irobotprotocol.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 // The iRobot (Roomba) protocol seems to be extremely simple.
13 // A "zero" is encoded with a 1000 usec pulse, 3000 usec space.
14 // A "one" is encoded with a 3000 usec pulse, 1000 usec space.
15 // So, it looks a little like a shift encoded protocol, even though it
16 // is space-encoded.
17 // There is no header and no trailer.
18 // Each command may run for 100000 usec (sources differ), but it looks like
19 // commands are not repeated at all...
20 // The carrier frequency is the usual 38 kHz.
21
22 IRobotProtocol::IRobotProtocol(
23   QObject *guiObject,
24   unsigned int index)
25   : SpaceProtocol(
26       guiObject, index,
27       1000, 3000,
28       3000, 1000,
29       0, 0,
30       0,
31       100000, true)
32 {
33 }
34
35
36 void IRobotProtocol::startSendingCommand(
37   unsigned int threadableID,
38   PIRKeyName command)
39 {
40   // Exceptions here are problematic; I'll try to weed them out by putting the
41   // whole thing in a try/catch block:
42   try
43   {
44     // First, check if we are meant to be the recipient of this command:
45     if (threadableID != id) return;
46
47     clearRepeatFlag();
48
49     KeycodeCollection::const_iterator i = keycodes.find(command);
50
51     // Do we even have this key defined?
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 device:
62     PIRRX51Hardware rx51device(carrierFrequency, dutyCycle);
63
64     int repeatCount = 0;
65     int commandDuration = 0;
66     while (repeatCount < MAX_REPEAT_COUNT)
67     {
68       // It looks like we only generate the command once, and remain
69       // silent for the rest of the time the button is held down.  So, no
70       // repeats.
71       if (!repeatCount)
72       {
73         commandDuration = generateCommand((*i).second, rx51device);
74
75         // Tell the device to send the command:
76         rx51device.sendCommandToDevice();
77       }
78
79       // sleep until the next repetition of command:
80       sleepUntilRepeat(commandDuration);
81
82       // Check whether we've reached the minimum required number of repetitons:
83       if (repeatCount >= minimumRepetitions)
84       {
85         // Check whether we've been asked to stop:
86         if (checkRepeatFlag())
87         {
88           break;
89 /*
90           QMutexLocker cifLocker(&commandIFMutex);
91           commandInFlight = false;
92           return;
93 */
94         }
95       }
96
97       ++repeatCount;
98     }
99
100     QMutexLocker cifLocker(&commandIFMutex);
101     commandInFlight = false;
102   }
103   catch (PIRException e)
104   {
105     // inform the gui:
106     emit commandFailed(e.getError().c_str());
107   }
108 }
109
110
111 int IRobotProtocol::generateCommand(
112   const PIRKeyBits &pkb,
113   PIRRX51Hardware &rx51device)
114 {
115   int duration = 0;
116
117   // The protocol seems to involve 8 command bits, a 16000 usec pause, and
118   // the same 8 bits repeated again.  So, we need to tack a 16000 usec
119   // space on at the end of the first 8 bits, and just drop the last space
120   // definition at the end of the second 8 bits:
121
122   // The first 7 bits:
123   int index = 0;
124   CommandSequence::const_iterator i = pkb.firstCode.begin();
125   while ((index < 7) && (i != pkb.firstCode.end()))
126   {
127     if (*i)
128     {
129       rx51device.addPair(onePulse, oneSpace);
130       duration += onePulse + oneSpace;
131     }
132     else
133     {
134       rx51device.addPair(zeroPulse, zeroSpace);
135       duration += zeroPulse + zeroSpace;
136     }
137
138     ++index;
139     ++i;
140   }
141
142   // Eighth bit with extra space at the end:
143   if (i != pkb.firstCode.end())
144   {
145     if (*i)
146     {
147       rx51device.addPair(onePulse, oneSpace + 16000);
148       duration += onePulse + oneSpace + 16000;
149     }
150     else
151     {
152       rx51device.addPair(zeroPulse, zeroSpace + 16000);
153       duration += zeroPulse + zeroSpace + 16000;
154     }
155   }
156
157   // The following seven bits:
158   index = 0;
159   i = pkb.firstCode.begin();
160   while ((index < 7) && (i != pkb.firstCode.end()))
161   {
162     if (*i)
163     {
164       rx51device.addPair(onePulse, oneSpace);
165       duration += onePulse + oneSpace;
166     }
167     else
168     {
169       rx51device.addPair(zeroPulse, zeroSpace);
170       duration += zeroPulse + zeroSpace;
171     }
172
173     ++index;
174     ++i;
175   }
176
177   // The last half-bit:
178   if (i != pkb.firstCode.end())
179   {
180     if (*i)
181     {
182       rx51device.addSingle(onePulse);
183       duration += onePulse;
184     }
185     else
186     {
187       rx51device.addSingle(zeroPulse);
188       duration += zeroPulse;
189     }
190   }
191
192   return duration;
193 }