common/Ui/GenesisToolBox/FrmLog.cs
2026-04-23 17:50:07 +02:00

529 lines
19 KiB
C#

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore;
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore;
namespace Xylem.Common.Ui.GenesisToolBox
{
public partial class FrmLog : Form
{
public GenesisMeter _currentGenesis { get; private set; }
public MeterBatch _meterBatch { get; private set; }
public FrmLog()
{
InitializeComponent();
}
private void button1_Click(Object sender, EventArgs e)
{
}
private void btnConnect_Click(Object sender, EventArgs e)
{
Connect();
}
/// <remarks date="2025-Oct-02" author="Thomas Wiedebusch">
/// - Catch error message on unknown data type and kill meter.
/// </remarks>
private void Connect()
{
try
{
var statusMap = new Dictionary<Int32, String>();
if (System.IO.File.Exists("Status.json"))
{
var dict = JsonConvert.DeserializeObject<Dictionary<String, JObject>>(System.IO.File.ReadAllText("Status.json"));
foreach (var item in dict)
{
statusMap.Add(int.Parse(item.Value.First.Values().First().ToString()), item.Key);
}
//var jo = JObject.Parse();
//((JObject)jo).ChildrenTokens
//var retListRealCsd = JsonConvert.DeserializeObject(<List<CsdParameterResult>>(retStr);
}
Int32 slotNr;
if (string.IsNullOrEmpty(cbComSlot.SelectedItem.ToString()) ||
!int.TryParse(cbComSlot.SelectedItem.ToString(), out slotNr))
{
return;
}
//var drive = 1;
_currentGenesis?.DisposeMeter();
//dispose old meter
_meterBatch = new MeterBatch();
_currentGenesis = null;
Thread.Sleep(200);
//assign new meter and assign meter to FW update file if this exists
_currentGenesis = new GenesisMeter();
_currentGenesis.SetupFromConfigFile(slotNr);
_meterBatch.AddMeter(_currentGenesis);
_currentGenesis.Configuration.UseRegisterWatchService = false;
_currentGenesis.Configuration.UseMinMaxCheck = false;
Task.Factory.StartNew(() =>
{
_meterBatch.MetersLogin();
if (!_currentGenesis.IsLoggedOn)
{
Thread.Sleep(2000);
_meterBatch.MetersLogin();
}
if (!_currentGenesis.IsLoggedOn)
{
return;
}
StringBuilder print = new StringBuilder();
print.AppendLine($"Meter time: { ByteArrayStyle.ByteStyler.ToString(_currentGenesis.ReadRegister("SYSTEM_CalendarSeconds"))}");
//flush the log files
print.AppendLine($"Flushing the logger");
_currentGenesis.WriteRegister("LOGGER_TriggerLogFlush", 1);
// read the log index
print.AppendLine($"Reading the list of log files");
var fl = get_filenames(_currentGenesis, 1);
var flHash = new HashSet<String>(fl);
fl = flHash.ToList();
var data = new Dictionary<String, List<Byte>>();
foreach (var fileName in fl)
{
print.AppendLine($"Reading the log files");
var fileData = new List<Byte>();
var listBack = new List<Byte>();
var namelist = new List<String>();
//write file name to meter with meter open command, don't wait for response
_currentGenesis.WriteRegister(Register.Configexchange.FileOpen, $"{1}\\{fileName}", false);
//write access flag
_currentGenesis.WriteRegister(Register.Configexchange.FileOpen, "r", false);
//CONFIGEXCHANGE_FOpen -> 02040400315c6c6f67696e646578000072000000
//get the file pointer
var _filePointer = RegisterConverter.ByteArrayToValue<Int32>(_currentGenesis.ReadRegister(
Register.Configexchange.FileOpen));
_currentGenesis.WriteRegister("CONFIGEXCHANGE_FSeek", _filePointer, false);
_currentGenesis.WriteRegister("CONFIGEXCHANGE_FSeek", 0, false);
_currentGenesis.WriteRegister("CONFIGEXCHANGE_FSeek", 2, false);
_currentGenesis.WriteRegister("CONFIGEXCHANGE_FTell", _filePointer, false);
var fixedReadBackCount = RegisterConverter.ByteArrayToValue<Int32>(_currentGenesis.ReadRegister("CONFIGEXCHANGE_FTell"));
_currentGenesis.WriteRegister("CONFIGEXCHANGE_FSeek", _filePointer, false);
_currentGenesis.WriteRegister("CONFIGEXCHANGE_FSeek", 0, false);
_currentGenesis.WriteRegister("CONFIGEXCHANGE_FSeek", 0, false);
_currentGenesis.WriteRegister("CONFIGEXCHANGE_FRead", 1, false);
_currentGenesis.WriteRegister("CONFIGEXCHANGE_FRead", fixedReadBackCount, false);
_currentGenesis.WriteRegister("CONFIGEXCHANGE_FRead", _filePointer, false);
var count_ret = RegisterConverter.ByteArrayToValue<Int32>(_currentGenesis.ReadRegister("CONFIGEXCHANGE_FRead"));
while (count_ret != 0)
{
var numRead = 0;
//
while (numRead <= count_ret / 4)
{
var readAdd = _currentGenesis.ReadRegister("CONFIGEXCHANGE_FRead");
if (readAdd != null)
{
fileData.AddRange(readAdd);
}
numRead = numRead + 1;
}
count_ret = RegisterConverter.ByteArrayToValue<Int32>(_currentGenesis.ReadRegister("CONFIGEXCHANGE_FRead"));
}
_currentGenesis.WriteRegister(Register.Configexchange.FileClose, _filePointer);
data.Add(fileName, fileData);
}
var loglines = new List<String>();
foreach (var item in data)
{
print.AppendLine(item.Key);
print.AppendLine($"all data: { ByteArrayStyle.ByteStyler.ToString(item.Value.ToArray())}");
if (item.Value != null && item.Value.Count >= 4)
{
var logtype = item.Value.GetRange(0, 1).First().ToString();
var status = BitConverter.ToUInt16(item.Value.GetRange(1, 2).ToArray(), 0);
var count = (Int32)BitConverter.ToUInt16(item.Value.GetRange(2, 2).ToArray(), 0);
count = count + 1;
var extradatasize = item.Value.GetRange(3, 1).First().ToString();
//var extradatasize = BitConverter.ToChar(item.Value.GetRange(3, 1).ToArray(), 0);
switch (logtype)
{
case "0":
logtype = $"({logtype}) Informational";
break;
case "1":
logtype = $"({logtype}) Warning";
break;
case "2":
logtype = $"({logtype}) Critical";
break;
}
print.AppendLine($"logtype:{logtype}");
if (statusMap.ContainsKey(status))
{
print.AppendLine($"status: ({status}) {statusMap[status]}");
}
else
{
print.AppendLine($"status:{status}");
}
print.AppendLine($"count:{count}");
print.AppendLine($"extradatasize:{extradatasize}");
var extradtalength = 0;
if (int.TryParse(extradatasize, out extradtalength))
{
print.Append("Extra data: ");
for (Int32 i = 0; i <= extradtalength; i++)
{
print.Append(item.Value.GetRange(i, 2).First().ToString("X2"));
print.Append(" ");
}
print.AppendLine();
}
}
else
{
print.AppendLine($"file is empty");
}
}
_currentGenesis.Logout();
Invoke(new Action(() =>
{
richTextBox1.Text = print.ToString();
}));
}).ContinueWith(delegate { ViewProgressPcb(false); });
}
catch (Exception ex)
{
ViewProgressPcb(false);
MessageBox.Show(ex.Message, @"FAILED", MessageBoxButtons.OK, MessageBoxIcon.Error);
// Dispose meter
_meterBatch.RemoveAllMeters();
// If meter is not already assigned to batch as the config reader may fail
_currentGenesis?.DisposeMeter();
}
}
private void ViewProgressPcb(Boolean v)
{
}
private List<String> get_filenames(GenesisMeter m, Int32 drive = 1)
{
var listBack = new List<Byte>();
var namelist = new List<String>();
//write file name to meter with meter open command, don't wait for response
m.WriteRegister(Register.Configexchange.FileOpen, $"1\\logindex", false);
//write access flag
m.WriteRegister(Register.Configexchange.FileOpen, "r", false);
//CONFIGEXCHANGE_FOpen -> 02040400315c6c6f67696e646578000072000000
//get the file pointer
var _filePointer = RegisterConverter.ByteArrayToValue<Int32>(m.ReadRegister(
Register.Configexchange.FileOpen));
//set timeout back to default value
//CONFIGEXCHANGE_FOpen <- 030a0000584400209ae0 (536888408)
var eof = false;
while (!eof)
{
//CONFIGEXCHANGE_FEOF-> 9b2007020b0904584400207a27(XD)
m.WriteRegister("CONFIGEXCHANGE_FEOF", _filePointer, false);
//CONFIGEXCHANGE_FEOF <-030a0000000000004194 (0)
var res = RegisterConverter.ByteArrayToValue<Int32>(m.ReadRegister("CONFIGEXCHANGE_FEOF"));
if (res != 0)
{
eof = true;
break;
}
m.WriteRegister("CONFIGEXCHANGE_FRead", 4, false);
m.WriteRegister("CONFIGEXCHANGE_FRead", 1, false);
m.WriteRegister("CONFIGEXCHANGE_FRead", _filePointer, false);
var resLength = RegisterConverter.ByteArrayToValue<Int32>(m.ReadRegister("CONFIGEXCHANGE_FRead"));
var filecontent = m.ReadRegister("CONFIGEXCHANGE_FRead", resLength);
namelist.Add(RegisterConverter.ByteArrayToValue<Int32>(filecontent).ToString("X8"));
}
_currentGenesis.WriteRegister(Register.Configexchange.FileClose, _filePointer);
return namelist;
}
private void label2_Click(Object sender, EventArgs e)
{
}
private void cbComSlot_SelectedIndexChanged(Object sender, EventArgs e)
{
}
}
}
//import opticalinterface.opticalapp as oa
//import struct
//import
//import datetime
//class LogEntry(object):
// statusdict = dict()
// STATUSFILENAME = 'status.json'
// @classmethod
// def bytes_to_log(cls, filename, data) :
// logformat = "<BHBB"
// entries = list()
// while data:
// logtype, status, count, extradatasize = struct.unpack_from(logformat, data)
// data = data[struct.calcsize(logformat) :]
// # count is stored as count-1
// count += 1
// extradata = data[:extradatasize]
// entries.append(cls(filename, logtype, count, status, extradata))
// data = data[extradatasize:]
// return entries
// def __init__(self, filename, logtype, count, status, extradata=[]) :
// self.filename = filename
// self.logtype = logtype
// self.count = count
// self.status = status
// self.extradata = extradata
// self.filenametime = datetime.datetime(2000, 1, 1) + datetime.timedelta(seconds = int(filename, 16))
// def log_type_name(self):
// if self.logtype == 0:
// return "Informational"
// if self.logtype == 1:
// return "Warning"
// if self.logtype == 2:
// return "Critical"
// return "Unknown logtype"
// def status_lookup(self, status= None):
// #if the status dictionary is empty populate it
// if len(self.statusdict) == 0:
// with open(self.STATUSFILENAME) as fp:
// self.statusdict = json.load(fp)
// if status == None:
// status = self.status
// try:
// return [x for x in self.statusdict if self.statusdict[x]['id'] == status][0]
// except IndexError:
// return "Unknown status {:04X}".format(status)
// def guess_extra_data(self):
//# now try some data types to guess the extra data
// ret = list()
//# timestamp followed by uint32_t
// try:
// data = struct.unpack("<II", self.extradata)
// extraword = data[1]
// ts = datetime.datetime(2000, 1, 1) + datetime.timedelta(seconds=data[0])
// ret += ["Timestamp: {}, uint32_t: {}".format(ts, extraword)]
// except:
// pass
//# timestamp followed by status
// try:
// data = struct.unpack("<IH", self.extradata)
// status = self.status_lookup(data[1])
// ts = datetime.datetime(2000, 1, 1) + datetime.timedelta(seconds=data[0])
// ret += ["Timestamp: {}, Status: {}".format(ts, status)]
// except:
// pass
//# timestamp followed by byte
// try:
// data = struct.unpack("<IB", self.extradata)
// extrabyte = data[1]
// ts = datetime.datetime(2000, 1, 1) + datetime.timedelta(seconds=data[0])
// ret += ["Timestamp: {}, Byte: {}".format(ts, extrabyte)]
// except:
// pass
//# just timestamp
// try:
// data = struct.unpack("<I", self.extradata)
// ts = datetime.datetime(2000, 1, 1) + datetime.timedelta(seconds=data[0])
// ret += ["Timestamp: {}".format(ts)]
// except:
// pass
//# uint32_t
// try:
// data = struct.unpack("<I", self.extradata)
// ret += ["uint32_t: {}".format(data[0])]
// except:
// pass
//# uint16_t
// try:
// data = struct.unpack("<H", self.extradata)
// ret += ["uint16_t: {}".format(data[0])]
// except:
// pass
//# uint8_t
// try:
// data = struct.unpack("<B", self.extradata)
// ret += ["uint8_t: {}".format(data[0])]
// except:
// pass
// return "\nor\n".join(ret)
// def __repr__(self):
// text = "File: {} ({})\n".format(self.filename, self.filenametime)
// text += "Severity: {}\n".format(self.log_type_name())
// text += "Status: {}\n".format(self.status_lookup())
// text += "Count: {}\n".format(self.count)
// text += "Extra data: "
// text += " ".join(["{:02X}".format(x) for x in self.extradata])
// text += "\n"
// guess = self.guess_extra_data()
// if guess:
// text += "Extra data may be:\n{}\n".format(guess)
// return text
//def get_filenames(optical, drive):
//# open the index file
// handle = optical.fopen("{}\\logindex".format(drive), "r")
// namelist = list()
// while not optical.feof(handle):
//# read a filename entry
// numread, name = optical.fread(4, 1, handle)
// if numread != 1:
//# we're not at the end of the file but we don't have a full filename
// break
//# convert the name bytes to a number
// name = struct.unpack("<I", name)[0]
//# and now convert the number to a string
// name = "{:08X}".format(name)
//# add the name to the list
// namelist.append(name)
// optical.fclose(handle)
// return namelist
//def read_file(optical, drive, file):
// alldata = bytearray()
//# open the file
// handle = optical.fopen("{}\\{}".format(drive, file), "r")
// if handle == 0:
// print("Couldn't open {}, it could be in use by Logger".format(file))
// else:
//# work out how big the file is
// optical.fseek(handle, 0, 2)
// numbytes = optical.ftell(handle)
// optical.fseek(handle, 0, 0)
//# read all the data
// bytesread, data = optical.fread(1, numbytes, handle)
// optical.fclose(handle)
// print("Read {} bytes from {}".format(bytesread, file))
//# stick it in a big structure
// alldata += bytearray(data)
// return alldata
//if __name__ == '__main__':
// import logging
// import argparse
// parser = argparse.ArgumentParser(description="Read the log entries from a Genesis"
// " 'optical' port")
// parser.add_argument('serialport', help='what serial port to use')
// parser.add_argument('--drive', default=1, help='meter drive to read')
// parser.add_argument('--irda', action='store_true', default=False)
// args = parser.parse_args()
//# Open the serial port
// o = oa.BreezeOptical(args.serialport, irda=args.irda)
//# log into the meter
// print("Logging out - to get a stable start situation")
//# logging.basicConfig(level=logging.DEBUG, filename= '18708048.log', filemode='w')
// o.login(0)
//# print the serial number
// print("PCB Serial Number: {}".format(o.CONFIGEXCHANGE_PCBSerialNumber))
//# log into the meter
// print("Logging in")
// o.login(8)
//# print the meter time
// print("Meter time: {}".format(o.SYSTEM_CalendarSeconds))