466 lines
24 KiB
C#
466 lines
24 KiB
C#
using Newtonsoft.Json;
|
|
using Newtonsoft.Json.Converters;
|
|
using Newtonsoft.Json.Linq;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using Xylem.Common.Hardware.WaterMeter.Genesis.Applications;
|
|
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
|
|
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers.DataTypes;
|
|
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers.RegisterProperties;
|
|
using Xylem.Common.Hardware.WaterMeter.WaterMeterRegisters;
|
|
|
|
namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
|
|
{
|
|
/// <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;
|
|
|
|
/// <summary>
|
|
/// Applications defined in configuration.json file
|
|
/// </summary>
|
|
public List<ApplicationDefinition> ConfigApplicationDefinitions;
|
|
|
|
/// <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");
|
|
}
|
|
|
|
Convert(File.ReadAllText(configFilePath));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert file content to register list
|
|
/// </summary>
|
|
/// <param name="fileContent"></param>
|
|
/// <returns></returns>
|
|
/// <exception cref="Exception"></exception>
|
|
private void Convert(String fileContent)
|
|
{
|
|
var applicationGroups = (JObject)JsonConvert.DeserializeObject(fileContent);
|
|
ConfigRegistersDefinitions = new List<IRegister>();
|
|
ConfigApplicationDefinitions = new List<ApplicationDefinition>();
|
|
try
|
|
{
|
|
//extract information of every application
|
|
if (applicationGroups != null)
|
|
foreach (var currentApplication in applicationGroups)
|
|
{
|
|
var o = (JObject)currentApplication.Value;
|
|
var application = new ApplicationDefinition();
|
|
Byte applicationAddress = 0;
|
|
|
|
foreach (var groupProp in o)
|
|
{
|
|
try
|
|
{
|
|
if (groupProp.Key == "id")
|
|
{
|
|
applicationAddress = groupProp.Value.Value<Byte>();
|
|
application.AppName = currentApplication.Key;
|
|
application.AppId = applicationAddress;
|
|
ConfigApplicationDefinitions.Add(application);
|
|
}
|
|
else if (groupProp.Key == "registers")
|
|
{
|
|
foreach (var registers in groupProp.Value)
|
|
{
|
|
var register = (JProperty)registers;
|
|
|
|
try
|
|
{
|
|
foreach (var registerJ in register.Value)
|
|
{
|
|
var reg = (JProperty)registerJ;
|
|
|
|
Byte? registerAddress = null;
|
|
if (reg.Name == "id")
|
|
{
|
|
registerAddress = (Byte)reg.Value;
|
|
}
|
|
|
|
if (reg.Name == "details")
|
|
{
|
|
var details = ((JArray)reg.Value);
|
|
|
|
foreach (var jdetail in details.Children())
|
|
{
|
|
var actualRegister = new RegisterDefinition();
|
|
var idTag = reg.Parent.First(f => ((JProperty)f).Name == "id");
|
|
var id = (Byte)(JProperty)idTag; //.Value<int>();
|
|
|
|
if (registerAddress.HasValue)
|
|
{
|
|
throw new Exception("invalid json cast");
|
|
}
|
|
|
|
actualRegister.RegAddressInApp = id;
|
|
actualRegister.AppName = currentApplication.Key;
|
|
actualRegister.AppAddress = applicationAddress;
|
|
actualRegister.RegisterDetail = new RegisterDetail();
|
|
actualRegister.RegisterName = register.Name;
|
|
var detailO = (JObject)jdetail;
|
|
JProperty detail;
|
|
detail = detailO.Property("privilege");
|
|
if (detail.Name == "privilege")
|
|
{
|
|
actualRegister.RegisterDetail.Privilege =
|
|
JsonConvert.DeserializeObject<Privilege>(
|
|
detail.Value.ToString(), Settings);
|
|
}
|
|
|
|
detail = detailO.Property("type");
|
|
if (detail.Name == "type")
|
|
{
|
|
actualRegister.DataType =
|
|
typeof(String); // detail.Value.ToString();
|
|
|
|
switch (detail.Value.ToString().ToLower())
|
|
{
|
|
case "bool_t":
|
|
actualRegister.DataType = typeof(Boolean);
|
|
break;
|
|
case "rpc":
|
|
actualRegister.DataType = typeof(Rpc);
|
|
break;
|
|
case "string":
|
|
actualRegister.DataType = typeof(String);
|
|
break;
|
|
case "uint32_t":
|
|
actualRegister.DataType = typeof(UInt32);
|
|
break;
|
|
case "time_t":
|
|
actualRegister.DataType = typeof(TimeT);
|
|
break;
|
|
case "status_t":
|
|
actualRegister.DataType = typeof(StatusT);
|
|
break;
|
|
case "uint16_t":
|
|
actualRegister.DataType = typeof(UInt16);
|
|
break;
|
|
case "uint8_t":
|
|
actualRegister.DataType = typeof(byte);
|
|
break;
|
|
case "enum8":
|
|
actualRegister.DataType = typeof(Enum8);
|
|
break;
|
|
case "uint64_t":
|
|
actualRegister.DataType = typeof(UInt64);
|
|
break;
|
|
case "uint96_t":
|
|
actualRegister.DataType = typeof(UInt96);
|
|
break;
|
|
case "int8_t":
|
|
actualRegister.DataType = typeof(sbyte);
|
|
break;
|
|
case "int32_t":
|
|
actualRegister.DataType = typeof(Int32);
|
|
break;
|
|
case "int64_t":
|
|
actualRegister.DataType = typeof(Int64);
|
|
break;
|
|
case "int16_t":
|
|
actualRegister.DataType = typeof(Int16);
|
|
break;
|
|
}
|
|
}
|
|
|
|
detail = detailO.Property("description");
|
|
if (detail.Name == "description")
|
|
{
|
|
actualRegister.RegisterDetail.Description =
|
|
detail.Value.ToString();
|
|
}
|
|
|
|
detail = detailO.Property("version");
|
|
if (detail.Name == "version")
|
|
{
|
|
actualRegister.RegisterDetail.Version =
|
|
JsonConvert.DeserializeObject<FwVersion>(
|
|
detail.Value.ToString());
|
|
}
|
|
|
|
detail = detailO.Property("values");
|
|
if (detail != null && detail.Name == "values")
|
|
{
|
|
foreach (var dValues in detail.Children().First())
|
|
{
|
|
switch (((JProperty)dValues).Name)
|
|
{
|
|
case "default":
|
|
actualRegister.Default =
|
|
(Int64)((JProperty)dValues).Value;
|
|
break;
|
|
case "maximum":
|
|
actualRegister.Maximum =
|
|
(Int64)((JProperty)dValues).Value;
|
|
break;
|
|
case "minimum":
|
|
actualRegister.Minimum =
|
|
(Int64)((JProperty)dValues).Value;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
detail = detailO.Property(StaticType.StaticTypeFieldIdentifier);
|
|
if (detail != null && detail.Name ==
|
|
StaticType.StaticTypeFieldIdentifier)
|
|
{
|
|
actualRegister.RestoreCapability =
|
|
new StaticType(detail.Value.ToString());
|
|
}
|
|
|
|
ConfigRegistersDefinitions.Add(actualRegister);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception )
|
|
{
|
|
//todo log ex
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception )
|
|
{
|
|
//todo log ex
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception )
|
|
{
|
|
// ignored
|
|
}
|
|
|
|
|
|
////tofile
|
|
var listOfRegisters = new List<RegisterDefinition>();
|
|
foreach (var item in ConfigRegistersDefinitions)
|
|
{
|
|
if (item is RegisterDefinition reg)
|
|
{
|
|
if (listOfRegisters.Any(a => a.GetIdent() == reg.GetIdent()))
|
|
{
|
|
var oldItem = listOfRegisters.First(a => a.GetIdent() == reg.GetIdent());
|
|
if (oldItem.RegisterDetail.Version.Last < reg.RegisterDetail.Version.Last)
|
|
{
|
|
listOfRegisters.Remove(oldItem);
|
|
listOfRegisters.Add(reg);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
listOfRegisters.Add(reg);
|
|
}
|
|
}
|
|
}
|
|
//#region create a file for my american friends
|
|
//var sbCSV = new StringBuilder();
|
|
|
|
//sbCSV.AppendLine("Filter;Ident;First;Last");
|
|
//foreach (var item in ConfigRegistersDefinitions)
|
|
//{
|
|
// if (item is RegisterDefinition Reg)
|
|
// {
|
|
// sbCSV.AppendLine($"ALL;{Reg.GetIdent()};{Reg.RegisterDetail.Version.First}; {Reg.RegisterDetail.Version.Last};");
|
|
// }
|
|
//}
|
|
|
|
//foreach (var item in lsitOfRegisters)
|
|
//{
|
|
// sbCSV.AppendLine($"InUse;{item.GetIdent()};{item.RegisterDetail.Version.First}; {item.RegisterDetail.Version.Last};");
|
|
//}
|
|
|
|
//foreach (var item in lsitOfRegisters)
|
|
//{
|
|
// sbCSV.AppendLine($"InUse;{item.GetIdent()};{item.RegisterDetail.Version.First}; {item.RegisterDetail.Version.Last};");
|
|
//}
|
|
//var k = sbCSV.ToString();
|
|
|
|
//sbCSV.AppendLine("###");
|
|
//sbCSV.AppendLine("###");
|
|
//sbCSV.AppendLine("###");
|
|
|
|
//sbCSV.AppendLine("App;Version");
|
|
//foreach (var item in lsitOfRegisters)
|
|
//{
|
|
// sbCSV.AppendLine($"InUse;{item.GetIdent()};{item.RegisterDetail.Version.First}; {item.RegisterDetail.Version.Last};");
|
|
//}
|
|
|
|
//foreach (var grpReg in lsitOfRegisters.GroupBy(g => g.AppName))
|
|
//{
|
|
|
|
// sb.AppendLine($"public static class {grpReg.Key} {{");
|
|
// foreach (var item in grpReg)
|
|
// {
|
|
// sbCSV.Append($"{grpReg.Key};{item.RegisterName};{item.DataType.Name};{item.RegisterDetail.Description}");
|
|
|
|
// sbCSV.Append($";{ item.RegisterDetail.Privilege.Lvl1.ToString()}");
|
|
// sbCSV.Append($";{ item.RegisterDetail.Privilege.Lvl2.ToString()}");
|
|
// sbCSV.Append($";{ item.RegisterDetail.Privilege.Lvl3.ToString()}");
|
|
// sbCSV.Append($";{ item.RegisterDetail.Privilege.Lvl4.ToString()}");
|
|
// sbCSV.Append($";{ item.RegisterDetail.Privilege.Lvl5.ToString()}");
|
|
// sbCSV.Append($";{ item.RegisterDetail.Privilege.Lvl6.ToString()}");
|
|
// sbCSV.Append($";{ item.RegisterDetail.Privilege.Lvl7.ToString()}");
|
|
// sbCSV.Append($";{ item.RegisterDetail.Privilege.Lvl8.ToString()}");
|
|
|
|
|
|
// sb.AppendLine($"public static readonly RegisterDefinition {item.RegisterName} = new RegisterDefinition() {{");
|
|
// sb.AppendLine($"DataType = typeof({item.DataType.Name}),");
|
|
// sb.AppendLine($"Address = new byte[2] {{ (byte){item.RegisterAddress[0]}, (byte){item.RegisterAddress[1]} }},");
|
|
|
|
// sb.AppendLine($"Default = new long?(");
|
|
// if (item.Default.HasValue)
|
|
// {
|
|
// sb.Append(item.Default.Value);
|
|
// sbCSV.Append($";{item.Default.Value}");
|
|
// }
|
|
// else
|
|
// {
|
|
// sbCSV.Append(";-");
|
|
// }
|
|
|
|
// sb.Append($"),");
|
|
|
|
// sb.AppendLine($"Maximum = new long?(");
|
|
// if (item.Maximum.HasValue)
|
|
// {
|
|
// sb.Append(item.Maximum.Value);
|
|
// sbCSV.Append($";{item.Maximum.Value}");
|
|
// }
|
|
// else
|
|
// {
|
|
// sbCSV.Append(";-");
|
|
// }
|
|
// sb.Append($"),");
|
|
|
|
// sb.AppendLine($"Minimum = new long?(");
|
|
// if (item.Minimum.HasValue)
|
|
// {
|
|
// sb.Append(item.Minimum.Value);
|
|
// sbCSV.Append($";{item.Minimum.Value}");
|
|
// }
|
|
// else
|
|
// {
|
|
// sbCSV.Append(";-");
|
|
// }
|
|
// sb.Append($"),");
|
|
// sb.AppendLine($"Detail = new Detail(){{");
|
|
// sb.AppendLine($" Description = \"{item.RegisterDetail.Description}\",");
|
|
// sb.AppendLine($" Version = new Version(1,{item.RegisterDetail.Version.Last}),");
|
|
// sb.AppendLine($" Privilege = new Privilege(){{");
|
|
// //
|
|
|
|
// sb.AppendLine($" Lvl1 = Access.{item.RegisterDetail.Privilege.Lvl1.ToString()},");
|
|
// sb.AppendLine($" Lvl2 = Access.{item.RegisterDetail.Privilege.Lvl2.ToString()},");
|
|
// sb.AppendLine($" Lvl3 = Access.{item.RegisterDetail.Privilege.Lvl3.ToString()},");
|
|
// sb.AppendLine($" Lvl4 = Access.{item.RegisterDetail.Privilege.Lvl4.ToString()},");
|
|
// sb.AppendLine($" Lvl5 = Access.{item.RegisterDetail.Privilege.Lvl5.ToString()},");
|
|
// sb.AppendLine($" Lvl6 = Access.{item.RegisterDetail.Privilege.Lvl6.ToString()},");
|
|
// sb.AppendLine($" Lvl7 = Access.{item.RegisterDetail.Privilege.Lvl7.ToString()},");
|
|
// sb.AppendLine($" Lvl8 = Access.{item.RegisterDetail.Privilege.Lvl8.ToString()},");
|
|
|
|
// sb.AppendLine($" }}");
|
|
// sb.AppendLine($"}}");
|
|
// sb.AppendLine($"}};");
|
|
// sbCSV.AppendLine(";");
|
|
// }
|
|
// sb.AppendLine($"}}");
|
|
//}
|
|
//#endregion
|
|
//var z = sbCSV.ToString();
|
|
|
|
//var code = sb.ToString();
|
|
}
|
|
|
|
internal class LvlConverter : JsonConverter
|
|
{
|
|
public override Boolean CanConvert(Type t) => t == typeof(Access) || t == typeof(Access?);
|
|
|
|
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);
|
|
switch (value)
|
|
{
|
|
case "NA":
|
|
return Access.Na;
|
|
case "RO":
|
|
return Access.Ro;
|
|
case "RW":
|
|
return Access.Rw;
|
|
case "WO":
|
|
return Access.Wo;
|
|
}
|
|
throw new Exception("Cannot unmarshal type Lvl");
|
|
}
|
|
|
|
public override void WriteJson(JsonWriter writer, Object untypedValue, JsonSerializer serializer)
|
|
{
|
|
if (untypedValue == null)
|
|
{
|
|
serializer.Serialize(writer, null);
|
|
return;
|
|
}
|
|
var value = (Access)untypedValue;
|
|
switch (value)
|
|
{
|
|
case Access.Na:
|
|
serializer.Serialize(writer, "NA");
|
|
return;
|
|
case Access.Ro:
|
|
serializer.Serialize(writer, "RO");
|
|
return;
|
|
case Access.Rw:
|
|
serializer.Serialize(writer, "RW");
|
|
return;
|
|
case Access.Wo:
|
|
serializer.Serialize(writer, "WO");
|
|
return;
|
|
}
|
|
throw new Exception("Cannot marshal type Lvl");
|
|
}
|
|
public static readonly LvlConverter Singleton = new LvlConverter();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Settings
|
|
/// </summary>
|
|
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
|
|
{
|
|
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
|
|
DateParseHandling = DateParseHandling.None,
|
|
Converters =
|
|
{
|
|
LvlConverter.Singleton,
|
|
new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
|
|
},
|
|
};
|
|
}
|
|
}
|