1 #include "irobotprotocol.h"
3 #include "pirrx51hardware.h"
5 #include "pirexception.h"
7 // Some global communications stuff:
9 extern bool commandInFlight;
10 extern QMutex commandIFMutex;
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
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.
22 IRobotProtocol::IRobotProtocol(
36 void IRobotProtocol::startSendingCommand(
37 unsigned int threadableID,
40 // Exceptions here are problematic; I'll try to weed them out by putting the
41 // whole thing in a try/catch block:
44 // First, check if we are meant to be the recipient of this command:
45 if (threadableID != id) return;
49 KeycodeCollection::const_iterator i = keycodes.find(command);
51 // Do we even have this key defined?
52 if (i == keycodes.end())
54 QMutexLocker cifLocker(&commandIFMutex);
55 commandInFlight = false;
57 // std::string s = "Tried to send a non-existent command.\n";
58 // throw PIRException(s);
61 // construct the device:
62 PIRRX51Hardware rx51device(carrierFrequency, dutyCycle);
65 int commandDuration = 0;
66 while (repeatCount < MAX_REPEAT_COUNT)
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
73 commandDuration = generateCommand((*i).second, rx51device);
75 // Tell the device to send the command:
76 rx51device.sendCommandToDevice();
79 // sleep until the next repetition of command:
80 sleepUntilRepeat(commandDuration);
82 // Check whether we've reached the minimum required number of repetitons:
83 if (repeatCount >= minimumRepetitions)
85 // Check whether we've been asked to stop:
86 if (checkRepeatFlag())
90 QMutexLocker cifLocker(&commandIFMutex);
91 commandInFlight = false;
100 QMutexLocker cifLocker(&commandIFMutex);
101 commandInFlight = false;
103 catch (PIRException e)
106 emit commandFailed(e.getError().c_str());
111 int IRobotProtocol::generateCommand(
112 const PIRKeyBits &pkb,
113 PIRRX51Hardware &rx51device)
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:
124 CommandSequence::const_iterator i = pkb.firstCode.begin();
125 while ((index < 7) && (i != pkb.firstCode.end()))
129 rx51device.addPair(onePulse, oneSpace);
130 duration += onePulse + oneSpace;
134 rx51device.addPair(zeroPulse, zeroSpace);
135 duration += zeroPulse + zeroSpace;
142 // Eighth bit with extra space at the end:
143 if (i != pkb.firstCode.end())
147 rx51device.addPair(onePulse, oneSpace + 16000);
148 duration += onePulse + oneSpace + 16000;
152 rx51device.addPair(zeroPulse, zeroSpace + 16000);
153 duration += zeroPulse + zeroSpace + 16000;
157 // The following seven bits:
159 i = pkb.firstCode.begin();
160 while ((index < 7) && (i != pkb.firstCode.end()))
164 rx51device.addPair(onePulse, oneSpace);
165 duration += onePulse + oneSpace;
169 rx51device.addPair(zeroPulse, zeroSpace);
170 duration += zeroPulse + zeroSpace;
177 // The last half-bit:
178 if (i != pkb.firstCode.end())
182 rx51device.addSingle(onePulse);
183 duration += onePulse;
187 rx51device.addSingle(zeroPulse);
188 duration += zeroPulse;