public EnsembleValuesForPoint(MainModel[] models, SmOutput.OutputType type, string name, string additionalParams)
        {
            Models = models;
            Values = new double[Models.Length];
            _type  = type;
            switch (_type)
            {
            case SmOutput.OutputType.linkFlowTimeSeries:
                throw new NotImplementedException();
                for (int i = 0; i < Models.Length; i++)
                {
                    //cons[i] = models[i].get
                }
                break;

            case SmOutput.OutputType.nodeVolume:
                nodex = Models[0].getNode(name);
                break;

            case SmOutput.OutputType.nodeWaterLevel:
                nodex    = Models[0].getNode(name);
                _type    = SmOutput.OutputType.nodeWaterLevel;
                _derived = new DerivedValue(additionalParams);

                break;

            case SmOutput.OutputType.outletFlowTimeSeries:

                outlets = new Outlet[Models.Length];

                int outletIndexInNodeArray = int.MaxValue;
                foreach (int i in Models[0].iOutlets)
                {
                    if (Models[0].Nodes[i].name == name)
                    {
                        outletIndexInNodeArray = i;
                    }
                }
                if (outletIndexInNodeArray == int.MaxValue)
                {
                    throw new Exception("could not find outlet");
                }

                for (int i = 0; i < Models.Length; i++)
                {
                    outlets[i] = (Outlet)models[i].Nodes[outletIndexInNodeArray];
                }

                break;

            default:
                break;
            }
        }
示例#2
0
        private DerivedValue ParseDerivedValue(string signalReference)
        {
            if (string.IsNullOrWhiteSpace(signalReference))
            {
                return(null);
            }

            DerivedValue derivedValue;

            // Remove device name from signal reference
            if (signalReference.StartsWith(Name, StringComparison.OrdinalIgnoreCase))
            {
                signalReference = signalReference.Substring(Name.Length);
            }

            int indexOfType = signalReference.IndexOf("-DV!", StringComparison.OrdinalIgnoreCase);

            if (indexOfType < 0)
            {
                // Instantaneous value
                derivedValue = new DerivedValue(DerivedType.UInt16);

                string addressDefinition = signalReference.Substring(signalReference.IndexOf('-') + 1);
                string recordType        = addressDefinition.Substring(0, 2).ToUpperInvariant();
                ushort address           = ushort.Parse(addressDefinition.Substring(2));

                derivedValue.AddressRecords.Add(new AddressRecord(recordType, address));
            }
            else
            {
                // Derived type value
                indexOfType += 4;

                int      indexOfAt   = signalReference.IndexOf('@', indexOfType);
                string   derivedType = signalReference.Substring(indexOfType, indexOfAt - indexOfType).ToUpperInvariant();
                string[] addressList = signalReference.Substring(indexOfAt + 1).Split('#');

                derivedValue = new DerivedValue(derivedType);

                for (int i = 0; i < addressList.Length; i++)
                {
                    string addressDefinition = addressList[i].Trim();
                    string recordType        = addressDefinition.Substring(0, 2).ToUpperInvariant();
                    ushort address           = ushort.Parse(addressDefinition.Substring(2));
                    derivedValue.AddressRecords.Add(new AddressRecord(recordType, address));
                }
            }

            return(derivedValue);
        }
示例#3
0
        private void PollingOperation()
        {
            if ((object)m_modbusConnection == null)
            {
                return;
            }

            try
            {
                Ticks timestamp = DateTime.UtcNow.Ticks;
                Dictionary <MeasurementKey, Measurement> measurements = OutputMeasurements.Select(measurement => Measurement.Clone(measurement, timestamp)).ToDictionary(measurement => measurement.Key, measurement => measurement);
                Group[] groups = m_sequences.SelectMany(sequence => sequence.Groups).ToArray();
                int     measurementsReceived = 0;

                int overallTasksCompleted = 0;
                int overallTasksCount     = m_sequences.Count + 1;
                OnProgressUpdated(this, new ProgressUpdate(ProgressState.Processing, true, "Starting polling operation...", overallTasksCompleted, overallTasksCount));
                OnStatusMessage(MessageLevel.Info, $"Executing poll operation {m_pollOperations + 1}.");

                // Handle read/write operations for sequence groups
                try
                {
                    foreach (Sequence sequence in m_sequences)
                    {
                        foreach (Group group in sequence.Groups)
                        {
                            OnProgressUpdated(this, new ProgressUpdate(ProgressState.Processing, false, $"Executing poll for {sequence.Type.ToString().ToLowerInvariant()} sequence group \"{group.Type}@{group.StartAddress}\"...", 0, group.PointCount));

                            switch (group.Type)
                            {
                            case RecordType.DI:
                                group.DataValues = ReadDiscreteInputs(group.StartAddress, group.PointCount);
                                break;

                            case RecordType.CO:
                                if (sequence.Type == SequenceType.Read)
                                {
                                    group.DataValues = ReadCoils(group.StartAddress, group.PointCount);
                                }
                                else
                                {
                                    WriteCoils(group.StartAddress, group.DataValues);
                                }
                                break;

                            case RecordType.IR:
                                group.DataValues = ReadInputRegisters(group.StartAddress, group.PointCount);
                                break;

                            case RecordType.HR:
                                if (sequence.Type == SequenceType.Read)
                                {
                                    group.DataValues = ReadHoldingRegisters(group.StartAddress, group.PointCount);
                                }
                                else
                                {
                                    WriteHoldingRegisters(group.StartAddress, group.DataValues);
                                }
                                break;
                            }

                            OnProgressUpdated(this, new ProgressUpdate(ProgressState.Processing, false, $"Completed poll for {sequence.Type.ToString().ToLowerInvariant()} sequence group \"{group.Type}@{group.StartAddress}\".", group.PointCount, group.PointCount));
                            Thread.Sleep(m_interSequenceGroupPollDelay);
                        }

                        OnProgressUpdated(this, new ProgressUpdate(ProgressState.Processing, true, null, ++overallTasksCompleted, overallTasksCount));
                    }
                }
                catch
                {
                    m_deviceErrors++;
                    throw;
                }

                OnProgressUpdated(this, new ProgressUpdate(ProgressState.Processing, false, "Processing derived values...", 0, m_derivedValues.Count));

                // Calculate derived values
                foreach (KeyValuePair <MeasurementKey, DerivedValue> item in m_derivedValues)
                {
                    DerivedValue derivedValue = item.Value;
                    ushort[]     dataValues   = derivedValue.GetDataValues(groups);
                    Measurement  measurement;

                    if (measurements.TryGetValue(item.Key, out measurement))
                    {
                        // TODO: Properly interpret measurement types after GSF data type transport update
                        switch (derivedValue.Type)
                        {
                        case DerivedType.String:
                            if (derivedValue.AddressRecords.Count > 0)
                            {
                                m_derivedStrings[item.Key] = DeriveString(dataValues);
                                measurementsReceived++;
                            }
                            else
                            {
                                OnStatusMessage(MessageLevel.Warning, $"No address records defined for derived String value \"{item.Key}\".");
                            }
                            break;

                        case DerivedType.Single:
                            if (derivedValue.AddressRecords.Count > 1)
                            {
                                measurement.Value = DeriveSingle(dataValues[0], dataValues[1]);
                                measurementsReceived++;
                            }
                            else
                            {
                                OnStatusMessage(MessageLevel.Warning, $"{derivedValue.AddressRecords.Count} address records defined for derived Single value \"{item.Key}\", expected 2.");
                            }
                            break;

                        case DerivedType.Double:
                            if (derivedValue.AddressRecords.Count > 3)
                            {
                                measurement.Value = DeriveDouble(dataValues[0], dataValues[1], dataValues[2], dataValues[3]);
                                measurementsReceived++;
                            }
                            else
                            {
                                OnStatusMessage(MessageLevel.Warning, $"{derivedValue.AddressRecords.Count} address records defined for derived Double value \"{item.Key}\", expected 4.");
                            }
                            break;

                        case DerivedType.UInt16:
                            if (derivedValue.AddressRecords.Count > 0)
                            {
                                measurement.Value = dataValues[0];
                                measurementsReceived++;
                            }
                            else
                            {
                                OnStatusMessage(MessageLevel.Warning, $"No address records defined for UInt16 value \"{item.Key}\".");
                            }
                            break;

                        case DerivedType.Int32:
                            if (derivedValue.AddressRecords.Count > 1)
                            {
                                measurement.Value = DeriveInt32(dataValues[0], dataValues[1]);
                                measurementsReceived++;
                            }
                            else
                            {
                                OnStatusMessage(MessageLevel.Warning, $"{derivedValue.AddressRecords.Count} address records defined for derived Int32 value \"{item.Key}\", expected 2.");
                            }
                            break;

                        case DerivedType.UInt32:
                            if (derivedValue.AddressRecords.Count > 1)
                            {
                                measurement.Value = DeriveUInt32(dataValues[0], dataValues[1]);
                                measurementsReceived++;
                            }
                            else
                            {
                                OnStatusMessage(MessageLevel.Warning, $"{derivedValue.AddressRecords.Count} address records defined for derived UInt32 value \"{item.Key}\", expected 2.");
                            }
                            break;

                        case DerivedType.Int64:
                            if (derivedValue.AddressRecords.Count > 3)
                            {
                                measurement.Value = DeriveInt64(dataValues[0], dataValues[1], dataValues[2], dataValues[3]);
                                measurementsReceived++;
                            }
                            else
                            {
                                OnStatusMessage(MessageLevel.Warning, $"{derivedValue.AddressRecords.Count} address records defined for derived Int64 value \"{item.Key}\", expected 4.");
                            }
                            break;

                        case DerivedType.UInt64:
                            if (derivedValue.AddressRecords.Count > 3)
                            {
                                measurement.Value = DeriveUInt64(dataValues[0], dataValues[1], dataValues[2], dataValues[3]);
                                measurementsReceived++;
                            }
                            else
                            {
                                OnStatusMessage(MessageLevel.Warning, $"{derivedValue.AddressRecords.Count} address records defined for derived UInt64 value \"{item.Key}\", expected 4.");
                            }
                            break;
                        }
                    }

                    if (measurementsReceived % 20 == 0)
                    {
                        OnProgressUpdated(this, new ProgressUpdate(ProgressState.Processing, false, null, measurementsReceived, m_derivedValues.Count));
                    }
                }

                OnProgressUpdated(this, new ProgressUpdate(ProgressState.Processing, false, "Completed derived value processing.", m_derivedValues.Count, m_derivedValues.Count));
                OnProgressUpdated(this, new ProgressUpdate(ProgressState.Succeeded, true, "Polling operation complete.", overallTasksCount, overallTasksCount));

                OnNewMeasurements(measurements.Values.ToArray());

                m_measurementsReceived += measurementsReceived;
                m_pollOperations++;
            }
            catch (Exception ex)
            {
                OnProgressUpdated(this, new ProgressUpdate(ProgressState.Failed, true, $"Failed during poll operation: {ex.Message}", 0, 1));

                // Restart connection cycle when an exception occurs
                Start();
                throw;
            }
            finally
            {
                m_measurementsExpected += OutputMeasurements.Length;
            }
        }
示例#4
0
        /// <summary>
        /// Initializes <see cref="ModbusPoller" />.
        /// </summary>
        public override void Initialize()
        {
            base.Initialize();

            ConnectionStringParser <ConnectionStringParameterAttribute> parser = new ConnectionStringParser <ConnectionStringParameterAttribute>();

            parser.ParseConnectionString(ConnectionString, this);

            // Register downloader with the statistics engine
            StatisticsEngine.Register(this, "Modbus", "MOD");
            StatisticsEngine.Register(m_deviceProxy, Name, "Device", "PMU");

            // Attach to output measurements for Modbus device
            OutputMeasurements = ParseOutputMeasurements(DataSource, false, $"FILTER ActiveMeasurements WHERE Device = '{Name}'");

            // Parse derived value expressions from defined signal reference fields
            m_derivedValues = OutputMeasurements.Select(measurement => measurement.Key).ToDictionary(key => key, key =>
            {
                DataTable measurements    = DataSource.Tables["ActiveMeasurements"];
                DerivedValue derivedValue = null;
                DataRow[] records         = measurements.Select($"ID = '{key}'");

                if (records.Length > 0)
                {
                    derivedValue = ParseDerivedValue(records[0]["SignalReference"].ToNonNullString());
                }

                return(derivedValue);
            });

            m_sequences = new List <Sequence>();

            Dictionary <string, string> settings = Settings;
            string setting;
            int    sequenceCount = 0;

            if (settings.TryGetValue("sequenceCount", out setting))
            {
                int.TryParse(setting, out sequenceCount);
            }

            for (int i = 0; i < sequenceCount; i++)
            {
                if (settings.TryGetValue($"sequence{i}", out setting))
                {
                    Dictionary <string, string> sequenceSettings = setting.ParseKeyValuePairs();
                    SequenceType sequenceType = SequenceType.Read;

                    if (sequenceSettings.TryGetValue("sequenceType", out setting))
                    {
                        Enum.TryParse(setting, true, out sequenceType);
                    }

                    Sequence sequence = new Sequence(sequenceType);
                    int      groupCount;

                    if (sequenceSettings.TryGetValue("groupCount", out setting) && int.TryParse(setting, out groupCount))
                    {
                        for (int j = 0; j < groupCount; j++)
                        {
                            Group group = new Group();

                            if (sequenceSettings.TryGetValue($"groupType{j}", out setting))
                            {
                                Enum.TryParse(setting, true, out group.Type);
                            }

                            if (sequenceSettings.TryGetValue($"groupStartAddress{j}", out setting))
                            {
                                ushort.TryParse(setting, out group.StartAddress);
                            }

                            if (sequenceSettings.TryGetValue($"groupPointCount{j}", out setting))
                            {
                                ushort.TryParse(setting, out group.PointCount);
                            }

                            if (group.StartAddress > 0 && group.PointCount > 0)
                            {
                                // Load any defined write sequence values
                                if (sequence.Type == SequenceType.Write)
                                {
                                    group.DataValues = new ushort[group.PointCount];

                                    for (int k = 0; k < group.PointCount; k++)
                                    {
                                        if (sequenceSettings.TryGetValue($"group{j}DataValue{k}", out setting))
                                        {
                                            ushort.TryParse(setting, out group.DataValues[k]);
                                        }
                                    }
                                }

                                sequence.Groups.Add(group);
                            }
                        }
                    }

                    if (sequence.Groups.Count > 0)
                    {
                        m_sequences.Add(sequence);
                    }
                }
            }

            if (m_sequences.Count == 0)
            {
                throw new InvalidOperationException("No sequences defined, cannot start Modbus polling.");
            }

            // Define synchronized polling operation
            m_pollingOperation = new ShortSynchronizedOperation(PollingOperation, exception => OnProcessException(MessageLevel.Warning, exception));

            // Define polling timer
            m_pollingTimer           = new Timer(m_pollingRate);
            m_pollingTimer.AutoReset = true;
            m_pollingTimer.Elapsed  += m_pollingTimer_Elapsed;
        }