public int Shot( int startTime, int valvePulseLength, int valveToQ, int flashToQ,
            int delayToDetectorTrigger, int delayToDeceleration, string detectorTriggerSource, TimingSequence decelSequence,
            string modulationMode, int decelOnStart, int decelOnDuration)
        {
            int time = 0;
            int tempTime = 0;
            // valve pulse
            tempTime = Pulse(startTime, 0, valvePulseLength,
                ((DigitalOutputChannel)Environs.Hardware.DigitalOutputChannels["valve"]).BitNumber);
            if (tempTime > time) time = tempTime;
            // Flash pulse
            tempTime = Pulse(startTime, valveToQ - flashToQ, FLASH_PULSE_LENGTH,
                ((DigitalOutputChannel)Environs.Hardware.DigitalOutputChannels["flash"]).BitNumber);
            if (tempTime > time) time = tempTime;
            // Q pulse
            tempTime = Pulse(startTime, valveToQ, Q_PULSE_LENGTH,
                ((DigitalOutputChannel)Environs.Hardware.DigitalOutputChannels["q"]).BitNumber);
            if (tempTime > time) time = tempTime;
            // Detector trigger
            tempTime = Pulse(startTime, delayToDetectorTrigger + valveToQ, DETECTOR_TRIGGER_LENGTH,
                ((DigitalOutputChannel)Environs.Hardware.DigitalOutputChannels[detectorTriggerSource]).BitNumber);
            if (tempTime > time) time = tempTime;

            // Deceleration sequence
            if (decelSequence != null)
            {
                foreach (TimingSequence.Edge edge in decelSequence.Sequence)
                {
                    tempTime = startTime + valveToQ + delayToDeceleration + edge.Time;
                    AddEdge(
                        ((DigitalOutputChannel)Environs.Hardware.DigitalOutputChannels[edge.Channel]).BitNumber,
                        tempTime,
                        edge.Sense
                        );
                }
            }
            else
            {
                if (modulationMode == "BurstAndOn" || modulationMode == "OnAndBurst") // long on pulse every other shot; otherwise, the decelerator stays off on every other shot
                {
                    tempTime = startTime + valveToQ + decelOnStart;
                    AddEdge(((DigitalOutputChannel)Environs.Hardware.DigitalOutputChannels["decelhplus"]).BitNumber, tempTime, true);
                    AddEdge(((DigitalOutputChannel)Environs.Hardware.DigitalOutputChannels["decelhminus"]).BitNumber, tempTime, true);
                    AddEdge(((DigitalOutputChannel)Environs.Hardware.DigitalOutputChannels["decelvplus"]).BitNumber, tempTime, true);
                    AddEdge(((DigitalOutputChannel)Environs.Hardware.DigitalOutputChannels["decelvminus"]).BitNumber, tempTime, true);
                    tempTime = startTime + valveToQ + decelOnStart + decelOnDuration;
                    AddEdge(((DigitalOutputChannel)Environs.Hardware.DigitalOutputChannels["decelhplus"]).BitNumber, tempTime, false);
                    AddEdge(((DigitalOutputChannel)Environs.Hardware.DigitalOutputChannels["decelhminus"]).BitNumber, tempTime, false);
                    AddEdge(((DigitalOutputChannel)Environs.Hardware.DigitalOutputChannels["decelvplus"]).BitNumber, tempTime, false);
                    AddEdge(((DigitalOutputChannel)Environs.Hardware.DigitalOutputChannels["decelvminus"]).BitNumber, tempTime, false);
                }
            }
            return time;
        }
        public int ShotSequence( int startTime, int numberOfOnOffShots, int padShots, int flashlampPulseInterval,
            int valvePulseLength, int valveToQ, int flashToQ, int delayToDetectorTrigger,
            int delayToDeceleration, TimingSequence decelSequence, string modulationMode, int decelOnStart, int decelOnDuration, bool modulation)
        {
            int time = startTime;

            for (int i = 0 ; i < numberOfOnOffShots ; i++ )
            {
                if (modulationMode == "BurstAndOff" || modulationMode == "BurstAndOn")
                {
                    // first with decelerator on
                    Shot(time, valvePulseLength, valveToQ, flashToQ, delayToDetectorTrigger, delayToDeceleration, "detector",
                        decelSequence, modulationMode, decelOnStart, decelOnDuration);
                    time += flashlampPulseInterval;
                    // then with the decelerator off if modulation is true (otherwise another on shot)
                    if (modulation)
                    {
                        Shot(time, valvePulseLength, valveToQ, flashToQ, delayToDetectorTrigger, delayToDeceleration, "detectorprime",
                            null, modulationMode, decelOnStart, decelOnDuration);
                    }
                    else
                    {
                        Shot(time, valvePulseLength, valveToQ, flashToQ, delayToDetectorTrigger, delayToDeceleration, "detector",
                            decelSequence, modulationMode, decelOnStart, decelOnDuration);
                    }
                    time += flashlampPulseInterval;
                }
                if (modulationMode == "OffAndBurst" || modulationMode == "OnAndBurst")
                {
                    // first with decelerator off
                    Shot(time, valvePulseLength, valveToQ, flashToQ, delayToDetectorTrigger, delayToDeceleration, "detector",
                        null, modulationMode, decelOnStart, decelOnDuration);
                    time += flashlampPulseInterval;
                    // then with the decelerator on if modulation is true (otherwise another off shot)
                    if (modulation)
                    {
                        Shot(time, valvePulseLength, valveToQ, flashToQ, delayToDetectorTrigger, delayToDeceleration, "detectorprime",
                            decelSequence, modulationMode, decelOnStart, decelOnDuration);
                    }
                    else
                    {
                        Shot(time, valvePulseLength, valveToQ, flashToQ, delayToDetectorTrigger, delayToDeceleration, "detector",
                            null, modulationMode, decelOnStart, decelOnDuration);
                    }
                    time += flashlampPulseInterval;
                }
                for (int p = 0 ; p < padShots ; p++)
                {
                    FlashlampPulse(time, valveToQ, flashToQ);
                    time += flashlampPulseInterval;
                }

            }

            return time;
        }
        private void buildDecelerationSequence()
        {
            //get the settings we need
            double voltage = (double)settings["voltage"];
            int initspeed = (int)settings["initspeed"];
            double onposition = (double)settings["onposition"] / 1000;
            double offposition = (double)settings["offposition"] / 1000;
            int numberOfStages = (int)settings["numberOfStages"];
            int resonanceOrder = (int)settings["resonanceOrder"];
            int jState = (int)settings["jState"];
            int mState = (int)settings["mState"];

            // make the FieldMap
            FieldMap map = new FieldMap((string)Environs.FileSystem.Paths["decelerationUtilitiesPath"] +
                (string)Environs.Hardware.GetInfo("deceleratorFieldMap"),
                (int)Environs.Hardware.GetInfo("mapPoints"),
                (double)Environs.Hardware.GetInfo("mapStartPoint"),
                (double)Environs.Hardware.GetInfo("mapResolution"));
            //make the molecule
            Molecule mol = new Molecule((string)Environs.Hardware.GetInfo("moleculeName"),
                (double)Environs.Hardware.GetInfo("moleculeMass"),
                (double)Environs.Hardware.GetInfo("moleculeRotationalConstant"),
                (double)Environs.Hardware.GetInfo("moleculeDipoleMoment"));
            //make the decelerator and the experiment
            Decelerator decel = new Decelerator();
            DecelerationExperiment experiment = new DecelerationExperiment();
            //assign a map and a lens spacing to the decelerator
            decel.Map = map;
            decel.LensSpacing = (double)Environs.Hardware.GetInfo("deceleratorLensSpacing");
            //assign decelerator, molecule, quantum state and switch structure to the experiment
            experiment.Decelerator = decel;
            experiment.Molecule = mol;
            experiment.QuantumState = new int[] { jState, mState };
            experiment.Structure = (DecelerationExperiment.SwitchStructure)Environs.Hardware.GetInfo("deceleratorStructure");
            //get the timing sequence
            double[] timesdouble = experiment.GetTimingSequence(voltage, onposition, offposition, initspeed, numberOfStages, resonanceOrder);

            // The list of times is in seconds and is measured from the moment when the synchronous molecule
            // reaches the decelerator. Add on the amount of time it takes to reach this point.
            // Then convert to the units of the clockFrequency and round to the nearest unit.
            double nominalTimeToDecelerator = (double)Environs.Hardware.GetInfo("sourceToSoftwareDecelerator") / initspeed;
            int[] times = new int[timesdouble.Length];
            for (int i = 0; i < timesdouble.Length; i++)
            {
                times[i] = (int)Math.Round((int)settings["clockFrequency"] * (nominalTimeToDecelerator + timesdouble[i]));
            }

            int[] structure = new int[times.Length];

            // the last switch must send all electrodes to ground
            structure[structure.Length - 1] = 0;
            // build the rest of the structure
            int k = 0;
            switch (experiment.Structure)
            {
                case DecelerationExperiment.SwitchStructure.H_Off_V_Off:
                    while (k < structure.Length - 1)
                    {
                        if (k < structure.Length - 1) { structure[k] = 2; k++; }
                        if (k < structure.Length - 1) { structure[k] = 0; k++; }
                        if (k < structure.Length - 1) { structure[k] = 1; k++; }
                        if (k < structure.Length - 1) { structure[k] = 0; k++; }
                    }
                    break;
                case DecelerationExperiment.SwitchStructure.V_Off_H_Off:
                    while (k < structure.Length - 1)
                    {
                        if (k < structure.Length - 1) { structure[k] = 1; k++; }
                        if (k < structure.Length - 1) { structure[k] = 0; k++; }
                        if (k < structure.Length - 1) { structure[k] = 2; k++; }
                        if (k < structure.Length - 1) { structure[k] = 0; k++; }
                    }
                    break;
                case DecelerationExperiment.SwitchStructure.H_V:
                    while (k < structure.Length - 1)
                    {
                        if (k < structure.Length - 1) { structure[k] = 2; k++; }
                        if (k < structure.Length - 1) { structure[k] = 1; k++; }
                    }
                    break;
                case DecelerationExperiment.SwitchStructure.V_H:
                    while (k < structure.Length - 1)
                    {
                        if (k < structure.Length - 1) { structure[k] = 1; k++; }
                        if (k < structure.Length - 1) { structure[k] = 2; k++; }
                    }
                    break;
            }
            // keep track of the state of the horizontal and vertical electrodes
            bool[] states = { false, false }; //{horizontal, vertical}
            decelSequence = new TimingSequence();
            // The timing sequence is built within this for loop. The structure of the decelerator is encoded
            // as follows: 0 means everything off, 1 means V on, H off, 2 means H on V off and 3 means both on.
            for (int i = 0; i < times.Length && i < structure.Length; i++)
            {
                if (structure[i] == 0) //horizontal = false, vertical = false
                {
                    if (states[0] != false)
                    {
                        decelSequence.Add("decelhplus", times[i], false);
                        decelSequence.Add("decelhminus", times[i], false);
                        states[0] = false;
                    }
                    if (states[1] != false)
                    {
                        decelSequence.Add("decelvplus", times[i], false);
                        decelSequence.Add("decelvminus", times[i], false);
                        states[1] = false;
                    }
                }

                if (structure[i] == 1) //horizontal = false, vertical = true
                {
                    if (states[0] != false)
                    {
                        decelSequence.Add("decelhplus", times[i], false);
                        decelSequence.Add("decelhminus", times[i], false);
                        states[0] = false;
                    }
                    if (states[1] != true)
                    {
                        decelSequence.Add("decelvplus", times[i], true);
                        decelSequence.Add("decelvminus", times[i], true);
                        states[1] = true;
                    }
                }

                if (structure[i] == 2) //horizontal = true, vertical = false
                {
                    if (states[0] != true)
                    {
                        decelSequence.Add("decelhplus", times[i], true);
                        decelSequence.Add("decelhminus", times[i], true);
                        states[0] = true;
                    }
                    if (states[1] != false)
                    {
                        decelSequence.Add("decelvplus", times[i], false);
                        decelSequence.Add("decelvminus", times[i], false);
                        states[1] = false;
                    }
                }

                if (structure[i] == 3) //horizontal = true, vertical = true
                {
                    if (states[0] != true)
                    {
                        decelSequence.Add("decelhplus", times[i], true);
                        decelSequence.Add("decelhminus", times[i], true);
                        states[0] = true;
                    }
                    if (states[1] != true)
                    {
                        decelSequence.Add("decelvplus", times[i], true);
                        decelSequence.Add("decelvminus", times[i], true);
                        states[1] = true;
                    }
                }
            }
            Console.WriteLine(decelSequence.ToString());
        }