/// <summary>
        /// Same as other version of groupDigitalChannels, but only allows for port numbers in the list allowedPortsToUse
        /// </summary>
        /// <param name="digitalIDs"></param>
        /// <param name="digitals"></param>
        /// <param name="port_digital_IDs"></param>
        /// <param name="usedPortNumbers"></param>
        /// <param name="allowedPortsToUse"></param>
        private static void groupDigitalChannels(List <int> digitalIDs, List <HardwareChannel> digitals, out Dictionary <int, int[]> port_digital_IDs, out List <int> usedPortNumbers, bool is6533, List <int> allowedPortsToUse)
        {
            // Irritating but true fact of life: To make the DAQmx drivers happy
            // we have to output the digital outputs in 8 bit groups corresponding to
            // the "port" of the device. This means we first have to amalgamate the digital channels that belong
            // to the same port, and fill in any "holes" (ie missing channels) with empty data
            {
                usedPortNumbers = new List <int>();
                // mapping from port number to an array of integers. The nth element of the array gives the digital ID
                // of the channel which is connected to the nth line of that port. If there is no channel on that port,
                // the ID is -1.
                port_digital_IDs = new Dictionary <int, int[]>();

                for (int i = 0; i < digitalIDs.Count; i++)
                {
                    int             digitalID = digitalIDs[i];
                    HardwareChannel hc        = digitals[i];

                    int portNum = hc.daqMxDigitalPortNumber();
                    int portNumBis;
                    if (!usedPortNumbers.Contains(portNum))
                    {
                        if (allowedPortsToUse.Contains(portNum))
                        {
                            if (!is6533)
                            {
                                usedPortNumbers.Add(portNum);
                                // Ports have to be used by pairs for the Daqmx driver to work. If port 0 is used, port 1 has to be used too, and the opposite too, etc...
                                portNumBis = portNum - 2 * (portNum % 2) + 1;
                                usedPortNumbers.Add(portNumBis);
                                // create the array mapping line number to digital IDs, and fill it with -1s.
                                port_digital_IDs.Add(portNum, new int[] { -1, -1, -1, -1, -1, -1, -1, -1 });
                                port_digital_IDs.Add(portNumBis, new int[] { -1, -1, -1, -1, -1, -1, -1, -1 });
                            }
                            else
                            {
                                usedPortNumbers.Add(0);
                                usedPortNumbers.Add(1);
                                usedPortNumbers.Add(2);
                                usedPortNumbers.Add(3);
                                port_digital_IDs.Add(0, new int[] { -1, -1, -1, -1, -1, -1, -1, -1 });
                                port_digital_IDs.Add(1, new int[] { -1, -1, -1, -1, -1, -1, -1, -1 });
                                port_digital_IDs.Add(2, new int[] { -1, -1, -1, -1, -1, -1, -1, -1 });
                                port_digital_IDs.Add(3, new int[] { -1, -1, -1, -1, -1, -1, -1, -1 });
                            }
                        }
                    }

                    if (usedPortNumbers.Contains(portNum))
                    {
                        port_digital_IDs[portNum][hc.daqMxDigitalLineNumber()] = digitalID;
                    }
                }
            }
        }
        /// <summary>
        /// This function creates channels in the given task, for the named device.
        /// </summary>
        /// <param name="deviceName">
        /// The name of the device which the channels will will be created for. Eg Dev1
        /// </param>
        /// <param name="usedDigitalChannels"></param>
        /// A dictionary, indexed by logical ID#, of all of the digital hardware channels parsed from parsed from settings data which
        /// reside on this server.
        /// <param name="usedAnalogChannels">
        /// A dictionary, indexed by logical ID#, of all of the analog hardware channels parsed from the settings data, which reside on this server.
        /// </param>
        /// <param name="task">The task for which channels will be created.</param>
        /// <param name="analogIDs">
        /// An out parameter, which will store a list of the analog IDs that were created, in the order created.
        /// </param>
        /// <param name="analogs">
        /// An out parameter, which will store a list of the analog hardware channels corresponding to the channels created, in the order created.
        /// </param>
        /// <param name="port_digital_IDs"></param>
        /// An out parameter, which will store a dictionary mapping a digital port number to an 8-length array of integers specifying the logical ID# of each bit of the
        /// given port #. Entries of -1 in this array indicate bits that have no logical ID# assigned. See **** in this method's source code for further information.
        /// <param name="usedPortNumbers">
        /// An out parameter, which will store a list of integers corresponding to the digital port numbers that were used on this device, in the order created.
        /// </param>
        private static void parseAndCreateChannels(string deviceName, DeviceSettings deviceSettings, Dictionary <int, HardwareChannel> usedDigitalChannels, Dictionary <int, HardwareChannel> usedAnalogChannels, Task task, out List <int> analogIDs, out List <HardwareChannel> analogs, out Dictionary <int, int[]> port_digital_IDs, out List <int> usedPortNumbers)
        {
            // figure out which of the analog and digital channels belong on this device. Add them here and index by
            // logical ID#
            Dictionary <int, HardwareChannel> analogsUnsorted  = getChannelsOnDevice(usedAnalogChannels, deviceName);
            Dictionary <int, HardwareChannel> digitalsUnsorted = getChannelsOnDevice(usedDigitalChannels, deviceName);


            // sort the lists by ID
            analogIDs = new List <int>();
            analogs   = new List <HardwareChannel>();
            sortDicionaryByID(analogIDs, analogs, analogsUnsorted);

            // list of the digital IDs of channels on this device
            List <int> digitalIDs = new List <int>();
            // list of the corresponding hardware channels
            List <HardwareChannel> digitals = new List <HardwareChannel>();

            sortDicionaryByID(digitalIDs, digitals, digitalsUnsorted);

            // ****
            // description of port_digital_IDs:
            // mapping from port number to an array of integers. The nth element of the array gives the digital ID
            // of the channel which is connected to the nth line of that port. If there is no channel on that port,
            // the ID is -1.

            if (deviceSettings.DeviceDescription.Contains("6533"))
            {
                groupDigitalChannels(digitalIDs, digitals, out port_digital_IDs, out usedPortNumbers, true);
            }
            else
            {
                groupDigitalChannels(digitalIDs, digitals, out port_digital_IDs, out usedPortNumbers, false);
            }

            //ok! create the channels.

            // analog first
            for (int i = 0; i < analogs.Count; i++)
            {
                task.AOChannels.CreateVoltageChannel(analogs[i].physicalChannelName(), "", -10, 10, AOVoltageUnits.Volts);
            }

            // now digital
            for (int i = 0; i < usedPortNumbers.Count; i++)
            {
                int portNum = usedPortNumbers[i];
                task.DOChannels.CreateChannel(deviceName + '/' + HardwareChannel.digitalPhysicalChannelName(portNum), "", ChannelLineGrouping.OneChannelForAllLines);
            }
        }
        /// <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));
            }
        }
예제 #5
0
        long postRetriggerTime = 100; // corresponds to 10us.
        // A workaround to issue when using software timed groups in
        // fpga-retriggered words

        // the workaround: delay the software timed group by an immesurable amount
        // if it is started in a retriggered word


        // This functionality is sort of somewhat duplicated in sequencedata.generatebuffers. It would be good
        // to come up with a more coherent framework to do these sorts of operations.

        public bool generateBuffer(SequenceData sequence, DeviceSettings deviceSettings, HardwareChannel hc, int logicalChannelID, List <GpibRampCommandConverter> commandConverters)
        {
            this.logicalChannelID = logicalChannelID;
            this.deviceType       = hc.GpibDeviceType;
            commandBuffer         = new List <GpibCommand>();


            if (deviceSettings.StartTriggerType != DeviceSettings.TriggerType.SoftwareTrigger)
            {
                throw new Exception("GPIB devices must have a software start trigger.");
            }

            // start by adding the initialization string to the command buffer
            // this does nothing for unknown device types
            // Modified by REO 11/25/08: Null strings produce errors if written to device, so check
            if (HardwareChannel.HardwareConstants.gpibInitializationCommands[(int)deviceType] != null)
            {
                commandBuffer.Add(new GpibCommand(HardwareChannel.HardwareConstants.gpibInitializationCommands[(int)deviceType], 0));
            }


            if (deviceType == HardwareChannel.HardwareConstants.GPIBDeviceType.Unknown)
            {
                foreach (GpibRampCommandConverter conv in commandConverters)
                {
                    //Modified by REO 11/25/08: Null strings produce errors if written to device, so check
                    if (deviceSettings.DeviceDescription.Contains(conv.DeviceIdentifierSubstring) && conv.InitializationCommand != null)
                    {
                        commandBuffer.Add(new GpibCommand(AddNewlineCharacters(conv.InitializationCommand), 0));
                    }
                }
            }

            int currentStepIndex = -1;

            //measured in ticks. 1 tick = 100 ns.
            long currentTime = 0;


            // This functionality is sort of somewhat duplicated in sequencedata.generatebuffers. It would be good
            // to come up with a more coherent framework to do these sorts of operations.
            while (true)
            {
                currentStepIndex++;

                if (currentStepIndex >= sequence.TimeSteps.Count)
                {
                    break;
                }

                TimeStep currentStep = sequence.TimeSteps[currentStepIndex];

                if (!currentStep.StepEnabled)
                {
                    continue;
                }

                if (currentStep.GpibGroup == null || !currentStep.GpibGroup.channelEnabled(logicalChannelID))
                {
                    currentTime += Shared.SecondsToTicks(currentStep.StepDuration.getBaseValue());
                    continue;
                }

                long postTime = 0;
                if (currentStep.RetriggerOptions.WaitForRetrigger)
                {
                    postTime = postRetriggerTime;
                }

                // determine the index of the next step in which this channel has an action
                int nextEnabledStepIndex = sequence.findNextGpibChannelEnabledTimestep(currentStepIndex, logicalChannelID);

                long groupDuration = Shared.SecondsToTicks(sequence.timeBetweenSteps(currentStepIndex, nextEnabledStepIndex));

                // now take action:

                GPIBGroupChannelData channelData = currentStep.GpibGroup.getChannelData(logicalChannelID);

                if (channelData.DataType == GPIBGroupChannelData.GpibChannelDataType.raw_string)
                {
                    // Raw string commands just get added
                    string stringWithCorrectNewlines = AddNewlineCharacters(channelData.RawString);

                    commandBuffer.Add(new GpibCommand(stringWithCorrectNewlines, currentTime + postTime));
                }
                else if (channelData.DataType == GPIBGroupChannelData.GpibChannelDataType.voltage_frequency_waveform)
                {
                    GpibRampCommandConverter rampConverter = null;
                    switch (hc.GpibDeviceType)
                    {
                    case HardwareChannel.HardwareConstants.GPIBDeviceType.Unknown:
                    {
                        foreach (GpibRampCommandConverter conv in commandConverters)
                        {
                            if (deviceSettings.DeviceDescription.Contains(conv.DeviceIdentifierSubstring))
                            {
                                rampConverter = conv;
                            }
                        }
                        if (rampConverter == null)
                        {
                            throw new Exception("Voltage/frequency ramp not supported for unknown gpib device " + hc.ToString() + ".");
                        }
                    }
                    break;

                    case HardwareChannel.HardwareConstants.GPIBDeviceType.Agilent_ESG_SIG_Generator:
                    {
                        rampConverter = ESG_SeriesRampConverter;
                    }
                    break;
                    }
                    double[] amplitudeArray;
                    double[] frequencyArray;

                    // get amplitude and frequency value arrays
                    int    nSamples         = (int)(Shared.TicksToSeconds(groupDuration) * (double)deviceSettings.SampleClockRate);
                    double secondsPerSample = Shared.TicksToSeconds(groupDuration) / (double)nSamples;

                    amplitudeArray = channelData.volts.getInterpolation(nSamples, 0, Shared.TicksToSeconds(groupDuration), sequence.Variables, sequence.CommonWaveforms);
                    frequencyArray = channelData.frequency.getInterpolation(nSamples, 0, Shared.TicksToSeconds(groupDuration), sequence.Variables, sequence.CommonWaveforms);

                    List <DoubleIntPair> amplitudeIndexPairs = ConvertArrayToIndexValuePairs(amplitudeArray);
                    List <DoubleIntPair> frequencyIndexPairs = ConvertArrayToIndexValuePairs(frequencyArray);
                    int amplitudeIndex = 0;
                    int frequencyIndex = 0;
                    for (int i = 0; i < nSamples; i++)
                    {
                        bool amplitudeMatch = false;
                        bool frequencyMatch = false;

                        // determine if there is either a amplitude or frequency data point for this sample number
                        if (amplitudeIndex < amplitudeIndexPairs.Count)
                        {
                            amplitudeMatch = amplitudeIndexPairs[amplitudeIndex].myInt == i;
                        }
                        if (frequencyIndex < frequencyIndexPairs.Count)
                        {
                            frequencyMatch = frequencyIndexPairs[frequencyIndex].myInt == i;
                        }

                        if (amplitudeIndex >= amplitudeIndexPairs.Count && frequencyIndex >= frequencyIndexPairs.Count)
                        {
                            break;
                        }

                        if (amplitudeMatch || frequencyMatch)
                        {
                            string command = "";
                            if (amplitudeMatch)
                            {
                                command += rampConverter.amplitudeCommand(amplitudeIndexPairs[amplitudeIndex].myDouble);
                                amplitudeIndex++;
                            }
                            if (frequencyMatch)
                            {
                                command += rampConverter.frequencyCommand(frequencyIndexPairs[frequencyIndex].myDouble);
                                frequencyIndex++;
                            }

                            long commandTime = currentTime + Shared.SecondsToTicks((double)i * secondsPerSample) + postTime;


                            commandBuffer.Add(new GpibCommand(command, commandTime));
                        }
                    }
                }
                else if (channelData.DataType == GPIBGroupChannelData.GpibChannelDataType.string_param_string)
                {
                    if (channelData.StringParameterStrings != null)
                    {
                        foreach (StringParameterString sps in channelData.StringParameterStrings)
                        {
                            string commandWithCorrectNewlines = AddNewlineCharacters(sps.ToString());
                            commandBuffer.Add(new GpibCommand(commandWithCorrectNewlines, currentTime + postTime));
                        }
                    }
                }

                currentTime += Shared.SecondsToTicks(currentStep.StepDuration.getBaseValue());
            }

            return(true);
        }
예제 #6
0
        public bool generateBuffer(SequenceData sequence, DeviceSettings deviceSettings, HardwareChannel hc, int logicalChannelID)
        {
            lock (commandBuffer)
            {
                commandBuffer.Clear();
                this.logicalChannelID = logicalChannelID;


                if (deviceSettings.StartTriggerType != DeviceSettings.TriggerType.SoftwareTrigger)
                {
                    throw new Exception("RS232 devices must have a software start trigger.");
                }


                //     List<TimeStep> enabledSteps = sequence.enabledTimeSteps();

                int currentStepIndex = -1;

                //measured in ticks. 1 tick = 100 ns.
                long currentTime = 0;

                long postRetriggerTime = 100; // corresponds to 10us.
                // A workaround to issue when using software timed groups in
                // fpga-retriggered words

                // the workaround: delay the software timed group by an immesurable amount
                // if it is started in a retriggered word



                // This functionality is sort of somewhat duplicated in sequencedata.generatebuffers. It would be good
                // to come up with a more coherent framework to do these sorts of operations.
                while (true)
                {
                    currentStepIndex++;

                    if (currentStepIndex >= sequence.TimeSteps.Count)
                    {
                        break;
                    }

                    TimeStep currentStep = sequence.TimeSteps[currentStepIndex];

                    if (!currentStep.StepEnabled)
                    {
                        continue;
                    }

                    long postTime = 0;
                    if (currentStep.RetriggerOptions.WaitForRetrigger)
                    {
                        postTime = postRetriggerTime;
                    }

                    if (currentStep.rs232Group == null || !currentStep.rs232Group.channelEnabled(logicalChannelID))
                    {
                        currentTime += seconds_to_ticks(currentStep.StepDuration.getBaseValue());
                        continue;
                    }

                    // determine the index of the next step in which this channel has an action
                    int nextEnabledStepIndex = sequence.findNextRS232ChannelEnabledTimestep(currentStepIndex, logicalChannelID);

                    long groupDuration = seconds_to_ticks(sequence.timeBetweenSteps(currentStepIndex, nextEnabledStepIndex));

                    // now take action:

                    RS232GroupChannelData channelData = currentStep.rs232Group.getChannelData(logicalChannelID);

                    if (channelData.DataType == RS232GroupChannelData.RS232DataType.Raw)
                    {
                        // Raw string commands just get added
                        string stringWithCorrectNewlines = AddNewlineCharacters(channelData.RawString);

                        commandBuffer.Add(new RS232Command(stringWithCorrectNewlines, currentTime + postTime));
                    }
                    else if (channelData.DataType == RS232GroupChannelData.RS232DataType.Parameter)
                    {
                        if (channelData.StringParameterStrings != null)
                        {
                            foreach (StringParameterString srs in channelData.StringParameterStrings)
                            {
                                commandBuffer.Add(new RS232Command(
                                                      AddNewlineCharacters(srs.ToString()), currentTime + postTime));
                            }
                        }
                    }



                    currentTime += seconds_to_ticks(currentStep.StepDuration.getBaseValue());
                }
            }

            return(true);
        }