laatzen/Common/Hardware/WaterMeter/Genesis/GenesisCore/GenesisConfigReader.cs
Thomas Wiedebusch 0f784bfb03 Genesis: - data types UInt48/72/88 supported,
manual merge from Dev_Shipping - part 1
2025-03-17 18:17:28 +01:00

238 lines
7.9 KiB
C#

namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
{
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using Applications;
using Registers;
using Registers.DataTypes;
using Registers.Json;
using WaterMeterRegisters;
/// <summary>
/// JSON filer reader for generation of register lists
/// </summary>
public class GenesisConfigurationReader
{
/// <summary>
/// Registers defined in configuration.json file
/// </summary>
public List<IRegister> ConfigRegistersDefinitions { get; }
= new List<IRegister>();
/// <summary>
/// Applications defined in configuration.json file
/// </summary>
public List<ApplicationDefinition> ConfigApplicationDefinitions { get; }
= new List<ApplicationDefinition>();
/// <summary>
/// Ctor
/// </summary>
public GenesisConfigurationReader() {}
/// <summary>
/// Ctor
/// </summary>
/// <param name="configFilePath">the file path for configuration.json as interface description to the meter</param>
public GenesisConfigurationReader(String configFilePath)
{
if (string.IsNullOrEmpty(configFilePath))
{
throw new ApplicationException("JsonFileRegisterReader needs at least one file path");
}
if (!File.Exists(configFilePath))
{
throw new ApplicationException($" {configFilePath} doesn't exists");
}
BuildRegisterList(File.ReadAllText(configFilePath));
}
/// <summary>
/// Convert file content to register list
/// </summary>
/// <param name="configurationJson"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public void BuildRegisterList(String configurationJson)
{
IDictionary<String, AppSection> sections;
try
{
sections = JsonConvert
.DeserializeObject<IDictionary<String, AppSection>>(configurationJson, SerializerSettings)
?? new Dictionary<String, AppSection>();
}
catch (Exception )
{
sections = new Dictionary<String, AppSection>();
}
foreach (var sectionKVP in sections)
{
var appId = sectionKVP.Value.Id;
var appName = sectionKVP.Key;
ConfigApplicationDefinitions.Add(new ApplicationDefinition
{
AppId = appId,
AppName = appName
});
var section = sectionKVP.Value;
var registers = section.Registers;
if (registers is null)
{
continue;
}
foreach (var registerKVP in registers)
{
var register = registerKVP.Value;
if (register is null)
{
continue;
}
var details = register.Details;
if (details is null)
{
continue;
}
var regId = register.Id;
foreach (var detail in details)
{
var values = detail.Values;
ConfigRegistersDefinitions.Add(new RegisterDefinition
{
AppAddress = appId,
AppName = appName,
DataType = GetType(detail.Type),
Default = values?.Default is Int64 d ? d : default(Int64?),
IsAvailable = default(Boolean),
Maximum = values?.Maximum is Int64 max ? max : default(Int64?),
Minimum = values?.Minimum is Int64 min ? min : default(Int64?),
RegAddressInApp = regId,
// RegisterAddress = new byte[] { appId, regId },
RegisterDetail = detail,
RegisterName = registerKVP.Key,
RestoreCapability = new StaticType(detail.StaticType)
});
}
}
}
}
/// <summary>
/// Settings
/// </summary>
private static readonly JsonSerializerSettings SerializerSettings = new JsonSerializerSettings
{
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
DateParseHandling = DateParseHandling.None,
Converters =
{
AccessConverter.Singleton,
new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
},
};
private static Type GetType(String value)
{
switch (value.ToLower())
{
case "bool_t": return typeof(Boolean);
case "rpc": return typeof(Rpc);
case "string": return typeof(String);
case "uint32_t": return typeof(UInt32);
case "time_t": return typeof(TimeT);
case "status_t": return typeof(StatusT);
case "uint16_t": return typeof(UInt16);
case "uint8_t": return typeof(Byte);
case "enum8": return typeof(Enum8);
case "uint64_t": return typeof(UInt64);
case "uint96_t": return typeof(UInt96);
case "uint128_t": return typeof(UInt128);
case "int8_t": return typeof(SByte);
case "int32_t": return typeof(Int32);
case "int64_t": return typeof(Int64);
case "int16_t": return typeof(Int16);
case "uint72_t": return typeof(UInt72);
case "uint48_t": return typeof(UInt48);
case "uint88_t": return typeof(UInt88);
default: throw new Exception($"Type {value} not recognized!");
}
}
}
/// <summary>
///
/// </summary>
public class AccessConverter : JsonConverter
{
/// <summary>
///
/// </summary>
/// <param name="t"></param>
/// <returns></returns>
public override Boolean CanConvert(Type t) => t == typeof(Access) || t == typeof(Access?);
/// <summary>
///
/// </summary>
/// <param name="reader"></param>
/// <param name="t"></param>
/// <param name="existingValue"></param>
/// <param name="serializer"></param>
/// <returns></returns>
public override Object ReadJson(JsonReader reader, Type t, Object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
{
return null;
}
var value = serializer.Deserialize<String>(reader);
return Enum.TryParse(value, true, out Access access) ? access : default(Access);
}
/// <summary>
///
/// </summary>
/// <param name="writer"></param>
/// <param name="untypedValue"></param>
/// <param name="serializer"></param>
public override void WriteJson(JsonWriter writer, Object untypedValue, JsonSerializer serializer)
{
if (untypedValue is Access access)
{
writer.WriteValue(access.ToString());
}
else
{
throw new Exception("Cannot marshal type Lvl");
}
}
/// <summary>
///
/// </summary>
public static readonly AccessConverter Singleton = new AccessConverter();
}
}