Update to UI
[pierogi] / protocols / irobotprotocol.cpp
diff --git a/protocols/irobotprotocol.cpp b/protocols/irobotprotocol.cpp
new file mode 100644 (file)
index 0000000..c2ac7ab
--- /dev/null
@@ -0,0 +1,187 @@
+#include "irobotprotocol.h"
+
+#include "pirrx51hardware.h"
+
+#include "pirexception.h"
+
+// Some global communications stuff:
+#include <QMutex>
+extern bool commandInFlight;
+extern QMutex commandIFMutex;
+
+// The iRobot (Roomba) protocol seems to be extremely simple.
+// A "zero" is encoded with a 1000 usec pulse, 3000 usec space.
+// A "one" is encoded with a 3000 usec pulse, 1000 usec space.
+// So, it looks a little like a shift encoded protocol, even though it
+// is space-encoded.
+// There is no header and no trailer.
+// Each command may run for 100000 usec (sources differ), but it looks like
+// commands are not repeated at all...
+// The carrier frequency is the usual 38 kHz.
+
+IRobotProtocol::IRobotProtocol(
+  QObject *guiObject,
+  unsigned int index)
+  : SpaceProtocol(
+      guiObject, index,
+      1000, 3000,
+      3000, 1000,
+      0, 0,
+      0,
+      100000, true)
+{
+}
+
+
+void IRobotProtocol::startSendingCommand(
+  unsigned int threadableID,
+  PIRKeyName command)
+{
+  // Exceptions here are problematic; I'll try to weed them out by putting the
+  // whole thing in a try/catch block:
+  try
+  {
+    // First, check if we are meant to be the recipient of this command:
+    if (threadableID != id) return;
+
+    clearRepeatFlag();
+
+    KeycodeCollection::const_iterator i = keycodes.find(command);
+
+    // Do we even have this key defined?
+    if (i == keycodes.end())
+    {
+      std::string s = "Tried to send a non-existent command.\n";
+      throw PIRException(s);
+    }
+
+    // construct the device:
+    PIRRX51Hardware rx51device(carrierFrequency, dutyCycle);
+
+    int repeatCount = 0;
+    int commandDuration = 0;
+    while (repeatCount < MAX_REPEAT_COUNT)
+    {
+      // It looks like we only generate the command once, and remain
+      // silent for the rest of the time the button is held down.  So, no
+      // repeats.
+      if (!repeatCount)
+      {
+        commandDuration = generateCommand((*i).second, rx51device);
+
+        // Tell the device to send the command:
+        rx51device.sendCommandToDevice();
+      }
+
+      // sleep until the next repetition of command:
+      sleepUntilRepeat(commandDuration);
+
+      // Check whether we've reached the minimum required number of repetitons:
+      if (repeatCount >= minimumRepetitions)
+      {
+        // Check whether we've been asked to stop:
+        if (checkRepeatFlag())
+        {
+          QMutexLocker cifLocker(&commandIFMutex);
+          commandInFlight = false;
+          return;
+        }
+      }
+
+      ++repeatCount;
+    }
+  }
+  catch (PIRException e)
+  {
+    // inform the gui:
+    emit commandFailed(e.getError().c_str());
+  }
+
+  QMutexLocker cifLocker(&commandIFMutex);
+  commandInFlight = false;
+}
+
+
+int IRobotProtocol::generateCommand(
+  const PIRKeyBits &pkb,
+  PIRRX51Hardware &rx51device)
+{
+  int duration = 0;
+
+  // The protocol seems to involve 8 command bits, a 16000 usec pause, and
+  // the same 8 bits repeated again.  So, we need to tack a 16000 usec
+  // space on at the end of the first 8 bits, and just drop the last space
+  // definition at the end of the second 8 bits:
+
+  // The first 7 bits:
+  int index = 0;
+  CommandSequence::const_iterator i = pkb.firstCode.begin();
+  while ((index < 7) && (i != pkb.firstCode.end()))
+  {
+    if (*i)
+    {
+      rx51device.addPair(onePulse, oneSpace);
+      duration += onePulse + oneSpace;
+    }
+    else
+    {
+      rx51device.addPair(zeroPulse, zeroSpace);
+      duration += zeroPulse + zeroSpace;
+    }
+
+    ++index;
+    ++i;
+  }
+
+  // Eighth bit with extra space at the end:
+  if (i != pkb.firstCode.end())
+  {
+    if (*i)
+    {
+      rx51device.addPair(onePulse, oneSpace + 16000);
+      duration += onePulse + oneSpace + 16000;
+    }
+    else
+    {
+      rx51device.addPair(zeroPulse, zeroSpace + 16000);
+      duration += zeroPulse + zeroSpace + 16000;
+    }
+  }
+
+  // The following seven bits:
+  index = 0;
+  i = pkb.firstCode.begin();
+  while ((index < 7) && (i != pkb.firstCode.end()))
+  {
+    if (*i)
+    {
+      rx51device.addPair(onePulse, oneSpace);
+      duration += onePulse + oneSpace;
+    }
+    else
+    {
+      rx51device.addPair(zeroPulse, zeroSpace);
+      duration += zeroPulse + zeroSpace;
+    }
+
+    ++index;
+    ++i;
+  }
+
+  // The last half-bit:
+  if (i != pkb.firstCode.end())
+  {
+    if (*i)
+    {
+      rx51device.addSingle(onePulse);
+      duration += onePulse;
+    }
+    else
+    {
+      rx51device.addSingle(zeroPulse);
+      duration += zeroPulse;
+    }
+  }
+
+  return duration;
+}