/// <summary>
        /// Returns the number of variable values that changed.
        /// </summary>
        /// <param name="sequence"></param>
        /// <returns></returns>
        public int refresh(SequenceData sequence)
        {
            Func<int> refreshFunc = () =>
            {
                int ans = 0;
                foreach (VariablePreviewEditor ed in eds)
                {
                    if (ed.refresh())
                        ans++;
                }

                // Force the sequence to re-calculate all equation based derived variables, with this
                // line of code that ends up calling setIterationNumber in sequence data
                sequence.ListIterationNumber = sequence.ListIterationNumber;

                foreach (VariablePreviewEditor ed in eds)
                {
                    ed.refresh();
                }

                return ans;
            };

            return (int) Invoke(refreshFunc);
        }
        public int refresh(SequenceData sequence)
        {
            if (this.InvokeRequired)
            {
                intSeqDelegate myDelegate = new intSeqDelegate(this.refresh);
                IAsyncResult result = this.BeginInvoke(myDelegate, new object [] {sequence});
                return (int) this.EndInvoke(result);
            }
            else
            {
                int ans = 0;
                foreach (VariablePreviewEditor ed in eds)
                {
                    if (ed.refresh())
                        ans++;
                }

                // Force the sequence to re-calculate all equation based derived variables, with this
                // line of code that ends up calling setIterationNumber in sequence data
                sequence.ListIterationNumber = sequence.ListIterationNumber;

                foreach (VariablePreviewEditor ed in eds)
                {
                    ed.refresh();
                }

                return ans;
            }
        }
 public void SequenceDataConstructorTest()
 {
     SequenceData target = new SequenceData();
     Assert.IsTrue(target.VersionNumberAtFirstCreation.isValid(),
         "Invalid/unparseable version number in DataStructures. Please" +
         " ensure DataStructures version number string is of the form" +
         " X.YZ");
 }
 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 WatchdogTimerTask(SequenceData sequence, int masterFrequency, NationalInstruments.DAQmx.Task taskToWatch,  double watchDogThresholdTime)
        {
            this.taskToWatch = taskToWatch;
            TimestepTimebaseSegmentCollection segments = sequence.generateVariableTimebaseSegments(SequenceData.VariableTimebaseTypes.AnalogGroupControlledVariableFrequencyClock,
                                         1.0 / ((double)masterFrequency));

            int currentSequenceSampleNumber = 0;
            long currentMasterSampleNumber=0;
            watchdogTimerSegments = new List<WatchdogTimerSegment>();

            int thresholdTime = (int)(masterFrequency*watchDogThresholdTime);

            for (int i = 0; i < sequence.TimeSteps.Count; i++)
            {
                TimeStep step = sequence.TimeSteps[i];
                if (step.StepEnabled)
                {

                    bool stepUsed = false;
                    if (segments.ContainsKey(step))
                    {
                        List<SequenceData.VariableTimebaseSegment> segmentList = segments[step];
                        for (int j = 0; j < segmentList.Count; j++)
                        {
                            SequenceData.VariableTimebaseSegment currentSegment = segmentList[j];

                            if (currentSegment.MasterSamplesPerSegmentSample >= thresholdTime)
                            {
                                if (!stepUsed)
                                {
                                    WatchdogTimerSegment wseg = new WatchdogTimerSegment();
                                    wseg.timeStepName = step.StepName;
                                    wseg.timeStepID = i;
                                    wseg.sequenceSampleNumber = currentSequenceSampleNumber + 1;
                                    wseg.masterSampleNumber = currentMasterSampleNumber + thresholdTime / 2;
                                    stepUsed = true;

                                    watchdogTimerSegments.Add(wseg);
                                }
                            }

                            currentSequenceSampleNumber += currentSegment.NSegmentSamples;
                            currentMasterSampleNumber += currentSegment.NSegmentSamples * currentSegment.MasterSamplesPerSegmentSample;
                        }

                    }
                }

            }
        }
        public FpgaTimebaseTask(DeviceSettings deviceSettings, okCFrontPanel opalKellyDevice, SequenceData sequence, double masterClockPeriod, out int nSegments, bool useRfModulation, bool assymetric)
            : base()
        {
            com.opalkelly.frontpanel.okCFrontPanel.ErrorCode errorCode;

            this.opalKellyDevice = opalKellyDevice;

            this.masterClockPeriod = masterClockPeriod;

            TimestepTimebaseSegmentCollection segments = sequence.generateVariableTimebaseSegments(SequenceData.VariableTimebaseTypes.AnalogGroupControlledVariableFrequencyClock,
                                                        masterClockPeriod);

            this.max_elapsedtime_ms = (UInt32)((sequence.SequenceDuration * 1000.0) + 100);

            byte[] data = FpgaTimebaseTask.createByteArray(segments, sequence, out nSegments, masterClockPeriod, assymetric );

            // Send the device an abort trigger.
            errorCode = opalKellyDevice.ActivateTriggerIn(0x40, 1);
            if (errorCode != okCFrontPanel.ErrorCode.NoError)
            {
                throw new Exception("Unable to set abort trigger to FPGA device. Error code " + errorCode.ToString());
            }

            UInt16 wireInValue = 0;
            if (deviceSettings.StartTriggerType != DeviceSettings.TriggerType.SoftwareTrigger)
            {
                wireInValue += 1;
            }

            if (useRfModulation)
            {
                wireInValue += 2;
            }

            setWireInValue(0x00, wireInValue);

            setWireInValue(0x01, deviceSettings.RetriggerDebounceSamples);

            opalKellyDevice.UpdateWireIns();

            // pipe the byte stream to the device
            int xfered = opalKellyDevice.WriteToPipeIn(0x80, data.Length, data);
            if (xfered != data.Length)
            {
                throw new Exception("Error when piping clock data to FPGA device. Sent " + xfered + " bytes instead of " + data.Length + "bytes.");
            }
        }
        public void usedVariablesTest()
        {
            SequenceData target = new SequenceData(); // TODO: Initialize to an appropriate value
            Assert.AreEqual(0, target.usedVariables().Count);

            target.Variables.Add(new Variable());
            target.Variables[0].VariableName = "Variable Name";
            Assert.AreEqual(0, target.usedVariables().Count); // Unused variables in variable list should still not appear

            target.TimeSteps.Add(new TimeStep());
            target.TimeSteps[0].StepDuration.parameter.variable = target.Variables[0];
            Assert.AreEqual(1, target.usedVariables().Count); // Unused variables in variable list should still not appear

            target.TimeSteps.Add(new TimeStep());
            target.TimeSteps[1].StepDuration.parameter.variable = target.Variables[0];
            Assert.AreEqual(1, target.usedVariables().Count); // Variables should not appear duplicate times even if used in several places
        }
 public static string applySequenceMode(SequenceData sequence, SequenceMode genre)
 {
     string ans = "";
     foreach (TimeStep step in sequence.TimeSteps)
     {
         if (!genre.TimestepEntries.ContainsKey(step))
         {
             ans += "No mode entry for [" + step.StepName + "]. ";
         }
         else
         {
             step.StepHidden = genre.TimestepEntries[step].StepHidden;
             step.StepEnabled = genre.TimestepEntries[step].StepEnabled;
         }
     }
     if (ans == "")
         return null;
     else
         return ans;
 }
        private void backgroundRunUpdated(object o, EventArgs e)
        {
            if (!RunForm.backgroundIsRunning() && queuedNextSequence != null)
            {
                RunForm.beginBackgroundRunAsLoop(queuedNextSequence, RunForm.RunType.Run_Iteration_Zero, true, new EventHandler(backgroundRunUpdated));
                queuedNextSequence = null;
                backgroundRunUpdated(this, null);
                return;
            }

            if (this.InvokeRequired)
                this.BeginInvoke(new EventHandler(backgroundRunUpdated), new object[] {this, null});
            else
            {
                if (RunForm.backgroundIsRunning())
                {
                    bgRunButton.Text = "Queue as Loop in Background";
                }
                else
                {
                    bgRunButton.Text = "Run as Loop in Background (^F9)";
                }
            }
        }
        private void setCalibrationSequence(SequenceData calibrationShotSequence)
        {
            Storage.sequenceData.calibrationShotsInfo.CalibrationShotSequence = calibrationShotSequence;
            if (Storage.sequenceData.calibrationShotsInfo.CalibrationShotSequence != null)
            {
                if (!Storage.sequenceData.calibrationShotsInfo.CalibrationShotSequence.Lists.ListLocked)
                {
                    MessageBox.Show("The sequence you have specified for use as a calibration shot does not have its lists locked, and therefore will not be usable as a calibration shot. To use this file as a calibration shot, lock its lists.", "Unable to use calibration shot with unlocked lists.");
                    Storage.sequenceData.calibrationShotsInfo.CalibrationShotSequence = null;

                }
                else
                    Storage.sequenceData.calibrationShotsInfo.CalibrationShotSequence.CalibrationShot = true;
            }
            layoutCalibrationUI();
        }
        public RunForm(SequenceData sequenceToRun)
        {
            this.runningSequence = sequenceToRun;
            if (WordGenerator.MainClientForm.instance.studentEdition)
            {
                MessageBox.Show("Your Cicero Professional Edition (C) License expired on March 31. You are now running a temporary 24 hour STUDENT EDITION license. Please see http://web.mit.edu/~akeshet/www/Cicero/apr1.html for license renewal information.", "License expired -- temporary STUDENT EDITION license.");
            }

            IPAddress lclhst = null;
            IPEndPoint ipe = null;
            CameraPCsSocketList = new List<Socket>();
            connectedPCs = new List<SettingsData.IPAdresses>();
            bool errorOccured = false;
            foreach (SettingsData.IPAdresses ipAdress in Storage.settingsData.CameraPCs)
            {
                errorOccured = false;
                if (ipAdress.inUse)
                {
                    try
                    {

                        lclhst = Dns.GetHostEntry(ipAdress.pcAddress).AddressList[0];
                        ipe = new IPEndPoint(lclhst, ipAdress.Port);
                        CameraPCsSocketList.Add(new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp));

                        CameraPCsSocketList[CameraPCsSocketList.Count - 1].Blocking = false;
                        CameraPCsSocketList[CameraPCsSocketList.Count - 1].SendTimeout = 100;
                        CameraPCsSocketList[CameraPCsSocketList.Count - 1].ReceiveTimeout = 100;

                    }
                    catch
                    {
                        errorOccured = true;
                    }
                    if (errorOccured)
                        continue;
                    else
                    {
                        connectedPCs.Add(ipAdress);
                        try
                        {
                            CameraPCsSocketList[CameraPCsSocketList.Count - 1].Connect(ipe);
                        }
                        catch { }
                    }
                }
            }

            if (Storage.settingsData.CameraPCs.Count != 0)
            {
                getConfirmationThread = new Thread(new ThreadStart(getConfirmationEntryPoint));
                getConfirmationThread.Start();
            }
            // Supress hotkeys in main form when this form is runnings. This will be cleared when the run form closes.
            WordGenerator.MainClientForm.instance.suppressHotkeys = true;

            InitializeComponent();
            runFormStatus = RunFormStatus.Inactive;
            formCreationTime = DateTime.Now;

            // hotkey registration
            hotkeyButtons = new Dictionary<int, Button>();

            // fortune cookie
            if (WordGenerator.MainClientForm.instance.fortunes != null)
            {
                List<string> forts = WordGenerator.MainClientForm.instance.fortunes;
                Random rand = new Random();
                fortuneCookieLabel.Text = forts[rand.Next(forts.Count - 1)];
            }
        }
        /// <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);
            }
        }
 public override bool setSequence(SequenceData sequence)
 {
     lock (remoteLockObj)
     {
         messageLog(this, new MessageEvent("Received sequence."));
         this.sequence = sequence;
         return true;
     }
 }
        public string insertSequence(SequenceData insertMe, TimeStep insertAfter)
        {
            int index = -1;
            for (int i=0; i<TimeSteps.Count; i++) {
                if (insertAfter == TimeSteps[i]) {
                    index = i;
                    break;
                }
            }

            return insertSequence(insertMe, index + 1);
        }
 public ServerActionStatus setSequenceOnConnectedServers(SequenceData sequence, EventHandler<MessageEvent> messageLog)
 {
     return runNamedMethodOnConnectedServers("setSequence", new object[] { sequence }, 4000, messageLog);
 }
        /// <summary>
        /// Create byte array for use in programming FPGA
        /// </summary>
        /// <param name="segments"></param>
        /// <param name="sequence"></param>
        /// <param name="nSegments"></param>
        /// <param name="masterClockPeriod"></param>
        /// <param name="assymetric"></param>
        /// <returns></returns>
        private static byte[] createByteArray(TimestepTimebaseSegmentCollection segments,
            SequenceData sequence, out int nSegments, double masterClockPeriod, bool assymetric)
        {
            List<ListItem> listItems = new List<ListItem>();

            for (int stepID = 0; stepID < sequence.TimeSteps.Count; stepID++)
            {
                if (sequence.TimeSteps[stepID].StepEnabled)
                {
                    if (sequence.TimeSteps[stepID].RetriggerOptions.WaitForRetrigger)
                    {
                        uint waitTime = (uint)(sequence.TimeSteps[stepID].RetriggerOptions.RetriggerTimeout.getBaseValue() / masterClockPeriod);

                        uint retriggerFlags = 0;
                        if (sequence.TimeSteps[stepID].RetriggerOptions.RetriggerOnEdge)
                            retriggerFlags += 1;
                        if (!sequence.TimeSteps[stepID].RetriggerOptions.RetriggerOnNegativeValueOrEdge)
                            retriggerFlags += 2;

                        listItems.Add(new ListItem(waitTime, retriggerFlags, 0));
                               // counts = 0 is a special signal for WAIT_FOR_RETRIGGER mode
                               // in this mode, FPGA waits a maximum of on_counts master samples
                               // before moving on anyway.
                               // (unless on_counts = 0, in which case it never artificially retriggers)
                                // retrigger flags set if the FPGA will trigger on edge or on value
                                // and whether to trigger on positive or negative (edge or value)
                    }

                    List<SequenceData.VariableTimebaseSegment> stepSegments = segments[sequence.TimeSteps[stepID]];
                    for (int i = 0; i < stepSegments.Count; i++)
                    {
                        ListItem item = new ListItem();
                        SequenceData.VariableTimebaseSegment currentSeg = stepSegments[i];

                        item.repeats = (uint)currentSeg.NSegmentSamples;
                        item.offCounts = (uint)(currentSeg.MasterSamplesPerSegmentSample / 2);
                        item.onCounts = (uint)(currentSeg.MasterSamplesPerSegmentSample - item.offCounts);

                        // in assymmetric mode (spelling?), the clock duty cycle is not held at 50%, but rather the pulses are made to be
                        // 5 master cycles long at most. This is a workaround for the weird behavior of one of our fiber links
                        // for sharing the variable timebase signal.
                        if (assymetric)
                        {
                            if (item.onCounts > 5)
                            {
                                uint difference = item.onCounts - 5;
                                item.onCounts = 5;
                                item.offCounts = item.offCounts + difference;
                            }
                        }

                        if (!item.isAllZeros())
                        { // filter out any erroneously produced all-zero codes, since these have
                            // special meaning to the FPGA (they are "wait for retrigger" codes
                            listItems.Add(item);
                        }
                    }
                }
            }

            // Add one final "pulse" at the end to trigger the dwell values. I'm basing this off the
            // old variable timebase code that I found in the SequenceData program.

            // This final pulse is made to be 100 us long at least, just to be on the safe side. (unless assymetric mode is on)

            int minCounts = (int)(0.0001 / masterClockPeriod);
            if (minCounts <= 0)
                minCounts = 1;

            ListItem finishItem = new ListItem((uint)minCounts, (uint)minCounts, 1);

            if (assymetric)
            {
                finishItem.onCounts = 5;
            }

            listItems.Add(finishItem);

            nSegments = listItems.Count;

            byte[] byteArray = new byte[listItems.Count * 16];

            // This loop goes through the list items and creates
            // the data as it is to be sent to the FPGA
            // the data is a little shuffled because
            // of the details of the byte order in
            // piping data to the fpga.

            // Each list item takes up 16 bytes in the output FIFO.
            for (int i = 0; i < listItems.Count; i++)
            {
                ListItem item = listItems[i];

                byte[] onb = splitIntToBytes(item.onCounts);
                byte[] offb = splitIntToBytes(item.offCounts);
                byte[] repb = splitIntToBytes(item.repeats);

                int offs = 16 * i;

                byteArray[offs + 2] = onb[1];
                byteArray[offs + 3] = onb[0];
                byteArray[offs + 4] = onb[3];
                byteArray[offs + 5] = onb[2];

                byteArray[offs + 8] = offb[1];
                byteArray[offs + 9] = offb[0];
                byteArray[offs + 10] = offb[3];
                byteArray[offs + 11] = offb[2];

                byteArray[offs + 12] = repb[1];
                byteArray[offs + 13] = repb[0];
                byteArray[offs + 14] = repb[3];
                byteArray[offs + 15] = repb[2];
            }

            return byteArray;
        }
        public void cleanupUnusedEntries(SequenceData sequence)
        {
            List<TimeStep> stepsToRemove = new List<TimeStep>();
            foreach (TimeStep step in TimestepEntries.Keys)
            {
                if (!sequence.TimeSteps.Contains(step))
                    stepsToRemove.Add(step);
            }

            foreach (TimeStep step in stepsToRemove)
            {
                TimestepEntries.Remove(step);
            }
        }
 public static SequenceMode createSequenceMode(SequenceData sequence)
 {
     SequenceMode ans = new SequenceMode();
     foreach (TimeStep step in sequence.TimeSteps)
     {
         ans.TimestepEntries.Add(step, new ModeEntry(step.StepEnabled, step.StepHidden));
     }
     return ans;
 }
        public bool generateBuffer(SequenceData sequence, DeviceSettings deviceSettings, HardwareChannel hc, int logicalChannelID)
        {
            this.logicalChannelID = logicalChannelID;

            commandBuffer = new List<RS232Command>();

            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;

               // 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.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));
               }
               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));
                       }
                   }
               }

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

               return true;
        }
 public override bool setSequence(SequenceData sequence)
 {
     return true;
 }
        public static byte[] createByteArray(TimestepTimebaseSegmentCollection segments,
            SequenceData sequence, out int nSegments, double masterClockPeriod, bool assymetric)
        {
            List<ListItem> listItems = new List<ListItem>();

            for (int stepID = 0; stepID < sequence.TimeSteps.Count; stepID++)
            {
                if (sequence.TimeSteps[stepID].StepEnabled)
                {
                    if (sequence.TimeSteps[stepID].WaitForRetrigger)
                    {
                        listItems.Add(new ListItem(0, 0, 0)); // 0,0,0 list item is code for "wait for retrigger
                                                              // FPGA knows how to handle this
                    }

                    List<SequenceData.VariableTimebaseSegment> stepSegments = segments[sequence.TimeSteps[stepID]];
                    for (int i = 0; i < stepSegments.Count; i++)
                    {
                        ListItem item = new ListItem();
                        SequenceData.VariableTimebaseSegment currentSeg = stepSegments[i];

                        item.repeats = currentSeg.NSegmentSamples;
                        item.offCounts = currentSeg.MasterSamplesPerSegmentSample / 2;
                        item.onCounts = currentSeg.MasterSamplesPerSegmentSample - item.offCounts;

                        // in assymmetric mode (spelling?), the clock duty cycle is not held at 50%, but rather the pulses are made to be
                        // 5 master cycles long at most. This is a workaround for the weird behavior of one of our fiber links
                        // for sharing the variable timebase signal.
                        if (assymetric)
                        {
                            if (item.onCounts > 5)
                            {
                                int difference = item.onCounts - 5;
                                item.onCounts = 5;
                                item.offCounts = item.offCounts + difference;
                            }
                        }

                        if (!item.isAllZeros())
                        { // filter out any erroneously produced all-zero codes, since these have
                            // special meaning to the FPGA (they are "wait for retrigger" codes
                            listItems.Add(item);
                        }
                    }
                }
            }

            // Add one final "pulse" at the end to trigger the dwell values. I'm basing this off the
            // old variable timebase code that I found in the SequenceData program.

            // This final pulse is made to be 100 us long at least, just to be on the safe side. (unless assymetric mode is on)

            int minCounts = (int)(0.0001 / masterClockPeriod);
            if (minCounts <= 0)
                minCounts = 1;

            ListItem finishItem = new ListItem(minCounts, minCounts, 1);

            if (assymetric)
            {
                finishItem.onCounts = 5;
            }

            listItems.Add(finishItem);

            nSegments = listItems.Count;

            byte[] byteArray = new byte[listItems.Count * 16];

            // This loop goes through the list items and creates
            // the data as it is to be sent to the FPGA
            // the data is a little shuffled because
            // of the details of the byte order in
            // piping data to the fpga.
            for (int i = 0; i < listItems.Count; i++)
            {
                ListItem item = listItems[i];

                byte[] onb = splitIntToBytes(item.onCounts);
                byte[] offb = splitIntToBytes(item.offCounts);
                byte[] repb = splitIntToBytes(item.repeats);

                int offs = 16 * i;

                byteArray[offs + 2] = onb[1];
                byteArray[offs + 3] = onb[0];
                byteArray[offs + 4] = onb[3];
                byteArray[offs + 5] = onb[2];

                byteArray[offs + 8] = offb[1];
                byteArray[offs + 9] = offb[0];
                byteArray[offs + 10] = offb[3];
                byteArray[offs + 11] = offb[2];

                byteArray[offs + 12] = repb[1];
                byteArray[offs + 13] = repb[0];
                byteArray[offs + 14] = repb[3];
                byteArray[offs + 15] = repb[2];
            }

            return byteArray;
        }
 /// <summary>
 /// Sets the sequence which is to be run.
 /// </summary>
 /// <param name="sequence"></param>
 public abstract bool setSequence(SequenceData sequence);
 private void bgRunButton_Click(object sender, EventArgs e)
 {
     if (!Storage.sequenceData.Lists.ListLocked)
     {
         MessageBox.Show("The current sequence does not have its lists locked, and thus cannot be run in the background. Please lock the lists (in the Variables tab).", "Lists not locked, unable to run in background.");
         return;
     }
     SequenceData sequenceCopy = (SequenceData)Common.createDeepCopyBySerialization(Storage.sequenceData);
     if (RunForm.backgroundIsRunning())
     {
         RunForm.bringBackgroundRunFormToFront();
         queuedNextSequence = sequenceCopy;
         RunForm.abortAtEndOfNextBackgroundRun();
     }
     else
     {
         RunForm.beginBackgroundRunAsLoop(sequenceCopy, RunForm.RunType.Run_Iteration_Zero, true, new EventHandler(backgroundRunUpdated));
     }
     backgroundRunUpdated(this, null);
 }
        private void saveMarked_Click(object sender, EventArgs e)
        {
            List<TimeStep> markedSteps = markedTimesteps();

            if (markedSteps.Count == 0)
            {
                MessageBox.Show("Unable to save marked timesteps, as no timesteps are marked.");
            }

            SequenceData saveMe = new SequenceData(markedSteps);

            Storage.SaveAndLoad.SaveSequenceData(null, saveMe);
        }
        public string insertSequence(SequenceData insertMe, int insertIndex)
        {
            bool specialUsed = false;
            Dictionary<Variable, string> temp = insertMe.usedVariables();
            foreach (Variable var in temp.Keys)
            {
                if (var.IsSpecialVariable)
                    specialUsed = true;
            }

            commonWaveforms.AddRange(insertMe.commonWaveforms);
            analogGroups.AddRange(insertMe.analogGroups);
            rs232Groups.AddRange(insertMe.rs232Groups);
            gpibGroups.AddRange(insertMe.gpibGroups);
            variables.AddRange(insertMe.variables);
            DigitalPulses.AddRange(insertMe.DigitalPulses);
            TimestepGroups.AddRange(insertMe.TimestepGroups);

            this.TimeSteps.InsertRange(insertIndex, insertMe.TimeSteps);

            this.cleanupSpecialVariables();

            if (specialUsed)
            {
                return "Warning: the inserted sequence made use of a \"Special Variable\" (iterCount, iterNum, etc.). The special variables used in the inserted sequence are now likely to be bound incorrectly. Please check the variables used in the inserted part of the sequence.";
            }
            else
            {
                return null;
            }
        }
        /// <summary>
        /// This function should be called after SequenceData is loaded, or if it is changed by a non-UI element.
        /// This is a slow function, it effectively causes all of the controls which lay themselves out based on SequenceData
        /// to be re-drawn. Thus, it should not be called unnecessarily.
        /// </summary>
        public void RefreshSequenceDataToUI(SequenceData sequenceData)
        {
            WordGenerator.mainClientForm.instance.cursorWait();

                lic_chk();

                this.commonWaveformEditor1.setCommonWaveforms(Storage.sequenceData.CommonWaveforms);

                if (sequenceData.AnalogGroups.Count != 0)
                    this.analogGroupEditor1.setAnalogGroup(sequenceData.AnalogGroups[0]);
                else
                    this.analogGroupEditor1.setAnalogGroup(null);

                this.sequencePage1.layoutAll();

                this.variablesEditor1.layout();

                if (sequenceData.GpibGroups.Count != 0)
                    this.gpibGroupEditor1.setGpibGroup(sequenceData.GpibGroups[0]);
                else
                    this.gpibGroupEditor1.setGpibGroup(null);

                if (sequenceData.RS232Groups.Count != 0)
                    this.rS232GroupEditor1.setRS232Group(sequenceData.RS232Groups[0]);
                else
                    this.rS232GroupEditor1.setRS232Group(null);

                this.analogGroupEditor1.updateRunOrderPanel();
                this.gpibGroupEditor1.updateRunOrderPanel();

                updateFormTitle();

                if (!Storage.sequenceData.TimeSteps.Contains(CurrentlyOutputtingTimestep))
                {
                    CurrentlyOutputtingTimestep = null;
                }

                pulsesPage1.layout();

                sequencePage1.forceUpdateAllScrollbars();

                setTimestepEditorBackgrounds();

                waitForReady.Checked = Storage.sequenceData.WaitForReady;

                WordGenerator.mainClientForm.instance.cursorWaitRelease();
        }
        /// <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;
        }
Example #28
0
            public static void SaveSequenceData(string path, SequenceData sequence)
            {
                if (path == null)
                {
                    path = SharedForms.PromptSaveFile(FileNameStrings.FriendlyNames.SequenceData, FileNameStrings.Extensions.SequenceData);
                }

                if (path != null)
                {
                    Save(path, sequence);
                    if (sequence == sequenceData)
                        WordGenerator.mainClientForm.instance.OpenSequenceFileName = path;
                    clientStartupSettings.AddNewFile(path);
                }
            }
        /// <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,
                1.0 / (double)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;
        }
        public bool do_run(int iterationNumber, SequenceData sequence, bool calibrationShot)
        {
            this.runningThread = Thread.CurrentThread;
            bool keepGoing = true;
            while (keepGoing)
            {
                MainClientForm.instance.CurrentlyOutputtingTimestep = null;

                setStatus(RunFormStatus.StartingRun);

                lic_chk();

                if (RunForm.backgroundIsRunning() && !this.isBackgroundRunform)
                {
                    addMessageLogText(this, new MessageEvent("A background run is still running. Waiting for it to terminate..."));
                    RunForm.abortAtEndOfNextBackgroundRun();
                    setStatus(RunFormStatus.ClosableOnly);
                    while (RunForm.backgroundIsRunning())
                    {
                        Thread.Sleep(50);
                    }

                    if (this.IsDisposed)
                    {
                        addMessageLogText(this, new MessageEvent("Foreground run form was closed before background run terminated. Aborting foreground run."));
                        return false;
                    }

                    setStatus(RunFormStatus.StartingRun);

                }

                addMessageLogText(this, new MessageEvent("Starting Run."));

                updateTitleBar(calibrationShot);

                // Begin section of undocumented Paris code that Aviv doesn't understand.
                bool wrongSavePath = false;
                try
                {
                    if (Storage.settingsData.SavePath != "")
                        System.IO.Directory.GetFiles(Storage.settingsData.SavePath);

                }
                catch
                {
                    wrongSavePath = true;
                }

                if (wrongSavePath)
                {
                    addMessageLogText(this, new MessageEvent("Unable to locate save path. Aborting run. See the SavePath setting (under Advanced->Settings Explorer)."));

                    setStatus(RunFormStatus.FinishedRun);
                    return false;
                }
                // End section of undocumented Paris code that Aviv doesn't understand

                if (!sequence.Lists.ListLocked)
                {
                    if (calibrationShot)
                    {
                        addMessageLogText(this, new MessageEvent("Calibration shot error -- Lists in the calibration shot are not locked. They must be locked manually. Please open your calibration sequence file, lock the lists, save your calibration sequence, and then re-import the calibration shot in this sequence."));
                        addMessageLogText(this, new MessageEvent("Skipping calibration shot and aborting run as a result of previous error."));
                        ErrorDetected = true;
                        setStatus(RunFormStatus.FinishedRun);
                        return false;
                    }

                    addMessageLogText(this, new MessageEvent("Lists not locked, attempting to lock them..."));

                    WordGenerator.MainClientForm.instance.variablesEditor.tryLockLists();

                    if (!sequence.Lists.ListLocked)
                    {
                        addMessageLogText(this, new MessageEvent("Unable to lock lists. Aborting run. See the Variables tab."));
                        ErrorDetected = true;

                        setStatus(RunFormStatus.FinishedRun);
                        return false;
                    }
                    addMessageLogText(this, new MessageEvent("Lists locked successfully."));
                }

                sequence.ListIterationNumber = iterationNumber;

                string listBoundVariableValues = "";

                foreach (Variable var in sequence.Variables)
                {
                    if (Storage.settingsData.PermanentVariables.ContainsKey(var.VariableName))
                    {
                        var.PermanentVariable = true;
                        var.PermanentValue = Storage.settingsData.PermanentVariables[var.VariableName];
                    }
                    else
                    {
                        var.PermanentVariable = false;
                    }
                }

                foreach (Variable var in sequence.Variables)
                {

                    if (var.ListDriven && !var.PermanentVariable)
                    {
                        if (listBoundVariableValues == "")
                        {
                            listBoundVariableValues = "List bound variable values: ";
                        }
                        listBoundVariableValues += var.VariableName + " = " + var.VariableValue.ToString() + ", ";
                    }
                }

                if (listBoundVariableValues != "")
                {
                    addMessageLogText(this, new MessageEvent(listBoundVariableValues));
                }

                foreach (Variable var in sequence.Variables)
                {
                    if (var.DerivedVariable)
                    {
                        if (var.parseVariableFormula(sequence.Variables) != null)
                        {
                            addMessageLogText(this, new MessageEvent("Warning! Derived variable " + var.ToString() + " has an an error. Will default to 0 for this run."));
                            ErrorDetected = true;
                        }
                    }
                }
                if (!calibrationShot)
                {
                    foreach (Variable var in sequence.Variables)
                    {
                        if (var.VariableName == "SeqMode")
                        {
                            addMessageLogText(this, new MessageEvent("Detected a variable with special name SeqMode. Nearest integer value " + (int)var.VariableValue + "."));
                            int i = (int)var.VariableValue;
                            if (i >= 0 && i < runningSequence.SequenceModes.Count)
                            {
                                SequenceMode mode = runningSequence.SequenceModes[i];
                                if (runningSequence == Storage.sequenceData)
                                {
                                    addMessageLogText(this, new MessageEvent("Settings sequence to sequence mode " + mode.ModeName + "."));
                                    WordGenerator.MainClientForm.instance.sequencePage.setMode(mode);
                                }
                                else
                                {
                                    addMessageLogText(this, new MessageEvent("Currently running sequence is either a calibration shot or background running sequence. Cannot change the sequence mode of a background sequence. Skipping mode change."));
                                }
                            }
                            else
                            {
                                addMessageLogText(this, new MessageEvent("Warning! Invalid sequence mode index. Ignoring the SeqMode variable."));
                                ErrorDetected = true;
                            }
                        }
                    }
                }

                if (variablePreviewForm != null)
                {
                    addMessageLogText(this, new MessageEvent("Updating variables according to variable preview window..."));
                    int nChanged = variablePreviewForm.refresh(sequence);
                    addMessageLogText(this, new MessageEvent("... " + nChanged + " variable values changed."));
                }

                // Create timestep "loop copies" if there are timestep loops in use
                bool useLoops = false;
                foreach (TimestepGroup tsg in sequence.TimestepGroups)
                {
                    if (tsg.LoopTimestepGroup && sequence.TimestepGroupIsLoopable(tsg) && tsg.LoopCountInt > 1)
                    {
                        useLoops = true;
                    }
                }
                if (useLoops)
                {
                    addMessageLogText(this, new MessageEvent("This sequence makes use of looping timestep groups. Creating temporary loop copies..."));
                    sequence.createLoopCopies();
                    addMessageLogText(this, new MessageEvent("...done"));
                }

                List<string> missingServers = Storage.settingsData.unconnectedRequiredServers();

                if (missingServers.Count != 0)
                {

                    string missingServerList = ServerManager.convertListOfServersToOneString(missingServers);

                    addMessageLogText(this, new MessageEvent("Unable to start run. The following required servers are not connected: " + missingServerList + "."));
                    ErrorDetected = true;
                    setStatus(RunFormStatus.FinishedRun);
                    return false;
                }

                List<LogicalChannel> overriddenDigitals = new List<LogicalChannel>();
                List<LogicalChannel> overriddenAnalogs = new List<LogicalChannel>();

                foreach (LogicalChannel lc in Storage.settingsData.logicalChannelManager.Digitals.Values)
                {
                    if (lc.overridden)
                        overriddenDigitals.Add(lc);
                }

                foreach (LogicalChannel lc in Storage.settingsData.logicalChannelManager.Analogs.Values)
                {
                    if (lc.overridden)
                        overriddenAnalogs.Add(lc);
                }

                if (overriddenDigitals.Count != 0)
                {
                    string list = "";
                    foreach (LogicalChannel lc in overriddenDigitals)
                    {
                        string actingName;
                        if (lc.Name != "" & lc.Name != null)
                        {
                            actingName = lc.Name;
                        }
                        else
                        {
                            actingName = "[Unnamed]";
                        }
                        list += actingName + ", ";
                    }
                    list = list.Remove(list.Length - 2);
                    list += ".";
                    addMessageLogText(this, new MessageEvent("Reminder. The following " + overriddenDigitals.Count + " digital channel(s) are being overridden: " + list));
                }

                if (overriddenAnalogs.Count != 0)
                {
                    string list = "";
                    foreach (LogicalChannel lc in overriddenAnalogs)
                    {
                        string actingName;
                        if (lc.Name != "" & lc.Name != null)
                        {
                            actingName = lc.Name;
                        }
                        else
                        {
                            actingName = "[Unnamed]";
                        }

                        list += actingName + ", ";
                    }
                    list = list.Remove(list.Length - 2);
                    list += ".";
                    addMessageLogText(this, new MessageEvent("Reminder. The following " + overriddenAnalogs.Count + " analog channel(s) are being overridden: " + list));
                }

                runStartTime = DateTime.Now;

                #region Sending camera instructions
                if (Storage.settingsData.UseCameras)
                {

                    byte[] msg;// = Encoding.ASCII.GetBytes(get_fileStamp(sequence));
                    string shot_name = NamingFunctions.get_fileStamp(sequence, Storage.settingsData, runStartTime);
                    string sequenceTime = sequence.SequenceDuration.ToString();
                    string FCamera;
                    string UCamera;

                    foreach (Socket theSocket in CameraPCsSocketList)
                    {
                        try
                        {
                            int index = CameraPCsSocketList.IndexOf(theSocket);
                            FCamera = connectedPCs[index].useFWCamera.ToString();
                            UCamera = connectedPCs[index].useUSBCamera.ToString();
                            msg = Encoding.ASCII.GetBytes(shot_name + "@" + sequenceTime + "@" + FCamera + "@" + UCamera + "@" + isCameraSaving.ToString() + "@\0");
                            theSocket.Send(msg, 0, msg.Length, SocketFlags.None);
                        }
                        catch { }
                    }
                }
                #endregion

                ServerManager.ServerActionStatus actionStatus;

                // send start timestamp
                addMessageLogText(this, new MessageEvent("Sending run start timestamp."));
                actionStatus = Storage.settingsData.serverManager.setNextRunTimestampOnConnectedServers(runStartTime, addMessageLogText);
                if (actionStatus != ServerManager.ServerActionStatus.Success)
                {
                    addMessageLogText(this, new MessageEvent("Unable to set start timestamp. " + actionStatus.ToString()));
                    ErrorDetected = true;
                    setStatus(RunFormStatus.FinishedRun);
                    return false;
                }

                // send settings data.
                addMessageLogText(this, new MessageEvent("Sending settings data."));
                actionStatus = Storage.settingsData.serverManager.setSettingsOnConnectedServers(Storage.settingsData, addMessageLogText);
                if (actionStatus != ServerManager.ServerActionStatus.Success)
                {
                    addMessageLogText(this, new MessageEvent("Unable to send settings data. " + actionStatus.ToString()));
                    ErrorDetected = true;
                    setStatus(RunFormStatus.FinishedRun);
                    return false;
                }

                // send sequence data.
                addMessageLogText(this, new MessageEvent("Sending sequence data."));
                actionStatus = Storage.settingsData.serverManager.setSequenceOnConnectedServers(sequence, addMessageLogText);
                if (actionStatus != ServerManager.ServerActionStatus.Success)
                {
                    addMessageLogText(this, new MessageEvent("Unable to send sequence data. " + actionStatus.ToString()));
                    ErrorDetected = true;
                    setStatus(RunFormStatus.FinishedRun);
                    return false;
                }

                // generate buffers.
                addMessageLogText(this, new MessageEvent("Generating buffers."));
                actionStatus = Storage.settingsData.serverManager.generateBuffersOnConnectedServers(iterationNumber, addMessageLogText);
                if (actionStatus != ServerManager.ServerActionStatus.Success)
                {
                    addMessageLogText(this, new MessageEvent("Unable to generate buffers. " + actionStatus.ToString()));
                    ErrorDetected = true;
                    setStatus(RunFormStatus.FinishedRun);
                    return false;
                }

                // arm tasks.

                Random rnd = new Random();
                clockID = (uint)rnd.Next();

                if (softwareClockProvider != null || networkClockProvider!=null)
                {
                    addMessageLogText(this, new MessageEvent("A software clock provider already exists, unexpectedly. Aborting."));
                    return false;
                }

                if (!Storage.settingsData.AlwaysUseNetworkClock)
                {
                    softwareClockProvider = new ComputerClockSoftwareClockProvider(10);
                    softwareClockProvider.addSubscriber(this, 41, 0);
                    softwareClockProvider.ArmClockProvider();
                }

                networkClockProvider = new NetworkClockProvider(clockID);
                networkClockProvider.addSubscriber(this, 41, 1);
                networkClockProvider.ArmClockProvider();

                currentSoftwareclockPriority = 0;

                addMessageLogText(this, new MessageEvent("Arming tasks."));
                actionStatus = Storage.settingsData.serverManager.armTasksOnConnectedServers(clockID, addMessageLogText);
                if (actionStatus != ServerManager.ServerActionStatus.Success)
                {
                    addMessageLogText(this, new MessageEvent("Unable to arm tasks. " + actionStatus.ToString()));
                    ErrorDetected = true;
                    setStatus(RunFormStatus.FinishedRun);
                    return false;
                }

                // generate triggers

                addMessageLogText(this, new MessageEvent("Generating triggers."));
                actionStatus = Storage.settingsData.serverManager.generateTriggersOnConnectedServers(addMessageLogText);
                if (actionStatus != ServerManager.ServerActionStatus.Success)
                {
                    addMessageLogText(this, new MessageEvent("Unable to generate triggers. " + actionStatus.ToString()));
                    ErrorDetected = true;
                    setStatus(RunFormStatus.FinishedRun);
                    return false;
                }

                setStatus(RunFormStatus.Running);

                // async call to progress bar initialization

                Action<double> initProgressBarAction = initializeProgressBar;
                Invoke(initProgressBarAction, new object[] { sequence.SequenceDuration });

                double duration = sequence.SequenceDuration;
                addMessageLogText(this, new MessageEvent("Sequence duration " + duration + " s. Running."));

                // start software clock
                if (softwareClockProvider!=null)
                    softwareClockProvider.StartClockProvider();
                networkClockProvider.StartClockProvider();

                while (true)
                {
                    if (currentSoftwareclockPriority == 0)
                    {
                        if (softwareClockProvider != null && (softwareClockProvider.getElapsedTime() >= (200 + duration * 1000.0)))
                            break;
                    }
                    else
                        if (networkClockProvider != null && (networkClockProvider.getElapsedTime() >= (duration * 1000.0)))
                            break;

                    Thread.Sleep(100);
                }

                if (softwareClockProvider!=null)
                    softwareClockProvider.AbortClockProvider();
                softwareClockProvider = null;
                networkClockProvider.AbortClockProvider();
                networkClockProvider = null;

                MainClientForm.instance.CurrentlyOutputtingTimestep = sequence.dwellWord();

                actionStatus = Storage.settingsData.serverManager.getRunSuccessOnConnectedServers(addMessageLogText);
                if (actionStatus != ServerManager.ServerActionStatus.Success)
                {
                    addMessageLogText(this, new MessageEvent("Run failed, possibly due to a buffer underrun. Please check the server event logs."));
                    ErrorDetected = true;
                    setStatus(RunFormStatus.FinishedRun);
                    return false;
                }

                if (useLoops)
                    sequence.cleanupLoopCopies();

                addMessageLogText(this, new MessageEvent("Finished run. Writing log file..."));
                RunLog runLog = new RunLog(runStartTime, formCreationTime, sequence, Storage.settingsData, WordGenerator.MainClientForm.instance.OpenSequenceFileName, WordGenerator.MainClientForm.instance.OpenSettingsFileName);
                string fileName = runLog.WriteLogFile();

                if (fileName != null)
                {
                    addMessageLogText(this, new MessageEvent("Log written to " + fileName));
                }
                else
                {
                    addMessageLogText(this, new MessageEvent("Log not written! Perhaps a file with this name already exists?"));
                    ErrorDetected = true;
                }

                foreach (RunLogDatabaseSettings rset in Storage.settingsData.RunlogDatabaseSettings)
                {

                    if (rset.Enabled)
                    {
                        RunlogDatabaseHandler handler = null;
                        try
                        {
                            handler = new RunlogDatabaseHandler(rset);
                            handler.addRunLog(fileName, runLog);
                            addMessageLogText(this, new MessageEvent("Run log added to mysql database at url " + rset.Url + " successfully."));
                        }
                        catch (RunLogDatabaseException e)
                        {
                            addMessageLogText(this, new MessageEvent("Caught exception when attempting to add runlog to mysqldatabase at " + rset.Url + "."));
                            if (rset.VerboseErrorReporting)
                            {
                                addMessageLogText(this, new MessageEvent("Displaying runlogdatabase exception. To disable this display, turn off verbose error reporting for this runlog database in Cicero settings (under Advanced->Settings Explorer)"));
                                ExceptionViewerDialog ev = new ExceptionViewerDialog(e);
                                ev.ShowDialog();
                            }
                            else
                            {
                                addMessageLogText(this, new MessageEvent("Exception was " + e.Message + ". For more detailed information, turn on verbose error reporting for this runlog database in Cicero settings (under Advanced->Settings Explorer)"));
                            }
                        }

                        if (handler != null)
                            handler.closeConnection();
                    }
                }

                if (runRepeat)
                    keepGoing = true;
                else
                    keepGoing = false;

                repeatCount++;

                if (abortAfterThis.Checked)
                {
                    userAborted = true;
                    setStatus(RunFormStatus.FinishedRun);
                    return false;
                }

                setStatus(RunFormStatus.FinishedRun);
            }

            return true;
        }