New GUI, many changes
[pierogi] / protocols / nokia32protocol.cpp
diff --git a/protocols/nokia32protocol.cpp b/protocols/nokia32protocol.cpp
new file mode 100644 (file)
index 0000000..63c36ad
--- /dev/null
@@ -0,0 +1,251 @@
+#include "nokia32protocol.h"
+
+#include "pirrx51hardware.h"
+
+#include "pirexception.h"
+
+// Some global communications stuff:
+#include <QMutex>
+extern bool commandInFlight;
+extern QMutex commandIFMutex;
+
+// The Nokia 32 protocol has a 2-bit space encoding system, and appears to
+// work like this:
+// A "zero" is encoded with a 164 usec pulse, 276 usec space.
+// A "one" is encoded with a 164 usec pulse, 445 usec space.
+// A "two" is encoded with a 164 usec pulse, 614 usec space.
+// A "three" is encoded with a 164 usec pulse, 783 usec space.
+// The header is a 412 usec pulse, 276 usec space.
+// Commands end with a trailing 164 usec pulse.
+// The entire pulse train is re-sent when repeating.
+// There is a 100000 usec gap between commands. (? not sure here)
+// The carrier frequency is presumably 36 kHz.
+// The duty cycle is presumably 1/3.
+
+Nokia32Protocol::Nokia32Protocol(
+  QObject *guiObject,
+  unsigned int index)
+  : PIRProtocol(guiObject, index, 100000, false),
+    zeroPulse(164),
+    zeroSpace(276),
+    onePulse(164),
+    oneSpace(445),
+    twoPulse(164),
+    twoSpace(614),
+    threePulse(164),
+    threeSpace(783),
+    headerPulse(412),
+    headerSpace(276),
+    trailerPulse(164),
+    keypressCount(0)
+{
+}
+
+
+void Nokia32Protocol::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)
+    {
+      commandDuration = generateStandardCommand((*i).second, rx51device);
+
+      // Now, tell the device to send the whole 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;
+          ++keypressCount;
+          return;
+        }
+      }
+
+      ++repeatCount;
+    }
+  }
+  catch (PIRException e)
+  {
+    // inform the gui:
+    emit commandFailed(e.getError().c_str());
+  }
+
+  QMutexLocker cifLocker(&commandIFMutex);
+  commandInFlight = false;
+  ++keypressCount;
+}
+
+
+int Nokia32Protocol::generateStandardCommand(
+  const PIRKeyBits &pkb,
+  PIRRX51Hardware &rx51device)
+{
+  int duration = 0;
+
+  // First, the "header" pulse:
+  rx51device.addPair(headerPulse, headerSpace);
+  duration += (headerPulse + headerSpace);
+
+  // The layout of the Nokia 32 protocol is as follows:
+  // 1) an 8-bit "device code"
+  // 2) an 8-bit "sub-device code"
+  // 3) one toggle bit
+  // 4) seven more bits somehow associated with the device
+  // 5) an 8-bit command code.
+  // All are sent in MSB order.
+
+  // It's a bit of a hack, but I'll store the first 16 bits of address in the
+  // preData, the next 7 bits of address in the postData, and the 8 bits
+  // of command in the firstCode:
+
+  duration += pushBits(preData, rx51device);
+  duration += pushToggleAndBits(postData, rx51device);
+  duration += pushBits(pkb.firstCode, rx51device);
+
+  // Finally add the "trail":
+  rx51device.addSingle(trailerPulse);
+  duration += trailerPulse;
+
+  return duration;
+}
+
+
+int Nokia32Protocol::pushBits(
+  const CommandSequence &bits,
+  PIRRX51Hardware &rx51device)
+{
+  int duration = 0;
+  bool firstBit;
+  bool secondBit;
+
+  CommandSequence::const_iterator i = bits.begin();
+  while (i != bits.end())
+  {
+    firstBit = *i;
+    ++i;
+    if (i == bits.end()) break;
+    secondBit = *i;
+
+    duration += pushDoubleBit(firstBit, secondBit, rx51device);
+
+    ++i;
+  }
+
+  return duration;
+}
+
+
+int Nokia32Protocol::pushToggleAndBits(
+  const CommandSequence &bits,
+  PIRRX51Hardware &rx51device)
+{
+  int duration = 0;
+  bool firstBit;
+  bool secondBit;
+
+  // The first bit is the toggle bit:
+  if (keypressCount % 2)
+  {
+    firstBit = 1;
+  }
+  else
+  {
+    firstBit = 0;
+  }
+
+  CommandSequence::const_iterator i = bits.begin();
+  if (i == bits.end()) return 0;
+
+  secondBit = *i;
+
+  duration += pushDoubleBit(firstBit, secondBit, rx51device);
+
+  ++i;
+
+  while (i != bits.end())
+  {
+    firstBit = *i;
+    ++i;
+    if (i == bits.end()) break;
+    secondBit = *i;
+
+    duration += pushDoubleBit(firstBit, secondBit, rx51device);
+
+    ++i;
+  }
+
+  return duration;
+}
+
+
+int Nokia32Protocol::pushDoubleBit(
+  bool firstBit,
+  bool secondBit,
+  PIRRX51Hardware &rx51device)
+{
+  int duration = 0;
+
+  if (firstBit == 0)
+  {
+    if (secondBit == 0)
+    {
+      // Send the pulse for "Zero":
+      rx51device.addPair(zeroPulse, zeroSpace);
+      duration += (zeroPulse + zeroSpace);
+    }
+    else
+    {
+      // Send the pulse for "One":
+      rx51device.addPair(onePulse, oneSpace);
+      duration += (onePulse + oneSpace);
+    }
+  }
+  else
+  {
+    if (secondBit == 0)
+    {
+      // Send the pulse for "Two":
+      rx51device.addPair(twoPulse, twoSpace);
+      duration += (twoPulse + twoSpace);
+    }
+    else
+    {
+      // Send the pulse for "Three":
+      rx51device.addPair(threePulse, threeSpace);
+      duration += (threePulse + threeSpace);
+    }
+  }
+
+  return duration;
+}