fix(historian): #681 re-review — OpcQuality low-byte comparison, no-data boundary quality is 1
This commit is contained in:
+1
-1
@@ -787,7 +787,7 @@ and evicts its shared historian session (see the HistorianGateway issue text in
|
|||||||
(histsdk evidence: `Quality = 133`, `OpcQuality = 192`) — the value in effect there, not a stored sample. Starting 1 ms early puts
|
(histsdk evidence: `Quality = 133`, `OpcQuality = 192`) — the value in effect there, not a stored sample. Starting 1 ms early puts
|
||||||
that row outside every bucket. A pre-window row only proves "the tag has earlier data" (start-of-data Partial, Count's in-range
|
that row outside every bucket. A pre-window row only proves "the tag has earlier data" (start-of-data Partial, Count's in-range
|
||||||
zero), and only when its **OPC quality is not Bad** — a "no earlier data" NULL row still carries a value on the wire (histsdk sets
|
zero), and only when its **OPC quality is not Bad** — a "no earlier data" NULL row still carries a value on the wire (histsdk sets
|
||||||
`NumericValue = 0` on every numeric row and `StringValue = ""` on a string one) but with OPC quality 0.
|
`NumericValue = 0` on every numeric row and `StringValue = ""` on a string one) but with a Bad OPC quality (captured as 1, no-data; histsdk string-read-layout.md).
|
||||||
- **Earlier-data probe.** When the data range matters (every per-sample aggregate but `Average`) and no non-Bad pre-window row
|
- **Earlier-data probe.** When the data range matters (every per-sample aggregate but `Average`) and no non-Bad pre-window row
|
||||||
arrived, a 2-row read `[1970-01-01, start)` asks whether the tag has data before the window. Normally this fires only for a tag
|
arrived, a 2-row read `[1970-01-01, start)` asks whether the tag has data before the window. Normally this fires only for a tag
|
||||||
whose history really begins inside the window.
|
whose history really begins inside the window.
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway;
|
|||||||
/// (1 ms) BEFORE the window, so that row lands outside every bucket and can never be counted as a sample. A row
|
/// (1 ms) BEFORE the window, so that row lands outside every bucket and can never be counted as a sample. A row
|
||||||
/// before the window counts only as evidence that the tag has earlier data, and only when its OPC quality is not
|
/// before the window counts only as evidence that the tag has earlier data, and only when its OPC quality is not
|
||||||
/// Bad — a "no earlier data" NULL row still arrives WITH a value (histsdk sets <c>NumericValue = 0</c> on every
|
/// Bad — a "no earlier data" NULL row still arrives WITH a value (histsdk sets <c>NumericValue = 0</c> on every
|
||||||
/// numeric row, <c>StringValue = ""</c> on a string one) but with OPC quality 0.
|
/// numeric row, <c>StringValue = ""</c> on a string one) but with a Bad OPC quality (captured: 1, no-data).
|
||||||
/// </para>
|
/// </para>
|
||||||
/// <para>
|
/// <para>
|
||||||
/// <b>The data range.</b> The start/end-of-data Partial rules and Count's in-range empty interval need the tag's
|
/// <b>The data range.</b> The start/end-of-data Partial rules and Count's in-range empty interval need the tag's
|
||||||
@@ -142,7 +142,7 @@ internal static class RawAggregateReader
|
|||||||
// latest at or after its earlier edge. A row before the window (the AVEVA boundary row, or a stored sample in
|
// latest at or after its earlier edge. A row before the window (the AVEVA boundary row, or a stored sample in
|
||||||
// the margin) proves earlier data only when its OPC quality is not Bad: AVEVA's boundary row for a tag with no
|
// the margin) proves earlier data only when its OPC quality is not Bad: AVEVA's boundary row for a tag with no
|
||||||
// earlier data is a NULL row, which arrives WITH a value (histsdk sets NumericValue = 0 / StringValue "") and
|
// earlier data is a NULL row, which arrives WITH a value (histsdk sets NumericValue = 0 / StringValue "") and
|
||||||
// OPC quality 0.
|
// a Bad OPC quality (captured: 1, no-data).
|
||||||
if (t >= plan.StartUtc || IsNotBadOnTheWire(raw))
|
if (t >= plan.StartUtc || IsNotBadOnTheWire(raw))
|
||||||
{
|
{
|
||||||
if (t <= plan.EndUtc && (earliest is null || t < earliest)) earliest = t;
|
if (t <= plan.EndUtc && (earliest is null || t < earliest)) earliest = t;
|
||||||
@@ -199,7 +199,7 @@ internal static class RawAggregateReader
|
|||||||
/// <see cref="SampleMapper.ToStatus"/>'s fallback to the AVEVA <c>quality</c> field when <c>opc_quality</c> is 0, which
|
/// <see cref="SampleMapper.ToStatus"/>'s fallback to the AVEVA <c>quality</c> field when <c>opc_quality</c> is 0, which
|
||||||
/// is also the OPC DA Bad value a NULL row carries.
|
/// is also the OPC DA Bad value a NULL row carries.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static bool IsNotBadOnTheWire(HistorianSample raw) => raw.OpcQuality >= 64;
|
private static bool IsNotBadOnTheWire(HistorianSample raw) => (byte)raw.OpcQuality >= 64; // low byte, as SampleMapper.ToStatus reads it
|
||||||
|
|
||||||
private static HistoryReadLimitExceededException LimitExceeded(string tag, int maxWindowRows) =>
|
private static HistoryReadLimitExceededException LimitExceeded(string tag, int maxWindowRows) =>
|
||||||
new(maxWindowRows,
|
new(maxWindowRows,
|
||||||
|
|||||||
Reference in New Issue
Block a user