Auto: focas-f1e — operator messages + block text

Closes #261
This commit is contained in:
Joseph Doherty
2026-04-25 14:49:11 -04:00
parent 84913638b1
commit cc757855e6
5 changed files with 507 additions and 0 deletions

View File

@@ -287,6 +287,52 @@ internal sealed class FwlibFocasClient : IFocasClient
return Task.FromResult<FocasWorkOffsetsInfo?>(new FocasWorkOffsetsInfo(slots));
}
public Task<FocasOperatorMessagesInfo?> GetOperatorMessagesAsync(CancellationToken cancellationToken)
{
if (!_connected) return Task.FromResult<FocasOperatorMessagesInfo?>(null);
// type 0..3 = OPMSG / MACRO / EXTERN / REJ-EXT (issue #261). Single-slot read
// (length 4 + 256 = 260) returns the most-recent message in each class — best-
// effort: a single-class failure leaves that class out of the snapshot rather
// than failing the whole call, mirroring GetProductionAsync's policy.
var list = new List<FocasOperatorMessage>(4);
string[] classNames = ["OPMSG", "MACRO", "EXTERN", "REJ-EXT"];
for (short t = 0; t < 4; t++)
{
var buf = new FwlibNative.OPMSG3 { Data = new byte[256] };
var ret = FwlibNative.RdOpMsg3(_handle, t, length: 4 + 256, ref buf);
if (ret != 0) continue;
var text = TrimAnsiPadding(buf.Data);
if (string.IsNullOrEmpty(text)) continue;
list.Add(new FocasOperatorMessage(buf.Datano, classNames[t], text));
}
return Task.FromResult<FocasOperatorMessagesInfo?>(new FocasOperatorMessagesInfo(list));
}
public Task<FocasCurrentBlockInfo?> GetCurrentBlockAsync(CancellationToken cancellationToken)
{
if (!_connected) return Task.FromResult<FocasCurrentBlockInfo?>(null);
var buf = new FwlibNative.ODBACTPT { Data = new byte[256] };
var ret = FwlibNative.RdActPt(_handle, ref buf);
if (ret != 0) return Task.FromResult<FocasCurrentBlockInfo?>(null);
return Task.FromResult<FocasCurrentBlockInfo?>(
new FocasCurrentBlockInfo(TrimAnsiPadding(buf.Data)));
}
/// <summary>
/// Decode + trim a Fanuc ANSI byte buffer. The CNC right-pads block text + opmsg
/// bodies with nulls or spaces; trim them so the round-trip through the OPC UA
/// address space stays stable (issue #261). Stops at the first NUL so any wire
/// buffer that gets reused doesn't leak old bytes.
/// </summary>
internal static string TrimAnsiPadding(byte[] data)
{
if (data is null) return string.Empty;
var len = 0;
for (; len < data.Length; len++)
if (data[len] == 0) break;
return System.Text.Encoding.ASCII.GetString(data, 0, len).TrimEnd(' ', '\0');
}
/// <summary>
/// Decode one OFSB axis block from a <c>cnc_rdzofs</c> data buffer. Each axis
/// occupies 10 bytes per <c>fwlib32.h</c>: <c>int data</c> + <c>short dec</c> +