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 { /// /// JSON filer reader for generation of register lists /// public class GenesisConfigurationReader { /// /// Registers defined in configuration.json file /// public List ConfigRegistersDefinitions; /// /// Applications defined in configuration.json file /// public List ConfigApplicationDefinitions; /// /// Ctor /// /// the file path for configuration.json as interface description to the meter 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)); } /// /// Convert file content to register list /// /// /// /// private void Convert(String fileContent) { var applicationGroups = (JObject)JsonConvert.DeserializeObject(fileContent); ConfigRegistersDefinitions = new List(); ConfigApplicationDefinitions = new List(); 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(); 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(); 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( 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( 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(); 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(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(); } /// /// Settings /// public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings { MetadataPropertyHandling = MetadataPropertyHandling.Ignore, DateParseHandling = DateParseHandling.None, Converters = { LvlConverter.Singleton, new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal } }, }; } }