Wire ApplyScaling, StorageRate; close out write-commands plan
ApplyScaling (HistorianTagDefinition.ApplyScaling): The EnsT2 trailer's second byte controls server-side scaling — `FE 00` mirrors MinRaw to MinEU and sets AnalogTag.Scaling=0; `FE 01` persists distinct MinRaw/MaxRaw and sets Scaling=1. Decoded by toggling set_ApplyScaling on the native harness and capturing the wire bytes for both values with identical inputs. The earlier docs claimed EnsureTagAsync needed a follow-up "UpdateTags" call; the WCF surface has no such operation — toggling that one byte is the whole fix. StorageRate (HistorianTagDefinition.StorageRateMs): Serializer accepts a non-default rate, validated empirically against the live server which only accepts quantized values (1000/5000/10000/60000/300000 ms). EnsureTagAsync upsert semantics: Second call on the same tag name with different fields succeeds and updates Description, MinEU, MaxEU, MinRaw, MaxRaw, Scaling in place (verified by direct SQL inspection in a live test). Plan + doc closeout: write-commands-reverse-engineering.md rewritten as a current-state plan with three workstreams (A doc closeout / B idempotency / C1 StorageRate) and a parallelism table; prior phase notes preserved as appendix. handoff.md, implementation-status.md, wcf-contract-evidence.md, README.md updated to remove "writes are out of scope" / non-existent UpdateTags references and document the actual EnsT2 wire format including the `FE xx` trailer. Reverse-engineering harness gains --write-apply-scaling and a SQL post-check that prints the persisted AnalogTag bounds so future RE sessions can verify wire→DB causality without leaving the harness. 169/169 tests pass (was 165; +4 new tests covering ApplyScaling, StorageRate golden bytes, StorageRate live persistence, and EnsureTagAsync upsert semantics). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -237,6 +237,7 @@ internal static class Program
|
||||
// server-cache refresh after a fresh AddTag requires a NEW process / connection.
|
||||
bool skipAddTag = HasFlag(args, "--write-skip-add-tag");
|
||||
bool skipAddValue = HasFlag(args, "--write-skip-add-value");
|
||||
bool writeApplyScaling = HasFlag(args, "--write-apply-scaling");
|
||||
|
||||
// Decoded via dnlib — actual enum field types on HistorianTag:
|
||||
// set_TagDataType stfld ArchestrA.HistorianDataType HistorianTag::dataType
|
||||
@@ -260,7 +261,7 @@ internal static class Program
|
||||
SetProperty(tag, "MinRaw", writeMinRaw);
|
||||
SetProperty(tag, "MaxRaw", writeMaxRaw);
|
||||
SetProperty(tag, "StorageRate", 1000u);
|
||||
SetProperty(tag, "ApplyScaling", false);
|
||||
SetProperty(tag, "ApplyScaling", writeApplyScaling);
|
||||
|
||||
uint tagKey = 0;
|
||||
if (!skipAddTag)
|
||||
@@ -305,6 +306,25 @@ internal static class Program
|
||||
tagKey = realKey;
|
||||
}
|
||||
}
|
||||
|
||||
using System.Data.SqlClient.SqlCommand analogCmd = sql.CreateCommand();
|
||||
analogCmd.CommandText = "SELECT MinEU, MaxEU, MinRaw, MaxRaw, Scaling FROM AnalogTag WHERE TagName = @t";
|
||||
analogCmd.Parameters.AddWithValue("@t", sandboxTag);
|
||||
using System.Data.SqlClient.SqlDataReader analogReader = analogCmd.ExecuteReader();
|
||||
if (analogReader.Read())
|
||||
{
|
||||
rows.Add(new
|
||||
{
|
||||
Kind = "AnalogTagPersisted",
|
||||
TagName = sandboxTag,
|
||||
MinEU = analogReader.IsDBNull(0) ? (object)"<null>" : analogReader.GetDouble(0),
|
||||
MaxEU = analogReader.IsDBNull(1) ? (object)"<null>" : analogReader.GetDouble(1),
|
||||
MinRaw = analogReader.IsDBNull(2) ? (object)"<null>" : analogReader.GetDouble(2),
|
||||
MaxRaw = analogReader.IsDBNull(3) ? (object)"<null>" : analogReader.GetDouble(3),
|
||||
Scaling = analogReader.IsDBNull(4) ? (object)"<null>" : analogReader.GetValue(4),
|
||||
InputApplyScaling = writeApplyScaling,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Server cache may not pick up new tags immediately. Allow a wait between AddTag
|
||||
|
||||
Reference in New Issue
Block a user