Search for Power Button Panel
[pierogi] / protocols / tdcprotocol.cpp
diff --git a/protocols/tdcprotocol.cpp b/protocols/tdcprotocol.cpp
new file mode 100644 (file)
index 0000000..1707137
--- /dev/null
@@ -0,0 +1,213 @@
+#include "tdcprotocol.h"
+
+#include "pirrx51hardware.h"
+
+#include "pirexception.h"
+
+#include <QMutex>
+extern bool commandInFlight;
+extern QMutex commandIFMutex;
+
+
+// There are apparently two forms of TDC protocol; I'm just focussing on one
+// for now.  As with the Philips protocols, this one is "shift encoded".
+// The unit biphase pulse length is 315 usec; each command contains 18 bits,
+// and is followed by an 89000 usec space.  The entire pulse train is
+// re-sent when repeating.  The carrier frequency is 38 kHz (the Pierogi
+// default value).
+
+// I'm going to count both the "device" and "subdevice" bits as pre-data.
+// (Both are 5 bits in length.)  This may need to be changed...
+
+TDCProtocol::TDCProtocol(
+  QObject *guiObject,
+  unsigned int index,
+  unsigned int deviceBits,
+  unsigned int subdeviceBits)
+  : PIRProtocol(guiObject, index, 89000, false),
+    biphaseUnit(315),
+    buffer(0)
+{
+  // Bit of a hack to get the device and subdevice data in:
+  setPreData(deviceBits, 5);
+  setPostData(subdeviceBits, 5);
+}
+
+
+void TDCProtocol::startSendingCommand(
+  unsigned int threadableID,
+  PIRKeyName command)
+{
+  // Catch any exceptions here before they go up any further:
+  try
+  {
+    // Check that this command is meant for us:
+    if (threadableID != id) return;
+
+    clearRepeatFlag();
+
+    KeycodeCollection::const_iterator i = keycodes.find(command);
+
+    // Sanity check:
+    if (i == keycodes.end())
+    {
+      QMutexLocker cifLocker(&commandIFMutex);
+      commandInFlight = false;
+      return;
+//      std::string s = "Tried to send a non-existent command.\n";
+//      throw PIRException(s);
+    }
+
+    // Construct the object that communicates with the device driver:
+    PIRRX51Hardware rx51device(carrierFrequency, dutyCycle);
+
+    int repeatCount = 0;
+    int commandDuration = 0;
+    while (repeatCount < MAX_REPEAT_COUNT)
+    {
+      // Construct the actual command string.
+      // The string always starts with a constant "1" bit:
+      commandDuration += pushBit(true, rx51device);
+
+      // Next, the device bits:
+      commandDuration += pushBits(preData, rx51device);
+
+      // Then, the subdevice bits:
+      commandDuration += pushBits(postData, rx51device);
+
+      // Finally, the command bits:
+      commandDuration += pushBits((*i).second.firstCode, rx51device);
+
+      // Clear out the buffer, if needed:
+      if (buffer)
+      {
+        rx51device.addSingle(buffer);
+        commandDuration += buffer;
+
+        buffer = 0;
+        bufferContainsSpace = false;
+        bufferContainsPulse = false;
+      }
+
+      // Send the command:
+      rx51device.sendCommandToDevice();
+
+      // Sleep for the required amount of time.
+      sleepUntilRepeat(commandDuration);
+
+      // Check whether we've been told to stop:
+      if (checkRepeatFlag())
+      {
+        // We shall stop:
+        break;
+/*
+        QMutexLocker cifLocker(&commandIFMutex);
+        commandInFlight = false;
+        return;
+*/
+      }
+
+      ++repeatCount;
+    }
+
+    QMutexLocker cifLocker(&commandIFMutex);
+    commandInFlight = false;
+  }
+  catch (PIRException e)
+  {
+    emit commandFailed(e.getError().c_str());
+  }
+}
+
+
+int TDCProtocol::pushBits(
+  const CommandSequence &bits,
+  PIRRX51Hardware &rx51device)
+{
+  int duration = 0;
+
+  CommandSequence::const_iterator i = bits.begin();
+
+  while (i != bits.end())
+  {
+    duration += pushBit(*i, rx51device);
+    ++i;
+  }
+
+  return duration;
+}
+
+
+int TDCProtocol::pushBit(
+  bool bitValue,
+  PIRRX51Hardware &device)
+{
+  unsigned int duration = 0;
+  // TDC encodes a "0" by using a space followed by a pulse,
+  // and a "1" by using a pulse followed by a space.
+
+  if (bitValue)
+  {
+    // We've got a "1".  First add a pulse, then a space.
+    if (bufferContainsPulse)
+    {
+      // Merge our pulse with the previous one, and send them to the device:
+      device.addSingle(buffer + biphaseUnit);
+      duration += (buffer + biphaseUnit);
+      buffer = 0;
+      bufferContainsPulse = false;
+    }
+    else
+    {
+      if (bufferContainsSpace)
+      {
+        // Flush out the buffer:
+        device.addSingle(buffer);
+        duration += buffer;
+        buffer = 0;
+        bufferContainsSpace = false;
+      }
+
+      // Add a pulse:
+      device.addSingle(biphaseUnit);
+      duration += biphaseUnit;
+    }
+
+    // Put a space into the buffer to wait:
+    buffer = biphaseUnit;
+    bufferContainsSpace = true;
+  }
+  else
+  {
+    // We've got a "0".  First add a space, then a pulse.
+    if (bufferContainsSpace)
+    {
+      // Merge our space with the previous space, and send them to
+      // the device.
+      device.addSingle(buffer + biphaseUnit);
+      duration += (buffer + biphaseUnit);
+      buffer = 0;
+      bufferContainsSpace = false;
+    }
+    else
+    {
+      if (bufferContainsPulse)
+      {
+        // Flush the buffer:
+        device.addSingle(buffer);
+        duration += buffer;
+        buffer = 0;
+        bufferContainsPulse = false;
+      }
+      // Add a space:
+      device.addSingle(biphaseUnit);
+      duration += biphaseUnit;
+    }
+
+    // Put a pulse into the buffer to wait.
+    buffer = biphaseUnit;
+    bufferContainsPulse = true;
+  }
+
+  return duration;
+}