public RunLog(DateTime runTime, DateTime listStartTime, SequenceData sequence, SettingsData settings, string sequenceFileName, string settingsFileName) { this.runTime = runTime; this.listStartTime = listStartTime; this.runSequence = sequence; this.runSettings = settings; this.SequenceFileName = sequenceFileName; this.SettingsFileName = settingsFileName; }
public void setSettings(SettingsData settings) { if (mainClientForm.instance != null) mainClientForm.instance.cursorWait(); if (digitalOverrides == null) { digitalOverrides = new List<DigitalOverride>(); } foreach (DigitalOverride dov in digitalOverrides) { digitalOverridePanel.Controls.Remove(dov); dov.unRegsiterHotkey(); dov.Dispose(); } digitalOverrides.Clear(); List<int> digitalIDs = new List<int>(settings.logicalChannelManager.Digitals.Keys); digitalIDs.Sort(); int counter = 0; foreach (int id in digitalIDs) { LogicalChannel chan = settings.logicalChannelManager.Digitals[id]; DigitalOverride dov = new DigitalOverride(chan, id); dov.Location = new Point(digitalOverridePlaceholder.Location.X, digitalOverridePlaceholder.Location.Y + counter * (digitalOverridePlaceholder.Height - 4)); digitalOverrides.Add(dov); dov.registerHotkey(); dov.BackColor = Storage.settingsData.DigitalGridColors[counter % Storage.settingsData.DigitalGridColors.Count]; counter++; } digitalOverridePanel.Controls.AddRange(digitalOverrides.ToArray()); if (analogOverrides == null) { analogOverrides = new List<AnalogOverride>(); } foreach (AnalogOverride ao in analogOverrides) { analogOverridePanel.Controls.Remove(ao); ao.Dispose(); } analogOverrides.Clear(); List<int> analogIDs = new List<int>(settings.logicalChannelManager.Analogs.Keys); analogIDs.Sort(); counter = 0; foreach (int id in analogIDs) { LogicalChannel chan = settings.logicalChannelManager.Analogs[id]; AnalogOverride ao = new AnalogOverride(chan, id); ao.Location = new Point(analogOverridePlaceholder.Location.X, analogOverridePlaceholder.Location.Y + counter * analogOverridePlaceholder.Height); analogOverrides.Add(ao); counter++; } analogOverridePanel.Controls.AddRange(analogOverrides.ToArray()); if (mainClientForm.instance != null) mainClientForm.instance.cursorWaitRelease(); }
public Dictionary<int, bool[]> _testCalculateAllDigitalBuffersVariableFrequency(SettingsData settings, double masterTimestepSize) { Dictionary<int, bool[]> ans = new Dictionary<int, bool[]>(); TimestepTimebaseSegmentCollection varbase = this.generateVariableTimebaseSegments(VariableTimebaseTypes.AnalogGroupControlledVariableFrequencyClock, masterTimestepSize); int nSamples = varbase.nSegmentSamples() +1; foreach (int digitalChannelId in settings.logicalChannelManager.Digitals.Keys) { bool[] chanBuff = new bool[nSamples]; this.computeDigitalBuffer(digitalChannelId, masterTimestepSize, chanBuff, varbase); ans.Add(digitalChannelId, chanBuff); } return ans; }
public Dictionary<int, double[]> _testCalculateAllAnalogBuffersFixedFrequenct(SettingsData settings, double masterTimestepSize) { Dictionary<int, double[]> ans = new Dictionary<int, double[]>(); foreach (int analogId in settings.logicalChannelManager.Analogs.Keys) { ans.Add(analogId, this.computeAnalogBuffer(analogId, masterTimestepSize)); } return ans; }
public void populateWithChannels(SettingsData settings) { foreach (TimeStep step in TimeSteps) { // Add digital datapoints to each timestep. foreach (int digitalID in settings.logicalChannelManager.ChannelCollections[HardwareChannel.HardwareConstants.ChannelTypes.digital].getSortedChannelIDList()) { if (!step.DigitalData.ContainsKey(digitalID)) { step.DigitalData.Add(digitalID, new DigitalDataPoint()); } } } foreach (AnalogGroup ag in AnalogGroups) { foreach (int analogID in settings.logicalChannelManager.ChannelCollections[HardwareChannel.HardwareConstants.ChannelTypes.analog].getSortedChannelIDList()) { if (!ag.containsChannelID(analogID)) { ag.addChannel(analogID); } } } }
public ServerActionStatus setSettingsOnConnectedServers(SettingsData settings, EventHandler<MessageEvent> messageLog) { return runNamedMethodOnConnectedServers("setSettings", new object[] { settings }, 4000, messageLog); }
public ServerActionStatus outputRS232GroupOnConnectedServers(RS232Group rs232Group, SettingsData settings, EventHandler<MessageEvent> messageLog) { return runNamedMethodOnConnectedServers("outputRS232Group", new object[] { rs232Group, settings }, 4000, messageLog); }
/// <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, 1.0 / deviceSettings.SampleClockRate); 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); } }
/// <summary> /// Outputs a single gpib group. (evaluated at the beginning of the group.) /// </summary> /// <param name="gpibGroup"></param> /// <param name="settings"></param> /// <returns></returns> public abstract bool outputGPIBGroup(GPIBGroup gpibGroup, SettingsData settings);
/// <summary> /// Sets the settings object. /// </summary> public abstract bool setSettings(SettingsData settings);
public override bool outputSingleTimestep(SettingsData settings, SingleOutputFrame output) { return true; }
public override bool outputRS232Group(RS232Group rs232Group, SettingsData settings) { return true; }
public override bool outputGPIBGroup(GPIBGroup gpibGroup, SettingsData settings) { return true; }
public override bool setSettings(SettingsData settings) { return true; }
public override bool outputRS232Group(RS232Group rs232Group, SettingsData settings) { lock (remoteLockObj) { try { messageLog(this, new MessageEvent("Received an output rs232 group request.")); if (rs232Group == null) { messageLog(this, new MessageEvent("Received a null output object. Unable to comply.")); displayError(); return false; } if (!stopAndCleanupTasks()) return false; if (!setSettings(settings)) return false; foreach (int channelID in usedRS232Channels.Keys) { if (rs232Group.channelEnabled(channelID)) { HardwareChannel hc = usedRS232Channels[channelID]; RS232GroupChannelData channelData = rs232Group.ChannelDatas[channelID]; if (channelData.DataType == RS232GroupChannelData.RS232DataType.Raw) { NationalInstruments.VisaNS.SerialSession ss = getSerialSession(hc); ss.Write(RS232Task.AddNewlineCharacters(channelData.RawString)); messageLog(this, new MessageEvent("Wrote rs232 command " + channelData.RawString)); } else if (channelData.DataType == RS232GroupChannelData.RS232DataType.Parameter) { if (channelData.StringParameterStrings != null) { foreach (StringParameterString sps in channelData.StringParameterStrings) { NationalInstruments.VisaNS.SerialSession ss = getSerialSession(hc); string rawCommand = sps.ToString(); string command = RS232Task.AddNewlineCharacters(rawCommand); ss.Write(command); messageLog(this, new MessageEvent("Wrote rs232 command " + rawCommand)); } } } else { messageLog(this, new MessageEvent("Skipping output on channel " + channelID + ", output now not enabled for data of type " + channelData.DataType.ToString())); } } } return true; } catch (Exception e) { messageLog(this, new MessageEvent("Caught exception when attempting output of single rs232 group: " + e.Message + e.StackTrace)); displayError(); return false; } return true; } }
public override bool setSettings(SettingsData settings) { lock (remoteLockObj) { try { messageLog(this, new MessageEvent("Received settings.")); this.settings = settings; findMyChannels(); return true; } catch (Exception e) { messageLog(this, new MessageEvent("Caught exception while attempting to verify settings. " + e.Message + e.StackTrace)); displayError(); return false; } } }
/// <summary> /// Outputs a single rs232 Group. (evaluated at the beginning of the group.) /// </summary> /// <param name="rs232Group"></param> /// <param name="settings"></param> /// <returns></returns> public abstract bool outputRS232Group(RS232Group rs232Group, SettingsData settings);
/// <summary> /// Outputs a single timestep. /// </summary> /// <param name="settings"></param> /// <param name="output"></param> /// <returns></returns> public abstract bool outputSingleTimestep(SettingsData settings, SingleOutputFrame output);
public ServerActionStatus setSettingsOnConnectedServers(SettingsData settings, EventHandler <MessageEvent> messageLog) { return(runNamedMethodOnConnectedServers("setSettings", new object[] { settings }, 4000, messageLog)); }
public ServerActionStatus outputGPIBGroupOnConnectedServers(GPIBGroup gpibGroup, SettingsData settings, EventHandler messageLog) { return runNamedMethodOnConnectedServers("outputGPIBGroup", new object[] { gpibGroup, settings }, 4000, messageLog); }
public ServerActionStatus outputSingleTimestepOnConnectedServers(SettingsData settings, SingleOutputFrame output, EventHandler <MessageEvent> messageLog) { return(runNamedMethodOnConnectedServers("outputSingleTimestep", new object[] { settings, output }, 5000, messageLog)); }
public ServerActionStatus outputSingleTimestepOnConnectedServers(SettingsData settings, SingleOutputFrame output, EventHandler<MessageEvent> messageLog) { return runNamedMethodOnConnectedServers("outputSingleTimestep", new object[] { settings, output }, 5000, messageLog); }
public ServerActionStatus outputRS232GroupOnConnectedServers(RS232Group rs232Group, SettingsData settings, EventHandler <MessageEvent> messageLog) { return(runNamedMethodOnConnectedServers("outputRS232Group", new object[] { rs232Group, settings }, 4000, messageLog)); }
public SingleOutputFrame getSingleOutputFrameAtEndOfTimestep(TimeStep step, SettingsData settings, bool outputAnalogDwellValues) { int analogStepID; if (outputAnalogDwellValues) { analogStepID = TimeSteps.IndexOf(dwellWord()); } else { analogStepID = TimeSteps.IndexOf(step); } TimeStep analogStep = TimeSteps[analogStepID]; int timeStepID = TimeSteps.IndexOf(step); SingleOutputFrame ans = new SingleOutputFrame(); foreach (int analogID in settings.logicalChannelManager.Analogs.Keys) { if (settings.logicalChannelManager.Analogs[analogID].TogglingChannel) { ans.analogValues.Add(analogID, 0); } else if (settings.logicalChannelManager.Analogs[analogID].overridden) { ans.analogValues.Add(analogID, settings.logicalChannelManager.Analogs[analogID].analogOverrideValue); } else { if (settings.logicalChannelManager.Analogs[analogID].AnalogChannelOutputNowUsesDwellWord) { ans.analogValues.Add(analogID, getAnalogValueAtEndOfTimestep(TimeSteps.IndexOf(dwellWord()), analogID, Variables)); } else { ans.analogValues.Add(analogID, getAnalogValueAtEndOfTimestep(analogStepID, analogID, Variables)); } } } foreach (int digitalID in settings.logicalChannelManager.Digitals.Keys) { bool val = false; if (settings.logicalChannelManager.Digitals[digitalID].TogglingChannel) { val = false; } else if (settings.logicalChannelManager.Digitals[digitalID].overridden) { val = settings.logicalChannelManager.Digitals[digitalID].digitalOverrideValue; } else { if (step.DigitalData.ContainsKey(digitalID)) { DigitalDataPoint dp = step.DigitalData[digitalID]; if (!dp.DigitalContinue) { val = step.DigitalData[digitalID].getValue(); } else // this digital value is a "continue" value, so, we have to go backwards in time until we find // what value to continue from { int checkStep = timeStepID - 1; val = false; // if we hunt all the way to the first timestep with no answer, the default answer is false while (checkStep >= 0) { if (TimeSteps[checkStep].StepEnabled) { if (TimeSteps[checkStep].DigitalData.ContainsKey(digitalID)) { if (TimeSteps[checkStep].DigitalData[digitalID].DigitalContinue) { checkStep--; // timestep had another continue keep hunting backwards... } else { val = TimeSteps[checkStep].DigitalData[digitalID].getValue(); break; } } else { break; } } else { checkStep--; // timestep was disabled, keep looking } } } } } ans.digitalValues.Add(digitalID, val); } return ans; }
public void RefreshSettingsDataToUI(SettingsData settingsData) { WordGenerator.mainClientForm.instance.cursorWait(); this.analogGroupEditor1.setChannelCollection(settingsData.logicalChannelManager.ChannelCollections[HardwareChannel.HardwareConstants.ChannelTypes.analog]); this.gpibGroupEditor1.setChannelCollection(settingsData.logicalChannelManager.ChannelCollections[HardwareChannel.HardwareConstants.ChannelTypes.gpib]); this.rS232GroupEditor1.setChannelCollection(settingsData.logicalChannelManager.ChannelCollections[HardwareChannel.HardwareConstants.ChannelTypes.rs232]); this.overridePage1.setSettings(Storage.settingsData); this.sequencePage1.layoutSettingsData(); this.sequencePage1.updateOverrideCount(); setTimestepEditorBackgrounds(); WordGenerator.mainClientForm.instance.cursorWaitRelease(); }
/// <summary> /// Used for automated testing purposes only. Creates a buffer snapshot object which can be archived, or /// compared to archived versions, to verify that buffer generation code doesn't change behavior with /// new releases. /// </summary> /// <param name="settings"></param> /// <param name="masterSamp"></param> /// <returns></returns> public BufferTestSnapshot _createBufferSnapshot(SettingsData settings, double masterSamp) { BufferTestSnapshot snap = new BufferTestSnapshot(); snap.MasterTimebaseSampleDuration = masterSamp; snap.Sequence = this; snap.Settings = settings; this.createLoopCopies(); snap.AnalogFixed = _testCalculateAllAnalogBuffersFixedFrequenct(snap.Settings, masterSamp); snap.AnalogVar = _testCalculateAllAnalogBuffersVariableFrequency(snap.Settings, masterSamp); snap.DigitalFixed = _testCalculateAllDigitalBuffersFixedFrequency(snap.Settings, masterSamp); snap.DigitalVar = _testCalculateAllDigitalBuffersVariableFrequency(snap.Settings, masterSamp); this.cleanupLoopCopies(); return snap; }
public Dictionary<int, bool[]> _testCalculateAllDigitalBuffersFixedFrequency(SettingsData settings, double masterTimestepSize) { Dictionary<int, bool[]> ans = new Dictionary<int, bool[]>(); foreach (int digitalChannelId in settings.logicalChannelManager.Digitals.Keys) { ans.Add(digitalChannelId, this.computeDigitalBuffer(digitalChannelId, masterTimestepSize)); } return ans; }
public override bool outputGPIBGroup(GPIBGroup gpibGroup, SettingsData settings) { lock (remoteLockObj) { try { messageLog(this, new MessageEvent("Received an output gpib group request.")); if (gpibGroup == null) { messageLog(this, new MessageEvent("Received a null object, unable to comply.")); displayError(); return false; } if (!stopAndCleanupTasks()) return false; if (!setSettings(settings)) return false; foreach (int channelID in usedGpibChannels.Keys) { if (gpibGroup.channelEnabled(channelID)) { HardwareChannel hc = usedGpibChannels[channelID]; GPIBGroupChannelData channelData = gpibGroup.ChannelDatas[channelID]; if (channelData.DataType == GPIBGroupChannelData.GpibChannelDataType.raw_string) { NationalInstruments.NI4882.Device gpibDevice = new NationalInstruments.NI4882.Device(hc.gpibBoardNumber(), niAddress(hc.GpibAddress)); gpibDevice.Write( GpibTask.AddNewlineCharacters(channelData.RawString)); messageLog(this, new MessageEvent("Wrote GPIB data : " + channelData.RawString)); } else if (channelData.DataType == GPIBGroupChannelData.GpibChannelDataType.string_param_string) { NationalInstruments.NI4882.Device gpibDevice = new NationalInstruments.NI4882.Device(hc.gpibBoardNumber(), niAddress(hc.GpibAddress)); if (channelData.StringParameterStrings != null) { foreach (StringParameterString sps in channelData.StringParameterStrings) { gpibDevice.Write( GpibTask.AddNewlineCharacters(sps.ToString())); messageLog(this, new MessageEvent("Wrote GPIB data : " + sps.ToString())); } } } else { messageLog(this, new MessageEvent("Skipping channel " + channelID + ", unsupported data type for an Output Now request: " + channelData.DataType.ToString())); displayError(); } } } return true; } catch (Exception e) { messageLog(this, new MessageEvent("Caught exception when attempting to output gpib group: " + e.Message + e.StackTrace)); displayError(); return false; } } }
/// <summary> /// Outputs a single output frame to analog and digital cards. All other cards / outputs are unaffected. /// </summary> /// <param name="settings"></param> /// <param name="output"></param> /// <returns></returns> public override bool outputSingleTimestep(SettingsData settings, SingleOutputFrame output) { lock (remoteLockObj) { try { messageLog(this, new MessageEvent("Received an output single timestep request.")); if (output == null) { messageLog(this, new MessageEvent("Received a null output object. Unable to comply.")); return false; } if (!stopAndCleanupTasks()) return false; if (!setSettings(settings)) return false; foreach (string dev in usedDaqMxDevices) { DeviceSettings deviceSettings = myServerSettings.myDevicesSettings[dev]; if (deviceSettings.DeviceEnabled) { messageLog(this, new MessageEvent("Generating single output for " + dev)); Task task = DaqMxTaskGenerator.createDaqMxTaskAndOutputNow(dev, deviceSettings, output, settings, usedDigitalChannels, usedAnalogChannels); daqMxTasks.Add(dev, task); messageLog(this, new MessageEvent("Success.")); } else { messageLog(this, new MessageEvent("Skipped buffer generation for disabled device " + dev)); } } return true; } catch (Exception e) { messageLog(this, new MessageEvent("Caught exception when attempting output of single timestep: " + e.Message + e.StackTrace)); displayError(); return false; } } }
/// <summary> /// This method creates analog and digital output buffers for daqMx cards. Note that the daqmx library seems to only support /// either analog OR digital on a given card at one time. Despite the fact that this method will create both types of buffers, /// it will probably throw some daqMX level exceptions if asked to create both analog and digital buffers for the same device. /// </summary> /// <param name="deviceName"></param> /// <param name="deviceSettings"></param> /// <param name="sequence"></param> /// <param name="settings"></param> /// <param name="usedDigitalChannels">digital channels which reside on this server.</param> /// <param name="usedAnalogChannels">analog channels which reside on this server</param> /// <returns></returns> public static Task createDaqMxTask(string deviceName, DeviceSettings deviceSettings, SequenceData sequence, SettingsData settings, Dictionary<int, HardwareChannel> usedDigitalChannels, Dictionary<int, HardwareChannel> usedAnalogChannels, ServerSettings serverSettings, out long expectedSamplesGenerated) { expectedSamplesGenerated = 0; Task task = new Task(deviceName + " output task"); List<int> analogIDs; List<HardwareChannel> analogs; Dictionary<int, int[]> port_digital_IDs; List<int> usedPortNumbers; // Parse and create channels. parseAndCreateChannels(deviceName,deviceSettings, usedDigitalChannels, usedAnalogChannels, task, out analogIDs, out analogs, out port_digital_IDs, out usedPortNumbers); if (analogIDs.Count != 0) { if (deviceSettings.UseCustomAnalogTransferSettings) { task.AOChannels.All.DataTransferMechanism = deviceSettings.AnalogDataTransferMechanism; task.AOChannels.All.DataTransferRequestCondition = deviceSettings.AnalogDataTransferCondition; } } if (usedPortNumbers.Count != 0) { if (deviceSettings.UseCustomDigitalTransferSettings) { task.DOChannels.All.DataTransferMechanism = deviceSettings.DigitalDataTransferMechanism; task.DOChannels.All.DataTransferRequestCondition = deviceSettings.DigitalDataTransferCondition; } } // ok! now create the buffers #region NON variable timebase buffer if (deviceSettings.UsingVariableTimebase == false) { // non "variable timebase" buffer creation double timeStepSize = 1.0 / (double)deviceSettings.SampleClockRate; int nBaseSamples = sequence.nSamples(timeStepSize); // for reasons that are utterly stupid and frustrating, the DAQmx libraries seem to prefer sample // buffers with lengths that are a multiple of 4. (otherwise they, on occasion, depending on the parity of the // number of channels, throw exceptions complaining. // thus we add a few filler samples at the end of the sequence which parrot back the last sample. int nFillerSamples = 4 - nBaseSamples % 4; if (nFillerSamples == 4) nFillerSamples = 0; int nSamples = nBaseSamples + nFillerSamples; if (deviceSettings.MySampleClockSource == DeviceSettings.SampleClockSource.DerivedFromMaster) { task.Timing.ConfigureSampleClock("", deviceSettings.SampleClockRate, deviceSettings.ClockEdge, SampleQuantityMode.FiniteSamples, nSamples); } else { task.Timing.ConfigureSampleClock(deviceSettings.SampleClockExternalSource, deviceSettings.SampleClockRate, deviceSettings.ClockEdge, SampleQuantityMode.FiniteSamples, nSamples); } if (deviceSettings.MasterTimebaseSource != "" && deviceSettings.MasterTimebaseSource != null) { task.Timing.MasterTimebaseSource = deviceSettings.MasterTimebaseSource.ToString(); } // Analog first... if (analogIDs.Count != 0) { double[,] analogBuffer; double[] singleChannelBuffer; try { analogBuffer = new double[analogs.Count, nSamples]; singleChannelBuffer = new double[nSamples]; } catch (Exception e) { throw new Exception("Unable to allocate analog buffer for device " + deviceName + ". Reason: " + e.Message + "\n" + e.StackTrace); } for (int i = 0; i < analogIDs.Count; i++) { int analogID = analogIDs[i]; if (settings.logicalChannelManager.Analogs[analogID].TogglingChannel) { DaqMxTaskGenerator.getAnalogTogglingBuffer(singleChannelBuffer); } else if (settings.logicalChannelManager.Analogs[analogID].overridden) { for (int j = 0; j < singleChannelBuffer.Length; j++) { singleChannelBuffer[j] = settings.logicalChannelManager.Analogs[analogID].analogOverrideValue; } } else { sequence.computeAnalogBuffer(analogIDs[i], timeStepSize, singleChannelBuffer); } for (int j = 0; j < nBaseSamples; j++) { analogBuffer[i, j] = singleChannelBuffer[j]; } for (int j = nBaseSamples; j < nSamples; j++) { analogBuffer[i, j] = analogBuffer[i, j - 1]; } } singleChannelBuffer = null; System.GC.Collect(); AnalogMultiChannelWriter writer = new AnalogMultiChannelWriter(task.Stream); writer.WriteMultiSample(false, analogBuffer); // analog cards report the exact number of generated samples. for non-variable timebase this is nSamples expectedSamplesGenerated = nSamples; } if (usedPortNumbers.Count != 0) { byte[,] digitalBuffer; bool[] singleChannelBuffer; try { digitalBuffer = new byte[usedPortNumbers.Count, nSamples]; singleChannelBuffer = new bool[nSamples]; } 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 < usedPortNumbers.Count; i++) { int portNum = usedPortNumbers[i]; byte digitalBitMask = 1; for (int lineNum = 0; lineNum < 8; lineNum++) { int digitalID = port_digital_IDs[portNum][lineNum]; if (digitalID != -1) { if (settings.logicalChannelManager.Digitals[digitalID].TogglingChannel) { getDigitalTogglingBuffer(singleChannelBuffer); } else if (settings.logicalChannelManager.Digitals[digitalID].overridden) { for (int j = 0; j < singleChannelBuffer.Length; j++) { singleChannelBuffer[j] = settings.logicalChannelManager.Digitals[digitalID].digitalOverrideValue; } } else { sequence.computeDigitalBuffer(digitalID, timeStepSize, singleChannelBuffer); } // byte digitalBitMask = (byte)(((byte) 2)^ ((byte)lineNum)); for (int j = 0; j < nBaseSamples; j++) { // copy the bit value into the digital buffer byte. if (singleChannelBuffer[j]) digitalBuffer[i, j] |= digitalBitMask; } } digitalBitMask = (byte)(digitalBitMask << 1); } for (int j = nBaseSamples; j < nSamples; j++) { digitalBuffer[i, j] = digitalBuffer[i, j - 1]; } } singleChannelBuffer = null; System.GC.Collect(); DigitalMultiChannelWriter writer = new DigitalMultiChannelWriter(task.Stream); writer.WriteMultiSamplePort(false, digitalBuffer); /// Digital cards report the number of generated samples as a multiple of 4 expectedSamplesGenerated = nSamples; } } #endregion #region Variable timebase buffer creation else // variable timebase buffer creation... { double timeStepSize = 1.0 / (double)deviceSettings.SampleClockRate; TimestepTimebaseSegmentCollection timebaseSegments = sequence.generateVariableTimebaseSegments(serverSettings.VariableTimebaseType, timeStepSize); int nBaseSamples = timebaseSegments.nSegmentSamples(); nBaseSamples++; // add one sample for the dwell sample at the end of the buffer // for reasons that are utterly stupid and frustrating, the DAQmx libraries seem to prefer sample // buffers with lengths that are a multiple of 4. (otherwise they, on occasion, depending on the parity of the // number of channels, throw exceptions complaining. // thus we add a few filler samples at the end of the sequence which parrot back the last sample. int nFillerSamples = 4 - nBaseSamples % 4; if (nFillerSamples == 4) nFillerSamples = 0; int nSamples = nBaseSamples + nFillerSamples; if (deviceSettings.MySampleClockSource == DeviceSettings.SampleClockSource.DerivedFromMaster) { throw new Exception("Attempt to use a uniform sample clock with a variable timebase enabled device. This will not work. To use a variable timebase for this device, you must specify an external sample clock source."); } else { task.Timing.ConfigureSampleClock(deviceSettings.SampleClockExternalSource, deviceSettings.SampleClockRate, deviceSettings.ClockEdge, SampleQuantityMode.FiniteSamples, nSamples); } // Analog first... if (analogIDs.Count != 0) { double[,] analogBuffer; double[] singleChannelBuffer; try { analogBuffer = new double[analogs.Count, nSamples]; singleChannelBuffer = new double[nSamples]; } catch (Exception e) { throw new Exception("Unable to allocate analog buffer for device " + deviceName + ". Reason: " + e.Message + "\n" + e.StackTrace); } for (int i = 0; i < analogIDs.Count; i++) { int analogID = analogIDs[i]; if (settings.logicalChannelManager.Analogs[analogID].TogglingChannel) { getAnalogTogglingBuffer(singleChannelBuffer); } else if (settings.logicalChannelManager.Analogs[analogID].overridden) { for (int j = 0; j < singleChannelBuffer.Length; j++) { singleChannelBuffer[j] = settings.logicalChannelManager.Analogs[analogID].analogOverrideValue; } } else { sequence.computeAnalogBuffer(analogIDs[i], timeStepSize, singleChannelBuffer, timebaseSegments); } for (int j = 0; j < nBaseSamples; j++) { analogBuffer[i, j] = singleChannelBuffer[j]; } for (int j = nBaseSamples; j < nSamples; j++) { analogBuffer[i, j] = analogBuffer[i, j - 1]; } } singleChannelBuffer = null; System.GC.Collect(); AnalogMultiChannelWriter writer = new AnalogMultiChannelWriter(task.Stream); writer.WriteMultiSample(false, analogBuffer); // Analog cards report the exact number of samples generated. for variable timebase this is nBaseSamples expectedSamplesGenerated = nBaseSamples; } if (usedPortNumbers.Count != 0) { byte[,] digitalBuffer; bool[] singleChannelBuffer; try { digitalBuffer = new byte[usedPortNumbers.Count, nSamples]; singleChannelBuffer = new bool[nSamples]; } 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 < usedPortNumbers.Count; i++) { int portNum = usedPortNumbers[i]; byte digitalBitMask = 1; for (int lineNum = 0; lineNum < 8; lineNum++) { int digitalID = port_digital_IDs[portNum][lineNum]; if (digitalID != -1) { if (settings.logicalChannelManager.Digitals[digitalID].TogglingChannel) { getDigitalTogglingBuffer(singleChannelBuffer); } else if (settings.logicalChannelManager.Digitals[digitalID].overridden) { for (int j = 0; j < singleChannelBuffer.Length; j++) { singleChannelBuffer[j] = settings.logicalChannelManager.Digitals[digitalID].digitalOverrideValue; } } else { sequence.computeDigitalBuffer(digitalID, timeStepSize, singleChannelBuffer, timebaseSegments); } // byte digitalBitMask = (byte)(((byte) 2)^ ((byte)lineNum)); for (int j = 0; j < nBaseSamples; j++) { // copy the bit value into the digital buffer byte. if (singleChannelBuffer[j]) digitalBuffer[i, j] |= digitalBitMask; } } digitalBitMask = (byte)(digitalBitMask << 1); } for (int j = nBaseSamples; j < nSamples; j++) { digitalBuffer[i, j] = digitalBuffer[i, j - 1]; } } singleChannelBuffer = null; System.GC.Collect(); DigitalMultiChannelWriter writer = new DigitalMultiChannelWriter(task.Stream); writer.WriteMultiSamplePort(false, digitalBuffer); // digital cards report number of samples generated up to multiple of 4 expectedSamplesGenerated = nSamples; } } #endregion if (deviceSettings.StartTriggerType == DeviceSettings.TriggerType.TriggerIn) { task.Triggers.StartTrigger.ConfigureDigitalEdgeTrigger( deviceSettings.TriggerInPort, DigitalEdgeStartTriggerEdge.Rising); } task.Control(TaskAction.Verify); task.Control(TaskAction.Commit); task.Control(TaskAction.Reserve); return task; }
/* /// <summary> /// This class contains both the analog and the digital tasks returned from a specific device. /// The reason for its existence is that if a device is to have both its analog and its digital outputs used, /// then they must exist in separate tasks. /// </summary> /// public class TaskCollection { public Task analogTask; public Task digitalTask; } */ /* public static Task createVariableTimebaseTask(string digitalTimebaseOutLine, string analogTimebaseOutLine) { }*/ /// /// This method creates a daqMX task for an "output now" command, and starts the output. /// </summary> /// <param name="deviceName"></param> /// <param name="settings"></param> /// <param name="output"></param> /// <returns></returns> public static Task createDaqMxTaskAndOutputNow(string deviceName, DeviceSettings deviceSettings, SingleOutputFrame output, SettingsData settings, Dictionary<int, HardwareChannel> usedDigitalChannels, Dictionary<int, HardwareChannel> usedAnalogChannels) { Task task = new Task(deviceName + " output task"); List<int> analogIDs; List<HardwareChannel> analogs; Dictionary<int, int[]> port_digital_IDs; List<int> usedPortNumbers; // Parse and create channels. parseAndCreateChannels(deviceName,deviceSettings, usedDigitalChannels, usedAnalogChannels, task, out analogIDs, out analogs, out port_digital_IDs, out usedPortNumbers); // now create buffer. task.Timing.SampleTimingType = SampleTimingType.OnDemand; // analog output if (analogIDs.Count != 0) { // extract a list of analog values corresponding to the list analodIDs. This is // sorted in the same way as the channels were created in parseAndCreateChannels List<double> outputValues = new List<double>(); foreach (int analogID in analogIDs) { double val; if (output.analogValues.ContainsKey(analogID)) val = output.analogValues[analogID]; else val = 0; outputValues.Add(val); } AnalogMultiChannelWriter writer = new AnalogMultiChannelWriter(task.Stream); writer.WriteSingleSample(true, outputValues.ToArray()); } // digital output if (usedPortNumbers.Count != 0) { List<byte> outputValues = new List<byte>(); foreach (int portNumber in usedPortNumbers) { byte digitalMask = 1; byte value=0; for (int lineNum = 0; lineNum < 8; lineNum++) { int digitalID = port_digital_IDs[portNumber][lineNum]; if (digitalID != -1) { bool val = false; if (output.digitalValues.ContainsKey(digitalID)) val = output.digitalValues[digitalID]; if (val) value |= digitalMask; } digitalMask = (byte) (digitalMask << 1); } outputValues.Add(value); } DigitalMultiChannelWriter writer = new DigitalMultiChannelWriter(task.Stream); writer.WriteSingleSamplePort(true, outputValues.ToArray()); } return task; }
public RfsgTask(SequenceData sequence, SettingsData settings, int channelID, string rfsgDeviceName, DeviceSettings deviceSettings) { if (!settings.logicalChannelManager.GPIBs.ContainsKey(channelID)) { throw new InvalidDataException("Attempted to create an rfsg task with channel id " + channelID + ", which does not exist in the settings as a gpib channel."); } this.channelID = channelID; int currentStepIndex = -1; //measured in ticks. 1 tick = 100 ns. long currentTime = 0; commandBuffer = new List<RFSGCommand>(); if (deviceSettings.AutoInitate) { RFSGCommand com = new RFSGCommand(); com.commandTime = 0; com.commandType = RFSGCommand.CommandType.Initiate; commandBuffer.Add(com); } if (deviceSettings.AutoEnable) { RFSGCommand com = new RFSGCommand(); com.commandTime = 0; com.commandType = RFSGCommand.CommandType.EnableOutput; commandBuffer.Add(com); } 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; if (currentStep.GpibGroup == null || !currentStep.GpibGroup.channelEnabled(channelID)) { currentTime += seconds_to_ticks(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, channelID); long groupDuration = seconds_to_ticks(sequence.timeBetweenSteps(currentStepIndex, nextEnabledStepIndex)); // now take action: GPIBGroupChannelData channelData = currentStep.GpibGroup.getChannelData(channelID); if (channelData.DataType == GPIBGroupChannelData.GpibChannelDataType.raw_string) { throw new Exception("Not yet implemented."); /* // Raw string commands just get added string stringWithCorrectNewlines = AddNewlineCharacters(channelData.RawString); commandBuffer.Add(new GpibCommand(stringWithCorrectNewlines, currentTime));*/ } else if (channelData.DataType == GPIBGroupChannelData.GpibChannelDataType.voltage_frequency_waveform) { double[] amplitudeArray; double[] frequencyArray; // get amplitude and frequency value arrays int nSamples = (int)(ticks_to_seconds(groupDuration) * (double)deviceSettings.SampleClockRate); double secondsPerSample = ticks_to_seconds(groupDuration) / (double)nSamples; amplitudeArray = channelData.volts.getInterpolation(nSamples, 0, ticks_to_seconds(groupDuration), sequence.Variables, sequence.CommonWaveforms); frequencyArray = channelData.frequency.getInterpolation(nSamples, 0, ticks_to_seconds(groupDuration), sequence.Variables, sequence.CommonWaveforms); double lastFreq = Double.MinValue; double lastAmp = Double.MinValue; for (int i = 0; i < nSamples; i++) { double currentFreq = frequencyArray[i]; double currentAmp = amplitudeArray[i]; if (currentFreq != lastFreq || currentAmp != lastAmp) { RFSGCommand command = new RFSGCommand(); command.commandType = RFSGCommand.CommandType.AmplitudeFrequency; command.frequency = currentFreq; command.amplitude = Vpp_to_dBm(currentAmp); command.commandTime = (long)(currentTime + i * secondsPerSample * 10000000) + postTime; commandBuffer.Add(command); } lastAmp = currentAmp; lastFreq = currentFreq; } } else if (channelData.DataType == GPIBGroupChannelData.GpibChannelDataType.string_param_string) { foreach (StringParameterString sps in channelData.StringParameterStrings) { string clean = sps.Prefix.Trim().ToUpper(); if (clean == "ENABLE") { RFSGCommand com = new RFSGCommand(); com.commandType = RFSGCommand.CommandType.EnableOutput; com.commandTime = currentTime + postTime; commandBuffer.Add(com); } if (clean == "DISABLE") { RFSGCommand com = new RFSGCommand(); com.commandType = RFSGCommand.CommandType.DisableOutput; com.commandTime = currentTime + postTime; commandBuffer.Add(com); } if (clean == "ABORT") { RFSGCommand com = new RFSGCommand(); com.commandType = RFSGCommand.CommandType.Abort; com.commandTime = currentTime + postTime; commandBuffer.Add(com); } if (clean == "INITIATE") { RFSGCommand com = new RFSGCommand(); com.commandType = RFSGCommand.CommandType.Initiate; com.commandTime = currentTime + postTime; commandBuffer.Add(com); } } } currentTime += seconds_to_ticks(currentStep.StepDuration.getBaseValue()); } if (rfsgDevices == null) { rfsgDevices = new Dictionary<string, niRFSG>(); rfsgDeviceInitiated = new Dictionary<niRFSG, bool>(); } if (rfsgDevices.ContainsKey(rfsgDeviceName)) { rfsgDevice = rfsgDevices[rfsgDeviceName]; } else { try { rfsgDevice = new niRFSG(rfsgDeviceName, true, false); } catch (Exception e) { throw new InvalidDataException("Caught exception when attempting to instantiate an rfsg device named " + rfsgDeviceName + ". Maybe a device by this name does not exist? Exception message: " + e.Message); } rfsgDevices.Add(rfsgDeviceName, rfsgDevice); rfsgDeviceInitiated.Add(rfsgDevice, false); } if (deviceSettings.MasterTimebaseSource != null && deviceSettings.MasterTimebaseSource != "") { rfsgDevice.ConfigureRefClock(deviceSettings.MasterTimebaseSource, 10000000); } }