Still fixing install, more keyset work
[pierogi] / necprotocol.cpp
index 101895f..6468e12 100644 (file)
@@ -4,6 +4,43 @@
 #include <string>
 //#include <iostream>
 
+// Some global communications stuff:
+#include <QMutex>
+extern bool commandInFlight;
+extern QMutex commandIFMutex;
+
+// The official NEC protocol, as I understand it, has the following attributes:
+// A "zero" is encoded with a 560 usec pulse, 560 usec space.
+// A "one" is encoded with a 560 usec pulse, and 3*560 (1680) usec space.
+// The header is a 9000 usec pulse, 4500 usec space.
+// Commands end with a trailing 560 usec pulse.
+// A repeat block is a 9000 usec pulse, 2250 usec space, then trailing pulse.
+// Each command runs for 110000 usec before another can be executed.
+
+// For standard NEC, use this constructor:
+NECProtocol::NECProtocol(
+  QObject *guiObject,
+  unsigned int index)
+  : PIRProtocol(guiObject, index, 110000, true),
+    zeroPulse(560),
+    zeroSpace(560),
+    onePulse(560),
+    oneSpace(1680),
+    headerPulse(9000),
+    headerSpace(4500),
+    hasHeaderPair(true),
+    trailerPulse(560),
+    hasTrailerPulse(true),
+    repeatPulse(9000),
+    repeatSpace(2250),
+    hasRepeatPair(true),
+    repeatNeedsHeader(false),
+    fullHeadlessRepeat(false),
+    elevenBitToggle(false)
+{
+}
+
+// For non-standard NEC, use this constructor:
 NECProtocol::NECProtocol(
   QObject *guiObject,
   unsigned int index,
@@ -18,11 +55,12 @@ NECProtocol::NECProtocol(
     zeroSpace(zSpace),
     onePulse(oPulse),
     oneSpace(oSpace),
-    hasTrailerPulse(false),
     hasHeaderPair(false),
+    hasTrailerPulse(false),
     hasRepeatPair(false),
     repeatNeedsHeader(false),
-    fullHeadlessRepeat(false)
+    fullHeadlessRepeat(false),
+    elevenBitToggle(false)
 {
 }
 
@@ -63,18 +101,10 @@ void NECProtocol::setFullHeadlessRepeat(
   fullHeadlessRepeat = flag;
 }
 
-void NECProtocol::setPreData(
-  unsigned long data,
-  unsigned int bits)
-{
-  appendToBitSeq(preData, data, bits);
-}
-
-void NECProtocol::setPostData(
-  unsigned long data,
-  unsigned int bits)
+void NECProtocol::setElevenBitToggle(
+  bool flag)
 {
-  appendToBitSeq(postData, data, bits);
+  elevenBitToggle = flag;
 }
 
 void NECProtocol::startSendingCommand(
@@ -85,11 +115,18 @@ void NECProtocol::startSendingCommand(
   // whole thing in a try/catch block:
   try
   {
-    clearRepeatFlag();
-
-    // Check if we are meant to be the recipient of this command:
+    // First, check if we are meant to be the recipient of this command:
     if (threadableID != id) return;
 
+    // An object that helps keep track of the number of commands:
+//    PIRCommandCounter commandCounter;
+
+    // Ok, we're going to lock down this method and make sure
+    // only one guy at a time passes this point:
+//    QMutexLocker commandLocker(&commandMutex);
+
+    clearRepeatFlag();
+
     KeycodeCollection::const_iterator i = keycodes.find(command);
 
     // Do we even have this key defined?
@@ -100,7 +137,7 @@ void NECProtocol::startSendingCommand(
     }
 
     // construct the device:
-    PIRDevice device(carrierFrequency, dutyCycle);
+    PIRRX51Hardware rx51device(carrierFrequency, dutyCycle);
 
     int repeatCount = 0;
     while (repeatCount < MAX_REPEAT_COUNT)
@@ -111,19 +148,23 @@ void NECProtocol::startSendingCommand(
       // use that signal.  Otherwise, generate a normal command string.
       if (hasRepeatPair && repeatCount)
       {
-        commandDuration = generateRepeatCommand(device);
+        commandDuration = generateRepeatCommand(rx51device);
       }
       else if (fullHeadlessRepeat && repeatCount)
       {
-        commandDuration = generateHeadlessCommand((*i).second, device);
+        commandDuration = generateHeadlessCommand((*i).second, rx51device);
+      }
+      else if (elevenBitToggle && (repeatCount % 2))
+      {
+        commandDuration = generateToggledCommand((*i).second, rx51device);
       }
       else
       {
-        commandDuration = generateStandardCommand((*i).second, device);
+        commandDuration = generateStandardCommand((*i).second, rx51device);
       }
 
       // Now, tell the device to send the whole command:
-      device.sendCommandToDevice();
+      rx51device.sendCommandToDevice();
 
       // sleep until the next repetition of command:
       sleepUntilRepeat(commandDuration);
@@ -134,6 +175,8 @@ void NECProtocol::startSendingCommand(
         // Check whether we've been asked to stop:
         if (checkRepeatFlag())
         {
+          QMutexLocker cifLocker(&commandIFMutex);
+          commandInFlight = false;
           return;
         }
       }
@@ -146,35 +189,38 @@ void NECProtocol::startSendingCommand(
     // inform the gui:
     emit commandFailed(e.getError().c_str());
   }
+
+  QMutexLocker cifLocker(&commandIFMutex);
+  commandInFlight = false;
 }
 
 
 int NECProtocol::generateStandardCommand(
   const CommandSequence &bits,
-  PIRDevice &device)
+  PIRRX51Hardware &rx51device)
 {
   int duration = 0;
 
   // First, the "header" pulse (if any):
   if (hasHeaderPair)
   {
-    device.addPair(headerPulse, headerSpace);
+    rx51device.addPair(headerPulse, headerSpace);
     duration += (headerPulse + headerSpace);
   }
 
   // Next, the "pre" data:
-  duration += pushBits(preData, device);
+  duration += pushBits(preData, rx51device);
 
   // Next, add the actual command:
-  duration += pushBits(bits, device);
+  duration += pushBits(bits, rx51device);
 
   // Next, add the "post" data:
-  duration += pushBits(postData, device);
+  duration += pushBits(postData, rx51device);
 
   // Finally add the "trail":
   if (hasTrailerPulse)
   {
-    device.addSingle(trailerPulse);
+    rx51device.addSingle(trailerPulse);
     duration += trailerPulse;
   }
 
@@ -184,23 +230,23 @@ int NECProtocol::generateStandardCommand(
 
 int NECProtocol::generateHeadlessCommand(
   const CommandSequence &bits,
-  PIRDevice &device)
+  PIRRX51Hardware &rx51device)
 {
   int duration = 0;
 
   // First, the "pre" data:
-  duration += pushBits(preData, device);
+  duration += pushBits(preData, rx51device);
 
   // Next, add the actual command:
-  duration += pushBits(bits, device);
+  duration += pushBits(bits, rx51device);
 
   // Next, add the "post" data:
-  duration += pushBits(postData, device);
+  duration += pushBits(postData, rx51device);
 
   // Finally add the "trail":
   if (hasTrailerPulse)
   {
-    device.addSingle(trailerPulse);
+    rx51device.addSingle(trailerPulse);
     duration += trailerPulse;
   }
 
@@ -209,7 +255,7 @@ int NECProtocol::generateHeadlessCommand(
 
 
 int NECProtocol::generateRepeatCommand(
-  PIRDevice &device)
+  PIRRX51Hardware &rx51device)
 {
   int duration = 0;
 
@@ -220,19 +266,80 @@ int NECProtocol::generateRepeatCommand(
     if (hasHeaderPair)
     {
       // Ok, then add the header to the repeat:
-      device.addPair(headerPulse, headerSpace);
+      rx51device.addPair(headerPulse, headerSpace);
       duration += (headerPulse + headerSpace);
     }
   }
 
   // Add the repeat pulse:
-  device.addPair(repeatPulse, repeatSpace);
+  rx51device.addPair(repeatPulse, repeatSpace);
   duration += (repeatPulse + repeatSpace);
 
   // Finally add the trailer:
   if (hasTrailerPulse)
   {
-    device.addSingle(trailerPulse);
+    rx51device.addSingle(trailerPulse);
+    duration += trailerPulse;
+  }
+
+  return duration;
+}
+
+
+// NOTE!  The following is a special command to toggle the last eleven bits
+// of the fifteen-bit commands used by Denon, Sharp, and a few others.  It
+// assumes the command sequence will contain all fifteen bits.  If this
+// is not the case, it will work incorrectly!
+int NECProtocol::generateToggledCommand(
+  const CommandSequence &bits,
+  PIRRX51Hardware &rx51device)
+{
+  int duration = 0;
+
+  CommandSequence::const_iterator i = bits.begin();
+
+  int bitcount = 0;
+  // First 4 bits:
+  while ((bitcount < 4) && (i != bits.end()))
+  {
+    if (*i)
+    {
+      // Send pulse for "one":
+      rx51device.addPair(onePulse, oneSpace);
+      duration += (onePulse + oneSpace);
+    }
+    else
+    {
+      // Send pulse for "zero":
+      rx51device.addPair(zeroPulse, zeroSpace);
+      duration += (zeroPulse + zeroSpace);
+    }
+    ++i;
+    ++bitcount;
+  }
+
+  // Now, invert the last eleven bits:
+  while (i != bits.end())
+  {
+    if (*i)
+    {
+      // Send pulse for "zero":
+      rx51device.addPair(zeroPulse, zeroSpace);
+      duration += (zeroPulse + zeroSpace);
+    }
+    else
+    {
+      // Send pulse for "one":
+      rx51device.addPair(onePulse, oneSpace);
+      duration += (onePulse + oneSpace);
+    }
+    ++i;
+  }
+
+  // Add trail on end:
+  if (hasTrailerPulse)
+  {
+    rx51device.addSingle(trailerPulse);
     duration += trailerPulse;
   }
 
@@ -242,7 +349,7 @@ int NECProtocol::generateRepeatCommand(
 
 int NECProtocol::pushBits(
   const CommandSequence &bits,
-  PIRDevice &device)
+  PIRRX51Hardware &rx51device)
 {
   int duration = 0;
   CommandSequence::const_iterator i = bits.begin();
@@ -251,13 +358,13 @@ int NECProtocol::pushBits(
     if (*i)
     {
       // Send the pulse for "One":
-      device.addPair(onePulse, oneSpace);
+      rx51device.addPair(onePulse, oneSpace);
       duration += (onePulse + oneSpace);
     }
     else
     {
       // Send the pulse for "Zero":
-      device.addPair(zeroPulse, zeroSpace);
+      rx51device.addPair(zeroPulse, zeroSpace);
       duration += (zeroPulse + zeroSpace);
     }
     ++i;