/// <summary>
        /// Creates a task for a variable timebase output. Consumes the entire port (8 bits) that the timebase is on. (ie outputs the
        /// signal on all 8 bits
        /// </summary>
        /// <param name="channelName"></param>
        /// <param name="masterFrequency"></param>
        /// <param name="sequenceData"></param>
        /// <param name="timebaseType"></param>
        /// <returns></returns>
        public static Task createDaqMxVariableTimebaseSource(string channelName, int masterFrequency, SequenceData sequenceData,
                                                             SequenceData.VariableTimebaseTypes timebaseType, ServerSettings serverSettings, DeviceSettings deviceSettings)
        {
            Task task = new Task("Variable timebase output task");

            TimestepTimebaseSegmentCollection timebaseSegments = sequenceData.generateVariableTimebaseSegments(timebaseType,
                                                                                                               Common.getPeriodFromFrequency(masterFrequency));

            bool [] buffer = sequenceData.getVariableTimebaseClock(timebaseSegments);

            string timebaseDeviceName = HardwareChannel.parseDeviceNameStringFromPhysicalChannelString(channelName);

            string timebasePort = HardwareChannel.parsePortStringFromChannelString(channelName);

            task.DOChannels.CreateChannel(timebasePort, "", ChannelLineGrouping.OneChannelForAllLines);

            task.Timing.ConfigureSampleClock("", (double)masterFrequency, deviceSettings.ClockEdge, SampleQuantityMode.FiniteSamples, buffer.Length);

            if (serverSettings.VariableTimebaseTriggerInput != "")
            {
                task.Triggers.StartTrigger.ConfigureDigitalEdgeTrigger(serverSettings.VariableTimebaseTriggerInput, DigitalEdgeStartTriggerEdge.Rising);
            }

            DigitalSingleChannelWriter writer = new DigitalSingleChannelWriter(task.Stream);

            byte[] byteBuffer = new byte[buffer.Length];
            for (int j = 0; j < buffer.Length; j++)
            {
                if (buffer[j])
                {
                    byteBuffer[j] = 255;
                }
            }

            writer.WriteMultiSamplePort(false, byteBuffer);


            return(task);
        }
        /// <summary>
        /// This method is a sort of combination of createDaqMxVariableTimebaseSource and createDaqMxTask. It is intended
        /// for use to create a digital output task that has both a variable timebase source on it, without having to discard
        /// all of the other channels on that port (and possibly on its neighboring port).
        ///
        /// NOTE: No longer true. This function can not create the variable timebase outputs at the same time as
        /// normal outputs. If you attempt to use digital outputs on the same half of the card as your variable timebase output,
        /// this method will complain.
        /// </summary>
        /// <param name="channelName">
        /// Name of the channel that will output the variable timebase clock.
        /// </param>
        /// <param name="portsToUse">
        /// A list of integers specifying the digital ports that this task will use. The task will automatically
        /// make use of the full port that the variable timebase clock belongs to. If portsToUse is null, then
        /// this function will automatically use both this port and its neighboring port (0 with 1, 2 with 3, etc).
        /// The rationale for this is that on some NI devices, these pairs of ports will share a sample clock and
        /// cannot truly be used independently.
        /// </param>
        /// <param name="masterFrequency">
        /// The frequency, in hertz, of the master clock which will drive the variable timebase clock and the rest of the
        /// channels in this task.
        /// </param>
        /// <param name="sequenceData"></param>
        /// <param name="timebaseType"></param>
        /// <param name="deviceName"></param>
        /// <param name="deviceSettings"></param>
        /// <param name="sequence"></param>
        /// <param name="settings"></param>
        /// <param name="usedDigitalChannels"></param>
        /// <param name="usedAnalogChannels"></param>
        /// <param name="serverSettings"></param>
        /// <returns></returns>
        public static Task createDaqMxDigitalOutputAndVariableTimebaseSource(string channelName, List <int> portsToUse, int masterFrequency,
                                                                             SequenceData sequenceData, SequenceData.VariableTimebaseTypes timebaseType,
                                                                             string deviceName, DeviceSettings deviceSettings, SettingsData settings, Dictionary <int, HardwareChannel> usedDigitalChannels, ServerSettings serverSettings)
        {
            // First generate the variable timebase buffer. We will need stuff like its length for configuring the task, which is why we do this first.

            TimestepTimebaseSegmentCollection timebaseSegments = sequenceData.generateVariableTimebaseSegments(timebaseType, Common.getPeriodFromFrequency(masterFrequency));

            bool[] variableTimebaseBuffer = sequenceData.getVariableTimebaseClock(timebaseSegments);


            if (deviceName.ToUpper() != HardwareChannel.parseDeviceNameStringFromPhysicalChannelString(channelName).ToUpper())
            {
                throw new Exception("The variable timebase device " + HardwareChannel.parseDeviceNameStringFromPhysicalChannelString(channelName) + " does not match device " + deviceName + ". These must match for their their task to be created together.");
            }

            int timebasePortNum;
            int timebaseLineNum;

            try
            {
                timebasePortNum = HardwareChannel.parsePortNumberFromChannelString(channelName);
                timebaseLineNum = HardwareChannel.parseLineNumberFromChannelString(channelName);
            }
            catch (Exception)
            {
                throw new Exception("Channel name " + channelName + " is not a valid digital channel name. Cannot create a variable timebase output on this channel.");
            }



            if (portsToUse == null)
            {
                portsToUse = new List <int>();
                portsToUse.Add(timebasePortNum);
                int spousePort; // this port is likely to have a shared sample clock with timebasePortNum,
                // at least in my experience so far.
                if (timebasePortNum % 2 == 0)
                {
                    spousePort = timebasePortNum + 1;
                }
                else
                {
                    spousePort = timebasePortNum - 1;
                }

                portsToUse.Add(spousePort);
            }

            if (!portsToUse.Contains(timebasePortNum))
            {
                portsToUse.Add(timebasePortNum);
            }

            bool otherChannelsUsedOnUsedPort = false;

            foreach (HardwareChannel hc in usedDigitalChannels.Values)
            {
                if (hc.DeviceName.ToUpper() == deviceName.ToUpper())
                {
                    if (portsToUse.Contains(hc.daqMxDigitalPortNumber()))
                    {
                        otherChannelsUsedOnUsedPort = true;
                    }
                }
            }

            if (otherChannelsUsedOnUsedPort)
            {
                throw new Exception("Variable timebase channel is on a port that shares a sample clock with a used output channel (on most devices, port 0 and 1 have a shared clock, and port 2 and 3 have a shared clock). This usage is not recommended, and not currently supported. Aborting buffer generation.");

                #region Deprecated code

                /*
                 * Task task = new Task("Variable timebase output task");
                 *
                 * // Create channels in the task
                 * foreach (int portNum in portsToUse)
                 * {
                 *  task.DOChannels.CreateChannel(deviceName + '/' + HardwareChannel.digitalPhysicalChannelName(portNum), "", ChannelLineGrouping.OneChannelForAllLines);
                 * }
                 *
                 * // Configure the task...
                 *
                 * task.Timing.ConfigureSampleClock("", masterFrequency, SampleClockActiveEdge.Rising, SampleQuantityMode.FiniteSamples, variableTimebaseBuffer.Length);
                 *
                 * if (serverSettings.VariableTimebaseTriggerInput != "")
                 * {
                 *  task.Triggers.StartTrigger.ConfigureDigitalEdgeTrigger(serverSettings.VariableTimebaseTriggerInput, DigitalEdgeStartTriggerEdge.Rising);
                 * }
                 *
                 *
                 * // Figure out which ports we are going to use, and which digital ID each line on each of those ports
                 * // maps to.
                 * Dictionary<int, HardwareChannel> digitalChannelsToUse = getChannelsOnDevice(usedDigitalChannels, deviceName);
                 * List<int> temp = new List<int>(digitalChannelsToUse.Keys);
                 * foreach (int id in temp)
                 * {
                 *  HardwareChannel ch = digitalChannelsToUse[id];
                 *  if (!portsToUse.Contains(HardwareChannel.parsePortNumberFromChannelString(ch.ChannelName)))
                 *  {
                 *      digitalChannelsToUse.Remove(id);
                 *  }
                 * }
                 *
                 * // Remove all of the digital channels this buffer generation is consuming from the
                 * // usedDigitalChannels dictionary. Why? Because there may still be another task to
                 * // generate on this device, and this is a way of keeping track of which channels
                 * // have already had their buffers generated.
                 * // Since digitalChannelsToUse gets passed by reference from AtticusServerRuntime.generateBuffers(...),
                 * // these changes thus get communicated back to AtticusServerRuntime.
                 * foreach (HardwareChannel hc in digitalChannelsToUse.Values)
                 * {
                 *  foreach (int i in usedDigitalChannels.Keys)
                 *  {
                 *      if (usedDigitalChannels[i] == hc)
                 *      {
                 *          usedDigitalChannels.Remove(i);
                 *          break;
                 *      }
                 *  }
                 * }
                 *
                 * List<int> ids = new List<int>(digitalChannelsToUse.Keys);
                 * ids.Sort();
                 * List<HardwareChannel> hcs = new List<HardwareChannel>();
                 * foreach (int id in ids)
                 * {
                 *  hcs.Add(digitalChannelsToUse[id]);
                 * }
                 *
                 * Dictionary<int, int[]> port_digital_ids;
                 * List<int> usedPorts;
                 *
                 * groupDigitalChannels(ids, hcs, out port_digital_ids, out usedPorts);
                 *
                 *
                 *
                 * // now to generate the buffers.
                 *
                 *
                 * if (usedPorts.Count != 0)
                 * {
                 *  byte[,] digitalBuffer;
                 *
                 *
                 *  try
                 *  {
                 *      digitalBuffer = new byte[usedPorts.Count, variableTimebaseBuffer.Length];
                 *  }
                 *  catch (Exception e)
                 *  {
                 *      throw new Exception("Unable to allocate digital buffer for device " + deviceName + ". Reason: " + e.Message + "\n" + e.StackTrace);
                 *  }
                 *
                 *  for (int i = 0; i < usedPorts.Count; i++)
                 *  {
                 *      int portNum = usedPorts[i];
                 *      byte digitalBitMask = 1;
                 *      for (int lineNum = 0; lineNum < 8; lineNum++)
                 *      {
                 *          bool[] singleChannelBuffer = null;
                 *
                 *          if (portNum == timebasePortNum && lineNum == timebaseLineNum)
                 *          { // this current line is the variable timebase...
                 *              singleChannelBuffer = variableTimebaseBuffer;
                 *          }
                 *          else
                 *          {
                 *              int digitalID = port_digital_ids[portNum][lineNum];
                 *              if (digitalID != -1)
                 *              {
                 *                  if (settings.logicalChannelManager.Digitals[digitalID].overridden)
                 *                  {
                 *                      singleChannelBuffer = new bool[variableTimebaseBuffer.Length];
                 *                      if (settings.logicalChannelManager.Digitals[digitalID].digitalOverrideValue)
                 *                      {
                 *                          for (int j = 0; j < singleChannelBuffer.Length; j++)
                 *                          {
                 *                              singleChannelBuffer[j] = true;
                 *                          }
                 *                      }
                 *                  }
                 *                  else
                 *                  {
                 *                      singleChannelBuffer = sequenceData.getDigitalBufferClockSharedWithVariableTimebaseClock(timebaseSegments, digitalID, 1.0 / deviceSettings.SampleClockRate);
                 *                  }
                 *              }
                 *          }
                 *
                 *          if (singleChannelBuffer != null)
                 *          {
                 *              for (int j = 0; j < singleChannelBuffer.Length; j++)
                 *              {
                 *                  if (singleChannelBuffer[j])
                 *                  {
                 *                      digitalBuffer[i, j] |= digitalBitMask;
                 *                  }
                 *              }
                 *          }
                 *          digitalBitMask = (byte)(digitalBitMask << 1);
                 *
                 *      }
                 *  }
                 *  System.GC.Collect();
                 *  DigitalMultiChannelWriter writer = new DigitalMultiChannelWriter(task.Stream);
                 *  writer.WriteMultiSamplePort(false, digitalBuffer);
                 *
                 *
                 * }
                 *
                 *
                 * return task; */

                #endregion
            }
            else
            {
                return(createDaqMxVariableTimebaseSource(
                           channelName, masterFrequency, sequenceData, timebaseType, serverSettings, deviceSettings));
            }
        }