private bool stopAndCleanupTasks()
        {
            try
            {
                bool ans = true;

                if (fpgaTasks != null)
                {
                    foreach (FpgaTimebaseTask ftask in fpgaTasks.Values)
                    {
                        ftask.Stop();
                        if (ftask.ClockStatus == DataStructures.Timing.SoftwareClockProvider.Status.Running)
                            ftask.AbortClockProvider();
                    }

                    fpgaTasks.Clear();
                }

                if (variableTimebaseClockTask != null)
                {
                    try
                    {
                        variableTimebaseClockTask.Stop();
                    }
                    catch (Exception e)
                    {
                        messageLog(this, new MessageEvent("Caught exception when trying to stop the variable timebase output task. This may indicate that the variable timebase clock suffered a buffer underrun in the previous run. Exception follows: " + e.Message + e.StackTrace));
                        displayError();
                        ans = false;
                    }

                    try
                    {
                        variableTimebaseClockTask.Dispose();
                    }
                    catch (Exception e)
                    {
                        messageLog(this, new MessageEvent("Caught exception when trying to dispose of the variable timebase output task. This may indicate that the variable timebase clock suffered a buffer underrun in the previous run. Exception follows: " + e.Message + e.StackTrace));
                        displayError();
                        ans = false;
                    }

                    variableTimebaseClockTask = null;
                }

                if (daqMxTasks == null)
                {
                    daqMxTasks = new Dictionary<string, Task>();
                }
                else
                {
                    List<string> stopMe = new List<string>(daqMxTasks.Keys);

                    foreach (string dev in stopMe)
                    {
                        try
                        {
                            daqMxTasks[dev].Stop();
                        }
                        catch (Exception e)
                        {
                            messageLog(this, new MessageEvent("Caught exception when trying to stop task on device " + dev + ". This may indicate that the previous run suffered from a buffer underrun. Exception follows: " + e.Message + e.StackTrace));
                            displayError();
                            ans = false;
                        }

                        try
                        {
                            daqMxTasks[dev].Dispose();
                        }
                        catch (Exception e)
                        {
                            messageLog(this, new MessageEvent("Caught exception when trying to dispose of task on device " + dev + ". This may indicated that the previous run suffered from a buffer underrun. Exception follows: " + e.Message + e.StackTrace));
                            displayError();
                            ans = false;
                        }

                        daqMxTasks.Remove(dev);
                    }
                    GC.Collect();
                    GC.Collect();
                }

                if (computerClockProvider != null)
                    if (computerClockProvider.ClockStatus== DataStructures.Timing.SoftwareClockProvider.Status.Running)
                        computerClockProvider.AbortClockProvider();
                computerClockProvider = null;

                if (clockBroadcaster != null)
                    clockBroadcaster = null;

                if (gpibTasks == null)
                {
                    gpibTasks = new Dictionary<HardwareChannel, GpibTask>();
                }
                else
                {

                    gpibTasks.Clear();
                }

                if (rs232Tasks == null)
                {
                    rs232Tasks = new Dictionary<HardwareChannel, RS232Task>();
                }
                else
                {
                     rs232Tasks.Clear();
                }

                if (rfsgTasks == null)
                {
                    rfsgTasks = new Dictionary<HardwareChannel, RfsgTask>();
                }
                else
                {
                    rfsgTasks.Clear();
                }

                //   resetAllDevices();

                System.GC.Collect();
                System.GC.Collect();

                taskErrorsDetected = false;

                return ans;
            }
            catch (Exception e)
            {
                messageLog(this, new MessageEvent("Caught exception when attempting to stop tasks. " + e.Message + e.StackTrace));
                displayError();
                return false;
            }
        }
        /// <summary>
        /// Start hardware triggered tasks, and software triggerred tasks which run off an external sample clock. This function also
        /// sets up the software-timed task triggering mechanism, if one is in use.
        /// </summary>
        /// <returns></returns>
        public override bool armTasks(UInt32 clockID)
        {
            lock (remoteLockObj)
            {
                try
                {
                    messageLog(this, new MessageEvent("Arming tasks"));
                    int armedTasks = 0;

                    DataStructures.Timing.SoftwareClockProvider softwareClockProvider;

                    // chose local software clock provider...
                    if (serverSettings.ReceiveNetworkClock)
                    {
                        softwareClockProvider = new DataStructures.Timing.NetworkClockProvider(clockID);
                        messageLog(this, new MessageEvent("Using network clock as software clock provider."));
                    }
                    else if (fpgaTasks!=null && fpgaTasks.Count != 0)
                    {
                        IEnumerator<string> e = fpgaTasks.Keys.GetEnumerator();
                        e.MoveNext();
                        string key = e.Current;
                        softwareClockProvider = fpgaTasks[key];
                        messageLog(this, new MessageEvent("Using FPGA task on device " + key + " as software clock source."));
                    }
                    else
                    {
                        if (computerClockProvider != null)
                        {
                            throw new Exception("Expected computer clock provider to be null when arming task. Aborting.");
                        }
                        this.computerClockProvider = new DataStructures.Timing.ComputerClockSoftwareClockProvider(5);
                        softwareClockProvider = computerClockProvider;
                        messageLog(this, new MessageEvent("Using computer clock as software clock source."));
                    }

                    // create a clock broadcaster
                    if (clockBroadcaster != null)
                    {
                        throw new Exception("Expected clockBroadcaster to be null when it was not.");
                    }
                    if (serverSettings.BroadcastNetworkClock && ! serverSettings.ReceiveNetworkClock)
                    {
                        clockBroadcaster = new DataStructures.Timing.NetworkClockBroadcaster(clockID, (uint)((sequence.SequenceDuration * 1000.0) + 100));
                        softwareClockProvider.addSubscriber(clockBroadcaster, 20);
                    }

                    // add software clock subscribers
                    foreach (RfsgTask task in this.rfsgTasks.Values)
                        softwareClockProvider.addSubscriber(task, 1);

                    foreach (GpibTask task in this.gpibTasks.Values)
                        softwareClockProvider.addSubscriber(task, 1);

                    foreach (RS232Task task in this.rs232Tasks.Values)
                        softwareClockProvider.addSubscriber(task, 1);

                    lock (softwareTriggeringTaskLock)
                    {
                        softwareTriggeringTask = null;
                    }

                    softwareTimedTasksTriggered = false;
                    softwareTimedTriggerCount = 0;

                    foreach (string dev in myServerSettings.myDevicesSettings.Keys)
                    {
                        if (daqMxTasks.ContainsKey(dev))
                        {
                            DeviceSettings ds = myServerSettings.myDevicesSettings[dev];

                            // Start the task if it is hardware triggered, or if it is software triggered but with an external sample clock.
                            if ((ds.StartTriggerType == DeviceSettings.TriggerType.TriggerIn) ||
                                 ((ds.StartTriggerType == DeviceSettings.TriggerType.SoftwareTrigger) && (ds.MySampleClockSource == DeviceSettings.SampleClockSource.External)))
                            {
                                Task task = daqMxTasks[dev];

                                if (dev == serverSettings.DeviceToSyncSoftwareTimedTasksTo)
                                {
                                    if (serverSettings.SoftwareTaskTriggerMethod == ServerSettings.SoftwareTaskTriggerType.SampleClockEvent)
                                    {
                                        messageLog(this, new MessageEvent("***** You are using SampleClockEvent as your SoftwareTaskTriggerMethod (in your ServerSettings). This is not recommended and no longer supported. Use PollBufferPosition instead. *****"));
                                        displayError();
                                        /*
                                        lock (softwareTriggeringTaskLock)
                                        {
                                            softwareTriggeringTask = task;
                                        }
                                        task.SampleClock += triggerSoftwareTimedTasks;

                                         */
                                        return false;
                                    }
                                }

                                task.Start();

                                if (dev == serverSettings.DeviceToSyncSoftwareTimedTasksTo)
                                {
                                    if (serverSettings.SoftwareTaskTriggerMethod == ServerSettings.SoftwareTaskTriggerType.PollBufferPosition)
                                    {
                                        if (softwareTaskTriggerPollingThread != null)
                                        {
                                            if (softwareTaskTriggerPollingThread.ThreadState == ThreadState.Running)
                                            {
                                                softwareTaskTriggerPollingThread.Abort();
                                                if (softwareTaskTriggerPollingThread.ThreadState != ThreadState.Aborted)
                                                {
                                                    throw new Exception("Unable to abort an already-running software-task triggering polling thread.");
                                                }

                                            }
                                        }

                                        lock (softwareTriggeringTaskLock)
                                        {
                                            softwareTriggeringTask = task;
                                            softwareTaskTriggerPollingFunctionInitialPosition = task.Stream.TotalSamplesGeneratedPerChannel;
                                            softwareTaskTriggerPollingThread = new Thread(new ThreadStart(softwareTaskTriggerPollingFunction));
                                            softwareTaskTriggerPollingThread.Start();
                                        }

                                    }
                                }

                                armedTasks++;

                            }
                        }
                    }

                    messageLog(this, new MessageEvent(armedTasks.ToString() + " tasks armed."));

                    if (variableTimebaseClockTask != null)
                    {
                        variableTimebaseClockTask.Control(TaskAction.Commit);
                    }

                    //if needed, the analog input task is launched here
                    if (analogInCardDetected)
                        reader_analog_S7.BeginReadMultiSample(sequence.nSamples(1 / (double)(AtticusServer.server.serverSettings.AIFrequency)), new AsyncCallback(callback_S7), null);

                    return true;
                }
                catch (Exception e)
                {
                    messageLog(this, new MessageEvent("Unable to arm tasks due to exception: " + e.Message + e.StackTrace));
                    displayError();
                    return false;
                }
            }
        }