Ejemplo n.º 1
0
        public void UpdateIO(DateTime referenceDateTime)
        {
            lock (_lock)
            {
                if (_isReconfiguring)
                {
                    return;
                }

                _counter = (int)((_counter + 1) % _settings.CycleFrequency);
                _actualWorkingCounter = EcHL.UpdateIo(this.Context, out _dcTime);

                #region "Diagnostics"

                // statistics
                if (_counter == 0)
                {
                    Trace.WriteLine($"lost frames: {(double)_lostFrameCounter / _settings.CycleFrequency:P2} / wkc mismatch: {(double)_wkcMismatchCounter / _settings.CycleFrequency:P2}");

                    if (_lostFrameCounter == _settings.CycleFrequency)
                    {
                        _logger.LogWarning($"frame loss occured ({ _settings.CycleFrequency } frames)");
                        _lostFrameCounter = 0;
                    }

                    if (_wkcMismatchCounter == _settings.CycleFrequency)
                    {
                        _logger.LogWarning($"working counter mismatch { _actualWorkingCounter }/{ _expectedWorkingCounter }");
                        //Trace.WriteLine(EcUtilities.GetSlaveStateDescription(_ecSettings.RootSlaves.SelectMany(x => x.Descendants()).ToList()));
                        _wkcMismatchCounter = 0;
                    }

                    _lostFrameCounter   = 0;
                    _wkcMismatchCounter = 0;
                }

                // no frame
                if (_actualWorkingCounter == -1)
                {
                    _lostFrameCounter += 1;

                    this.UtcDateTime         = DateTime.MinValue;
                    this.DcRingBufferAverage = 0;

                    return;
                }

                // working counter mismatch
                if (_expectedWorkingCounter != _actualWorkingCounter)
                {
                    _wkcMismatchCounter += 1;

                    this.UtcDateTime         = DateTime.MinValue;
                    this.DcRingBufferAverage = 0;

                    return;
                }

                #endregion

                // the UpdateIo timer tries to fire at discrete times. The timer is allowed to be early or delayed by < (CycleTime - Offset) and the resulting DC time will be floored to nearest 10 ms.
                this.UtcDateTime = _dcEpoch.AddTicks(Convert.ToInt64(_dcTime / _dateTime_To_Ns));  // for time loop control

                // for compensation, if DC is not initialized with real time or not initialized at all
                if (_offset == TimeSpan.Zero)
                {
                    _offset = referenceDateTime - this.UtcDateTime;
                }
                else
                {
                    this.UtcDateTime += _offset;
                }

                // dc drift compensation
                _dcRingBuffer[_dcRingBufferIndex] = Convert.ToInt64(referenceDateTime.Ticks - this.UtcDateTime.Ticks) * _dateTime_To_Ns;
                this.DcRingBufferAverage          = Convert.ToInt64(_dcRingBuffer.Average());

                if (!_isDcCompensationRunning && Math.Abs(this.DcRingBufferAverage) > 1500000) // 1.5 ms
                {
                    _isDcCompensationRunning = true;
                    _logger.LogInformation("DC drift compensation started");
                }
                else if (_isDcCompensationRunning && Math.Abs(this.DcRingBufferAverage) < 1000000) // 1.0 ms
                {
                    _isDcCompensationRunning = false;
                    _logger.LogInformation("DC drift compensation finished");
                }

                if (_isDcCompensationRunning)
                {
                    EcHL.CompensateDcDrift(this.Context, Convert.ToInt32(Math.Min(Math.Max(this.DcRingBufferAverage, -_dcDriftCompensationRate), _dcDriftCompensationRate)));
                }

                _dcRingBufferIndex = (_dcRingBufferIndex + 1) % _dcRingBufferSize;
            }
        }