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; } }
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); }
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; } }
/// <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; }