Refactor PoseidonReader to use lazy initialization for CliRunner, introduce SafetyTimeOut, enhance JSON deserialization with fallback logic, and improve error logging using log4net.

This commit is contained in:
Michal Buzik 2025-09-09 20:47:53 +02:00
parent 35e4078dda
commit 780d44166e
3 changed files with 78 additions and 20 deletions

View File

@ -346,7 +346,7 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
if (iRegReader is PoseidonReader)
{
PoseidonReader poseidonReader = (iRegReader as PoseidonReader);
if(poseidonReader != null)
if(poseidonReader == null)
continue;
if (!(poseidonReader.CurrentOp == PoseidonReader.CurrentPoseidonOp.ReadDatastream_Done
|| poseidonReader.CurrentOp == PoseidonReader.CurrentPoseidonOp.ReadDatastream_Running))

View File

@ -2,14 +2,19 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using log4net;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using SharedDatabase;
namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
{
public class CliRunner
{
static readonly ILog log = LogManager.GetLogger(typeof(CliRunner));
private List<Task> taskPool = new List<Task>();
private long startTime;
@ -96,13 +101,13 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
return allOutput;
}
public void AddRunAndCaptureJsonAsync<T>(SerialPortData data, SerialPortData.EMeterArg eMeterArg)
public void AddRunAndCaptureJsonAsync<T>(SerialPortData data, SerialPortData.EMeterArg eMeterArg) where T : new()
{
var task = RunAndCaptureJsonAsync<T>(data.SerialPortCmdClientPath, data.DefaultArgSettings(eMeterArg));
taskPool.Add(task);
}
public async Task<T> RunAndCaptureJsonAsync<T>(string fileName, string args)
public async Task<T> RunAndCaptureJsonAsync<T>(string fileName, string args) where T : new()
{
var psi = new ProcessStartInfo
{
@ -136,12 +141,58 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
if (json != null)
{
return JsonConvert.DeserializeObject<T>(json);
try
{
return JsonConvert.DeserializeObject<T>(json);
}
catch (Exception ex)
{
log.Debug(ex.Message);
return TryConvert<T>(json);
}
}
return default;
}
private static T TryConvert<T>(string json) where T : new()
{
T obj = new T();
try
{
JObject jObject = JObject.Parse(json);
foreach (PropertyInfo prop in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
if (!prop.CanWrite) continue;
JToken token;
if (jObject.TryGetValue(prop.Name, StringComparison.OrdinalIgnoreCase, out token))
{
try
{
object value = token.ToObject(prop.PropertyType);
prop.SetValue(obj, value);
}
catch
{
// leave default if conversion fails
}
}
// else → keep default value
}
}
catch (Exception ex)
{
Console.WriteLine($"TryConvert failed: {ex.Message}");
}
return obj;
}
private string ExtractJson(string text)
{
int start = text.IndexOf('{');

View File

@ -31,7 +31,15 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
private bool activeHandlerSessioEnabled = false;
private CliRunner _cliRunner;
private CliRunner CliRunner
{
get
{
return (_cliRunner != null ? _cliRunner : (_cliRunner = new CliRunner()));
}
}
public enum CurrentPoseidonOp
{
None,
@ -300,23 +308,23 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
/// <summary>Start this operation</summary>
public void Start()
{
//TODO BUMI start CLI serial port
_cliRunner = new CliRunner();
}
private static long SafetyTimeOut = 30 * 1000; /// 30 seconds
/// <summary>Run this operation</summary>
/// <returns>eventDone</returns>
public Event Run()
{
if (_currentOp == CurrentPoseidonOp.SendStartDataStream)
{
_cliRunner.AddSendAsync(serialPort, SerialPortData.EMeterArg.AllParams);
CliRunner.AddSendAsync(serialPort, SerialPortData.EMeterArg.AllParams);
return Event.Busy;
}
else if (_currentOp == CurrentPoseidonOp.SendStartDataStream_Runing)
{
if (_cliRunner.AreTasksDone()
|| _cliRunner.TimeOutReceived(5000))
if (CliRunner.AreTasksDone()
|| CliRunner.TimeOutReceived(SafetyTimeOut))
{
_currentOp = CurrentPoseidonOp.SendStartDataStream_Done;
}
@ -331,13 +339,13 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|| _currentOp == CurrentPoseidonOp.ReadDataStream_End)
{
_isReadingStart = (_currentOp == CurrentPoseidonOp.ReadDataStream_Start);
_cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort, SerialPortData.EMeterArg.AllParams);
CliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort, SerialPortData.EMeterArg.AllParams);
_currentOp = CurrentPoseidonOp.ReadDatastream_Running;
return Event.Busy;
}else if (_currentOp == CurrentPoseidonOp.ReadDatastream_Running)
{
if (_cliRunner.AreTasksDone()
|| _cliRunner.TimeOutReceived(5000))
if (CliRunner.AreTasksDone()
|| CliRunner.TimeOutReceived(SafetyTimeOut))
{
_currentOp = CurrentPoseidonOp.ReadDatastream_Done;
}
@ -346,7 +354,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
else if (_currentOp == CurrentPoseidonOp.ReadDatastream_Done)
{
JsonDataFromPoseidon data = null;
var first = _cliRunner.TaskPool.FindLast(t => t is Task<JsonDataFromPoseidon>);
var first = CliRunner.TaskPool.FindLast(t => t is Task<JsonDataFromPoseidon>);
if (first != null && first is Task<JsonDataFromPoseidon>)
{
data = (first as Task<JsonDataFromPoseidon>).Result;
@ -438,10 +446,9 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
else
{
//TODO BUMI start session - CMD send data to Poseidon
_cliRunner = new CliRunner();
_cliRunner.AddSendAsync(serialPort, SerialPortData.EMeterArg.DeviceId);
_cliRunner.WaitAll();
foreach (Task task in _cliRunner.TaskPool)
CliRunner.AddSendAsync(serialPort, SerialPortData.EMeterArg.DeviceId);
CliRunner.WaitAll();
foreach (Task task in CliRunner.TaskPool)
{
if (task is Task<string>)
{
@ -453,7 +460,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
}
}
_cliRunner.Clear();
CliRunner.Clear();
}
}
@ -482,7 +489,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
{
if (_cliRunner != null)
{
_cliRunner.Clear();
}
activeHandlerSessioEnabled = false;
}