Files
Joseph Doherty 9dccf8e72f deprecate(lmxproxy): move all LmxProxy code, tests, and docs to deprecated/
LmxProxy is no longer needed. Moved the entire lmxproxy/ workspace, DCL
adapter files, and related docs to deprecated/. Removed LmxProxy registration
from DataConnectionFactory, project reference from DCL, protocol option from
UI, and cleaned up all requirement docs.
2026-04-08 15:56:23 -04:00

167 lines
6.9 KiB
C#

using System;
using ArchestrA.MxAccess;
using ZB.MOM.WW.LmxProxy.Host.Domain;
namespace ZB.MOM.WW.LmxProxy.Host.Implementation
{
/// <summary>
/// Event handlers for MxAccessClient to process data changes, write completions, and operation completions.
/// </summary>
public sealed partial class MxAccessClient
{
/// <summary>
/// Handles data change events from the MxAccess server.
/// </summary>
/// <param name="hLMXServerHandle">Server handle.</param>
/// <param name="phItemHandle">Item handle.</param>
/// <param name="pvItemValue">Item value.</param>
/// <param name="pwItemQuality">Item quality code.</param>
/// <param name="pftItemTimeStamp">Item timestamp.</param>
/// <param name="ItemStatus">Status array.</param>
private void OnDataChange(int hLMXServerHandle, int phItemHandle, object pvItemValue,
int pwItemQuality, object pftItemTimeStamp, ref MXSTATUS_PROXY[] ItemStatus)
{
try
{
if (!_subscriptionsByHandle.TryGetValue(phItemHandle, out SubscriptionInfo? subscription))
{
return;
}
// Convert quality from integer
Quality quality = ConvertQuality(pwItemQuality);
DateTime timestamp = ConvertTimestamp(pftItemTimeStamp);
var vtq = new Vtq(pvItemValue, timestamp, quality);
// Invoke callback
subscription.Callback?.Invoke(subscription.Address, vtq);
}
catch (Exception ex)
{
Logger.Error(ex, "Error processing data change for handle {Handle}", phItemHandle);
}
}
/// <summary>
/// Handles write completion events from the MxAccess server.
/// </summary>
/// <param name="hLMXServerHandle">Server handle.</param>
/// <param name="phItemHandle">Item handle.</param>
/// <param name="ItemStatus">Status array.</param>
private void OnWriteComplete(int hLMXServerHandle, int phItemHandle, ref MXSTATUS_PROXY[] ItemStatus)
{
try
{
WriteOperation? writeOp;
lock (_lock)
{
if (_pendingWrites.TryGetValue(phItemHandle, out writeOp))
{
_pendingWrites.Remove(phItemHandle);
}
}
if (writeOp != null)
{
try
{
if (ItemStatus is { Length: > 0 })
{
var status = ItemStatus[0];
if (status.success == 0)
{
string errorMsg = GetWriteErrorMessage(status.detail);
Logger.Warning(
"Write failed for {Address} (handle {Handle}): {Error} (Category={Category}, Detail={Detail})",
writeOp.Address, phItemHandle, errorMsg, status.category, status.detail);
writeOp.CompletionSource.TrySetException(new InvalidOperationException(
$"Write failed: {errorMsg}"));
}
else
{
Logger.Debug("Write completed successfully for {Address} (handle {Handle})",
writeOp.Address, phItemHandle);
writeOp.CompletionSource.TrySetResult(true);
}
}
else
{
Logger.Debug("Write completed for {Address} (handle {Handle}) with no status",
writeOp.Address, phItemHandle);
writeOp.CompletionSource.TrySetResult(true);
}
}
finally
{
// Clean up the item after write completes
lock (_lock)
{
if (_lmxProxy != null)
{
try
{
_lmxProxy.UnAdvise(_connectionHandle, phItemHandle);
_lmxProxy.RemoveItem(_connectionHandle, phItemHandle);
}
catch (Exception ex)
{
Logger.Debug(ex, "Error cleaning up after write for handle {Handle}", phItemHandle);
}
}
}
}
}
else if (ItemStatus is { Length: > 0 })
{
var status = ItemStatus[0];
if (status.success == 0)
{
Logger.Warning("Write failed for unknown handle {Handle}: Category={Category}, Detail={Detail}",
phItemHandle, status.category, status.detail);
}
}
}
catch (Exception ex)
{
Logger.Error(ex, "Error processing write complete for handle {Handle}", phItemHandle);
}
}
/// <summary>
/// Handles operation completion events from the MxAccess server.
/// </summary>
/// <param name="hLMXServerHandle">Server handle.</param>
/// <param name="phItemHandle">Item handle.</param>
/// <param name="ItemStatus">Status array.</param>
private void OnOperationComplete(int hLMXServerHandle, int phItemHandle, ref MXSTATUS_PROXY[] ItemStatus)
{
// Log operation completion
Logger.Debug("Operation complete for handle {Handle}", phItemHandle);
}
/// <summary>
/// Converts an integer MxAccess quality code to <see cref="Quality" />.
/// </summary>
/// <param name="mxQuality">The MxAccess quality code.</param>
/// <returns>The corresponding <see cref="Quality" /> value.</returns>
private Quality ConvertQuality(int mxQuality) => (Quality)mxQuality;
/// <summary>
/// Converts a timestamp object to <see cref="DateTime" /> in UTC.
/// </summary>
/// <param name="timestamp">The timestamp object.</param>
/// <returns>The UTC <see cref="DateTime" /> value.</returns>
private DateTime ConvertTimestamp(object timestamp)
{
if (timestamp is DateTime dt)
{
return dt.Kind == DateTimeKind.Utc ? dt : dt.ToUniversalTime();
}
return DateTime.UtcNow;
}
}
}