用于控制器数据采集和管理的核心类Data

    public class Data
    {
        private const double DefaultCollectionPeriod = 1.0;

        private readonly Controller controller;

        private ConfiguredRecord[] configuredRecords;

        private double configuredRate;

        private DataCollectionConfiguration configuration = new DataCollectionConfiguration();
        private readonly ContinuousDataCollectionPoller continuousDataPoller;
        private readonly AxesDiagPacketRetriever axesDiagRetriever;

        public DataCollectionStatus Status
        {
            get
            {
                DATACOLLECTION_STATUS pDataCollectionStatus_ = default(DATACOLLECTION_STATUS);
                ExceptionResolver.ResolveThrow(controller, Wrapper.getDataCollectionStatus(controller.Handle.Value, ref pDataCollectionStatus_));
                bool isContinuousMode = (pDataCollectionStatus_.dwStatus & 0x200) != 0;
                return new DataCollectionStatus(pDataCollectionStatus_.dwAllocated, pDataCollectionStatus_.dwCollected, pDataCollectionStatus_.dwRetrieved, ((pDataCollectionStatus_.dwStatus & 4) | (pDataCollectionStatus_.dwStatus & 0x10000)) != 0, isContinuousMode, (pDataCollectionStatus_.dwStatus & 0x10) != 0, (pDataCollectionStatus_.dwStatus & 0x800) != 0, pDataCollectionStatus_.dwScopeTrigID);
            }
        }

        public DataCollectionConfiguration Configuration => configuration;

        internal ContinuousDataCollectionPoller Poller => continuousDataPoller;

        internal AxesDiagPacketRetriever AxesDiagPacketRetriever => axesDiagRetriever;

        public event EventHandler<ContinuousDataSamplesRetrievedEventArgs> ContinuousDataSamplesRetrieved
        {
            add
            {
                continuousDataPoller.ContinuousDataSamplesRetrieved += value;
            }
            remove
            {
                continuousDataPoller.ContinuousDataSamplesRetrieved -= value;
            }
        }

        internal Data(Controller controller)
        {
            this.controller = controller;
            axesDiagRetriever = new AxesDiagPacketRetriever(controller);
            continuousDataPoller = new ContinuousDataCollectionPoller(controller);
        }

        public ControllerDiagPacket RetrieveDiagnostics()
        {
            return RetrieveDiagnostics(new UnitInformation(DistanceUnit.Primary, TimeUnit.Seconds));
        }

        public ControllerDiagPacket RetrieveDiagnostics(UnitInformation units)
        {
            KeyValuePair<DiagPacket[], double[]> axesDiagnostics = axesDiagRetriever.GetAxesDiagnostics(units);
            return new ControllerDiagPacket(controller, units, axesDiagnostics.Key, axesDiagnostics.Value);
        }

        public void ApplyConfiguration()
        {
            ApplyConfiguration(configuration);
        }

        public void ApplyConfiguration(DataCollectionConfiguration configuration)
        {
            if (configuration == null)
            {
                throw new ArgumentNullException("configuration");
            }

            setCollectionConfiguration(configuration);
        }

        public DataCollectionResults GetData()
        {
            return GetData(Status.PointsAllocated);
        }

        public DataCollectionResults GetData(ProgressChangedEventHandler progressChangedEventHandler)
        {
            return GetData(Status.PointsAllocated, progressChangedEventHandler);
        }

        public DataCollectionResults GetData(int pointsToRetrieve)
        {
            if (pointsToRetrieve < 0)
            {
                throw new ArgumentOutOfRangeException("pointsToRetrieve");
            }

            return getResults(pointsToRetrieve);
        }

        public DataCollectionResults GetData(int pointsToRetrieve, ProgressChangedEventHandler progressChangedEventHandler)
        {
            if (pointsToRetrieve < 0)
            {
                throw new ArgumentOutOfRangeException("pointsToRetrieve");
            }

            bool flag = false;
            DataCollectionStatus status = Status;
            Action<int> action = delegate (int progress)
            {
                if (progressChangedEventHandler != null)
                {
                    progressChangedEventHandler(controller, new ProgressChangedEventArgs(progress, null));
                }
            };
            while (status.PointsRetrieved < pointsToRetrieve && pointsToRetrieve <= status.PointsAllocated)
            {
                if (!status.IsCollecting)
                {
                    flag = true;
                    break;
                }

                action(Math.Min(100, (int)(100.0 * (double)status.PointsRetrieved / (double)pointsToRetrieve)));
                Thread.Sleep(10);
                status = Status;
            }

            if (!flag)
            {
                action(100);
            }

            return GetData(pointsToRetrieve);
        }

        public void Start()
        {
            Start(configuration);
        }

        public void Start(DataCollectionConfiguration configuration)
        {
            if (configuration == null)
            {
                throw new ArgumentNullException("configuration");
            }

            setCollectionConfiguration(configuration);
            triggerDataCollection(DataCollectionTriggerType.Immediate);
        }

        public void StartContinuous(int numberOfPoints)
        {
            StartContinuous(configuration, numberOfPoints);
        }

        public void StartContinuous(DataCollectionConfiguration configuration, int numberOfPoints)
        {
            if (configuration == null)
            {
                throw new ArgumentNullException("configuration");
            }

            if (numberOfPoints < 0 || numberOfPoints > configuration.PointsToCollect)
            {
                throw new ArgumentException("numberOfPoints");
            }

            setCollectionConfiguration(configuration);
            if (numberOfPoints > 0)
            {
                continuousDataPoller.Samples = numberOfPoints;
                continuousDataPoller.Start();
            }

            triggerDataCollection(DataCollectionTriggerType.Continuous);
        }

        public void WaitForData(int points)
        {
            WaitForData(points, null);
        }

        public void WaitForData(int points, ProgressChangedEventHandler waiter)
        {
            if (points <= 0)
            {
                throw new ArgumentOutOfRangeException(string.Format(Resources.ArgumentMustBePositive, "points"));
            }

            if (points > Status.PointsAllocated)
            {
                throw new InvalidOperationException(string.Format(Resources.ArgumentGreaterThanPointsAllocated, "points"));
            }

            int num = 0;
            int num2 = 0;
            bool flag = false;
            DataCollectionStatus status = Status;
            while (num < points)
            {
                if (!status.IsCollecting)
                {
                    flag = true;
                    break;
                }

                if (waiter != null && num2 != 100 * num / points)
                {
                    num2 = 100 * num / points;
                    waiter(controller, new ProgressChangedEventArgs(num2, null));
                }

                Thread.Sleep(10);
                status = Status;
                num = status.PointsCollected;
            }

            if (waiter != null && !flag)
            {
                waiter(controller, new ProgressChangedEventArgs(100, null));
            }
        }

        public void Stop()
        {
            ExceptionResolver.ResolveThrow(controller, Wrapper.dataCollectionHalt(controller.Handle.Value));
            continuousDataPoller.Stop();
        }

        private void setCollectionConfiguration(DataCollectionConfiguration configuration)
        {
            ErrorData err = new ErrorData(92, 5);
            int num = (int)((configuration.SampleTrigger.Time == null) ? configuration.SampleTrigger.Change.Trigger : ((DataCollectionSampleTrigger)0));
            int num2 = ((configuration.SampleTrigger.Time == null) ? configuration.SampleTrigger.Change.Signal : 0);
            int num3 = ((configuration.SampleTrigger.Time != null) ? (-1) : configuration.SampleTrigger.Change.Index);
            int sampleTriggerOptional_ = ((configuration.SampleTrigger.Time == null) ? configuration.SampleTrigger.Change.Optional : 0);
            if (configuration.SampleTrigger.Change != null)
            {
                if (configuration.SampleTrigger.Change.VariableName != null)
                {
                    Variable variable = null;
                    if (controller.Variables[configuration.SampleTrigger.Change.VariableName] != null)
                    {
                        variable = controller.Variables[configuration.SampleTrigger.Change.VariableName];
                    }
                    else
                    {
                        if (controller.Variables.Tasks[configuration.SampleTrigger.Change.Index][configuration.SampleTrigger.Change.VariableName] == null)
                        {
                            throw new ArgumentOutOfRangeException("variable", Resources.ErrorVariableNameNotFound, variable.Name);
                        }

                        variable = controller.Variables.Tasks[configuration.SampleTrigger.Change.Index][configuration.SampleTrigger.Change.VariableName];
                    }

                    if (variable.ValueType == VariableType.String)
                    {
                        ExceptionResolver.ResolveThrow(controller, err);
                    }

                    VariableDescriptor[] array = new VariableDescriptor[1];
                    array[0].name = variable.Name;
                    array[0].taskId = (TaskId)variable.ContextKey;
                    num2 = CoreVariableHelper.CreateVariableSignalRecords(controller, array)[0].itemCode;
                    num3 = variable.ContextKey;
                    sampleTriggerOptional_ = variable.Number;
                }
                else if (configuration.SampleTrigger.Change.AxisName != null)
                {
                    num3 = controller.Information.Axes[configuration.SampleTrigger.Change.AxisName].Number;
                }
            }

            ConfiguredRecord[] array2 = DataCollectionHelper.ConvertConfigurationToRecords(controller, configuration);
            List<DATACOLLECTION_RECORD> list = new List<DATACOLLECTION_RECORD>();
            ConfiguredRecord[] array3 = array2;
            for (int i = 0; i < array3.Length; i++)
            {
                ConfiguredRecord configuredRecord = array3[i];
                list.Add(configuredRecord.coreRecord);
            }

            double msec = configuration.SampleTrigger.getMsec();
            DataCollectionRate collectionRate = DataCollectionHelper.GetCollectionRate(msec);
            ExceptionResolver.ResolveThrow(controller, Wrapper.setDataCollectionConfiguration(controller.Handle.Value, list.ToArray(), (short)array2.Length, configuration.PointsToCollect, collectionRate.msecBetweenSamples, collectionRate.samplesPerMsec, (short)num, (short)num2, (short)num3, sampleTriggerOptional_));
            configuredRecords = array2;
            configuredRate = msec;
        }

        private void triggerDataCollection(DataCollectionTriggerType triggerType)
        {
            ExceptionResolver.ResolveThrow(controller, Wrapper.setDataCollectionTriggerMode(controller.Handle.Value, (short)triggerType));
        }

        private DataCollectionResults getResults(int numRequested)
        {
            if (configuredRecords == null)
            {
                throw new InvalidOperationException();
            }

            double[] array = new double[configuredRecords.Length * numRequested];
            if (numRequested > 0 && configuredRecords.Length != 0)
            {
                if (!Status.IsContinuousMode)
                {
                    ExceptionResolver.ResolveThrow(controller, Wrapper.getDataSamples(controller.Handle.Value, 0, numRequested, array));
                }
                else
                {
                    ExceptionResolver.ResolveThrow(controller, Wrapper.getQueueSamples(controller.Handle.Value, numRequested, array));
                }
            }

            double[][] array2 = new double[configuredRecords.Length][];
            for (int i = 0; i < configuredRecords.Length; i++)
            {
                array2[i] = new double[numRequested];
            }

            for (int j = 0; j < configuredRecords.Length * numRequested; j++)
            {
                int num = j % configuredRecords.Length;
                int num2 = j / configuredRecords.Length;
                array2[num][num2] = array[j];
            }

            List<CollectedAxisDataSignalEntry> list = new List<CollectedAxisDataSignalEntry>();
            List<CollectedAxisExtendedDataSignalEntry> list2 = new List<CollectedAxisExtendedDataSignalEntry>();
            List<CollectedSystemDataSignalEntry> list3 = new List<CollectedSystemDataSignalEntry>();
            List<CollectedTaskDataSignalEntry> list4 = new List<CollectedTaskDataSignalEntry>();
            List<CollectedVariableDataSignalEntry> list5 = new List<CollectedVariableDataSignalEntry>();
            for (int k = 0; k < configuredRecords.Length; k++)
            {
                ConfiguredRecord configuredRecord = configuredRecords[k];
                switch (configuredRecord.context)
                {
                    case DataSignalContext.Axis:
                        list.Add(new CollectedAxisDataSignalEntry((AxisDataSignal)configuredRecord.coreRecord.dataID, controller.Information.Axes[configuredRecord.coreRecord.index].Name, configuredRecord.coreRecord.index, configuredRecord.coreRecord.additionalInfo, array2[k], string.Empty));
                        break;
                    case DataSignalContext.AxisExtended:
                        list2.Add(new CollectedAxisExtendedDataSignalEntry((AxisExtendedDataSignal)configuredRecord.coreRecord.dataID, controller.Information.Axes[configuredRecord.coreRecord.index].Name, configuredRecord.coreRecord.index, configuredRecord.coreRecord.additionalInfo, array2[k], string.Empty));
                        break;
                    case DataSignalContext.System:
                        list3.Add(new CollectedSystemDataSignalEntry((SystemDataSignal)configuredRecord.coreRecord.dataID, configuredRecord.coreRecord.additionalInfo, array2[k], string.Empty));
                        break;
                    case DataSignalContext.Task:
                        list4.Add(new CollectedTaskDataSignalEntry((TaskDataSignal)configuredRecord.coreRecord.dataID, (TaskId)configuredRecord.coreRecord.index, configuredRecord.coreRecord.index, configuredRecord.coreRecord.additionalInfo, array2[k], string.Empty));
                        break;
                    case DataSignalContext.Variable:
                        {
                            _PTR_DATA meta = (_PTR_DATA)configuredRecord.metadata;
                            if (configuredRecord.coreRecord.dataID == 51 || configuredRecord.coreRecord.dataID == 52)
                            {
                                _ = ref meta.arrayDimension[0];
                                array2[k] = Array.ConvertAll(array2[k], (Converter<double, double>)((double point) => (((int)point & (1 << meta.arrayDimension[0].dwValue % 16)) != 0) ? 1 : 0));
                            }

                            list5.Add(new CollectedVariableDataSignalEntry(configuredRecord.recordName, (TaskId)meta.taskIndex, meta.taskIndex, array2[k], string.Empty));
                            break;
                        }
                }
            }

            return new DataCollectionResults(controller, new UnitInformation(DistanceUnit.Counts, TimeUnit.Seconds), new SystemDataResults(list3), new AxisDataResults(list), new AxisExtendedDataResults(list2), new TaskDataResults(list4), new VariableDataResults(list5), numRequested, configuredRate).ConvertUnits(new UnitInformation(DistanceUnit.Counts, TimeUnit.Seconds));
        }
    }

这个 Data 类看起来是一个用于数据采集和管理的核心类,主要用于控制器的诊断数据收集、配置和检索。以下是代码的分析、优化建议和关键点说明:


代码分析

1. 主要功能
  • 数据采集配置:通过 DataCollectionConfiguration 设置采集参数(如采样率、触发条件等)。

  • 数据采集控制:支持立即采集 (Start)、连续采集 (StartContinuous) 和停止采集 (Stop)。

  • 数据检索:提供同步 (GetData) 和带进度回调 (GetData with ProgressChangedEventHandler) 的数据获取方式。

  • 诊断数据:通过 RetrieveDiagnostics 获取控制器和轴的状态信息。

2. 关键组件
  • ContinuousDataCollectionPoller:处理连续数据采集的后台轮询。

  • AxesDiagPacketRetriever:负责轴诊断数据的获取。

  • DataCollectionStatus:封装数据采集的当前状态(如已分配点数、已采集点数等)。

3. 外部依赖
  • Wrapper 类:包含与底层硬件交互的 Native 方法(如 setDataCollectionConfigurationgetDataSamples)。

  • ExceptionResolver:统一处理硬件调用中的错误。


优化建议

1. 线程安全改进
  • 问题WaitForData 和 GetData 中的 Thread.Sleep 可能导致不必要的阻塞。

  • 改进:改用 Task.Delay + async/await(需升级到支持异步的 API):

public async Task<DataCollectionResults> GetDataAsync(int pointsToRetrieve, 
    IProgress<int> progress = null, 
    CancellationToken cancellationToken = default)
{
    while (status.PointsRetrieved < pointsToRetrieve)
    {
        cancellationToken.ThrowIfCancellationRequested();
        progress?.Report(CalculateProgress());
        await Task.Delay(10, cancellationToken).ConfigureAwait(false);
    }
    return GetData(pointsToRetrieve);
}
 配置验证
  • 问题setCollectionConfiguration 中部分验证逻辑分散。

  • 改进:集中验证配置参数:

private void ValidateConfiguration(DataCollectionConfiguration config)
{
    if (config == null) throw new ArgumentNullException(nameof(config));
    if (config.PointsToCollect <= 0) throw new ArgumentOutOfRangeException(...);
    // 其他验证...
}
3. 事件暴露
  • 问题ContinuousDataSamplesRetrieved 事件直接委托给 continuousDataPoller

  • 改进:添加中间层以便扩展:

public event EventHandler<ContinuousDataSamplesRetrievedEventArgs> ContinuousDataSamplesRetrieved
{
    add => continuousDataPoller.ContinuousDataSamplesRetrieved += value;
    remove => continuousDataPoller.ContinuousDataSamplesRetrieved -= value;
}
4. 资源释放
  • 问题:未实现 IDisposable,但持有 ContinuousDataCollectionPoller

  • 改进:实现 IDisposable

public class Data : IDisposable
{
    public void Dispose()
    {
        continuousDataPoller?.Dispose();
        axesDiagRetriever?.Dispose();
    }
}

关键代码片段说明

1. 数据采集触发
public void StartContinuous(DataCollectionConfiguration configuration, int numberOfPoints)
{
    // 参数验证
    setCollectionConfiguration(configuration);
    if (numberOfPoints > 0)
    {
        continuousDataPoller.Samples = numberOfPoints;
        continuousDataPoller.Start(); // 启动后台轮询
    }
    triggerDataCollection(DataCollectionTriggerType.Continuous); // 通知硬件开始采集
}

2. 数据结果转换

private DataCollectionResults getResults(int numRequested)
{
    // 从硬件读取原始数据
    double[] rawData = new double[configuredRecords.Length * numRequested];
    Wrapper.getDataSamples(..., rawData);

    // 按信号类型分类数据
    var axisData = new List<CollectedAxisDataSignalEntry>();
    foreach (var record in configuredRecords)
    {
        axisData.Add(new CollectedAxisDataSignalEntry(
            record.coreRecord.dataID,
            controller.Information.Axes[record.coreRecord.index].Name,
            record.coreRecord.index,
            record.coreRecord.additionalInfo,
            extractedData,
            unitDescription));
    }
    return new DataCollectionResults(...); // 封装结果
}

兼容性注意事项

  1. .NET 版本

    • 若需支持旧版 .NET Framework,避免使用 IProgress<T> 和 ValueTask

  2. 硬件依赖

    • Wrapper 类中的 Native 方法需要确保与硬件驱动版本兼容。

  3. 线程模型

    • 如果 ContinuousDataCollectionPoller 使用多线程,需确保对 configuredRecords 的访问是线程安全的。


总结

  • 当前实现:功能完整,但存在阻塞调用和资源管理风险。

  • 推荐改进

    • 异步化长时间操作(async/await)。

    • 显式资源释放(IDisposable)。

    • 集中配置验证逻辑。

  • 扩展性:可通过继承 DataCollectionConfiguration 支持更多数据采集模式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值