Auto: s7-d1 — TIA Portal CSV + STEP 7 Classic AWL symbol import
Closes #299
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
(* Sample STEP 7 Classic AWL file — PR-S7-D1 / #299 fixture.
|
||||
Carries a VAR_GLOBAL block (M-area sequential offsets) and a
|
||||
DATA_BLOCK (DB1, sequential DBW/DBD offsets). Comments stripped
|
||||
before declaration parsing so this preamble does not affect counts.
|
||||
*)
|
||||
|
||||
VAR_GLOBAL
|
||||
// M-area globals — assigned sequentially: MW0, MW2, MD4
|
||||
Speed : INT; // motor speed setpoint
|
||||
Pressure : INT; // pressure transducer
|
||||
ActualValue : REAL;
|
||||
END_VAR
|
||||
|
||||
DATA_BLOCK DB1
|
||||
TITLE = 'Sample DB'
|
||||
VERSION : 0.1
|
||||
STRUCT
|
||||
CycleCount : INT; (* runtime cycle counter *)
|
||||
Setpoint : REAL := 50.0; (* setpoint with init *)
|
||||
ActualValue : REAL;
|
||||
RunFlag : BOOL;
|
||||
Recipe : STRING[20];
|
||||
END_STRUCT;
|
||||
BEGIN
|
||||
END_DATA_BLOCK
|
||||
@@ -0,0 +1,9 @@
|
||||
Name,Path,Data type,Logical address,Comment,Hmi accessible,Hmi visible,Hmi writeable,Length
|
||||
ProbeWord,Default tag table,UInt,%MW0,Probe word for liveness,True,True,True,
|
||||
SmokeI16,Default tag table,Int,%DB1.DBW10,Signed 16-bit smoke tag,True,True,True,
|
||||
SmokeI32,Default tag table,DInt,%DB1.DBD20,Signed 32-bit smoke tag,True,True,True,
|
||||
SmokeF32,Default tag table,Real,%DB1.DBD30,32-bit float smoke tag,True,True,True,
|
||||
SmokeBool,Default tag table,Bool,%DB1.DBX50.3,Boolean smoke tag,True,True,True,
|
||||
RecipeName,Default tag table,String,%DB2.DBB0,Recipe name string,True,True,True,32
|
||||
CookerCfg,Default tag table,"CookerSettings",%DB10.DBB0,UDT placeholder — wait for D2,True,True,True,
|
||||
HiddenInternal,Default tag table,Int,%MW100,Internal symbol — should be filtered,False,False,False,
|
||||
|
@@ -0,0 +1,6 @@
|
||||
Name;Path;Data type;Logical address;Comment;Hmi accessible;Hmi visible;Hmi writeable;Length
|
||||
ProbeWort;Standard-Variablentabelle;UInt;%MW0;Probe-Wort für Liveness;WAHR;WAHR;WAHR;
|
||||
SmokeI16;Standard-Variablentabelle;Int;%DB1.DBW10;Vorzeichenbehaftete 16-bit;WAHR;WAHR;WAHR;
|
||||
SmokeBool;Standard-Variablentabelle;Bool;%DB1.DBX50,3;Boolescher Smoke-Tag;WAHR;WAHR;WAHR;
|
||||
SmokeReal;Standard-Variablentabelle;Real;%DB1.DBD30;32-bit float;WAHR;WAHR;WAHR;
|
||||
VerstecktInternal;Standard-Variablentabelle;Int;%MW100;Internes Symbol — herausgefiltert;FALSCH;FALSCH;FALSCH;
|
||||
|
@@ -0,0 +1,83 @@
|
||||
using System.IO;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
||||
using ZB.MOM.WW.OtOpcUa.Driver.S7.IntegrationTests.S7_1500;
|
||||
using ZB.MOM.WW.OtOpcUa.Driver.S7.SymbolImport;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.Driver.S7.IntegrationTests.SymbolImport;
|
||||
|
||||
/// <summary>
|
||||
/// PR-S7-D1 / #299 — golden-fixture integration test. Loads the canonical TIA Portal
|
||||
/// CSV export shipped under <c>Fixtures/sample_tia_export.csv</c>, materialises a
|
||||
/// driver-options object via <c>AddTiaCsvImport</c>, then exercises the runtime read
|
||||
/// path against the python-snap7 simulator.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The fixture's address layout (<c>%MW0</c>, <c>%DB1.DBW10</c>, <c>%DB1.DBD20</c>,
|
||||
/// <c>%DB1.DBD30</c>, <c>%DB1.DBX50.3</c>) is deliberately aligned with the seed
|
||||
/// offsets baked into the snap7 S7-1500 profile (<see cref="S7_1500Profile"/>) so
|
||||
/// a successful round-trip proves the importer's address normalisation lands at
|
||||
/// exactly the offsets the simulator seeds — a regression in <c>%</c>-stripping or
|
||||
/// decimal-comma rewriting surfaces here as a read-mismatch, not a flaky timeout.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The test is build-only by default (the assertions run only when the simulator
|
||||
/// fixture reports <c>SkipReason is null</c>) — local dev invokes it with snap7
|
||||
/// running; CI relies on the fixture's auto-skip when no simulator is reachable.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[Collection(Snap7ServerCollection.Name)]
|
||||
[Trait("Category", "Integration")]
|
||||
[Trait("Device", "S7_1500")]
|
||||
public sealed class TiaCsvImportIntegrationTests(Snap7ServerFixture sim)
|
||||
{
|
||||
private static string FixturePath(string name) =>
|
||||
Path.Combine(AppContext.BaseDirectory, "Fixtures", name);
|
||||
|
||||
[Fact]
|
||||
public async Task Driver_imports_csv_then_reads_seeded_tags()
|
||||
{
|
||||
if (sim.SkipReason is not null) Assert.Skip(sim.SkipReason);
|
||||
|
||||
// Start with an empty options object pinned at the simulator's endpoint, then
|
||||
// layer the fixture CSV's tags on top via AddTiaCsvImport. The merge keeps the
|
||||
// endpoint config (Host, Port, CpuType) untouched and adds the imported tags.
|
||||
var baseOptions = new S7DriverOptions
|
||||
{
|
||||
Host = sim.Host,
|
||||
Port = sim.Port,
|
||||
CpuType = global::S7.Net.CpuType.S71500,
|
||||
Timeout = TimeSpan.FromSeconds(5),
|
||||
Probe = new S7ProbeOptions { Enabled = false },
|
||||
Tags = [],
|
||||
};
|
||||
|
||||
var options = baseOptions.AddTiaCsvImport(FixturePath("sample_tia_export.csv"), out var importResult);
|
||||
|
||||
// Fixture has 8 rows: 6 importable + 1 UDT placeholder + 1 HMI-hidden (skipped).
|
||||
importResult.ParsedCount.ShouldBe(7);
|
||||
importResult.SkippedCount.ShouldBe(1);
|
||||
importResult.UdtPlaceholderCount.ShouldBe(1);
|
||||
options.Tags.Count.ShouldBe(7);
|
||||
|
||||
await using var drv = new S7Driver(options, driverInstanceId: "s7-tia-import");
|
||||
await drv.InitializeAsync("{}", TestContext.Current.CancellationToken);
|
||||
|
||||
// Read the seed-aligned tags by their browse-name references. ProbeWord at MW0
|
||||
// doesn't have a snap7 seed (the simulator profile seeds DB1.DBW0 instead), so
|
||||
// we focus on the DB-anchored tags whose offsets match the S7_1500Profile seeds.
|
||||
var snapshots = await drv.ReadAsync(
|
||||
["SmokeI16", "SmokeI32", "SmokeF32", "SmokeBool"],
|
||||
TestContext.Current.CancellationToken);
|
||||
|
||||
snapshots.Count.ShouldBe(4);
|
||||
foreach (var s in snapshots) s.StatusCode.ShouldBe(0u, "imported-then-read must succeed end-to-end");
|
||||
|
||||
Convert.ToInt32(snapshots[0].Value).ShouldBe((int)S7_1500Profile.SmokeI16SeedValue);
|
||||
Convert.ToInt32(snapshots[1].Value).ShouldBe(S7_1500Profile.SmokeI32SeedValue);
|
||||
Convert.ToSingle(snapshots[2].Value).ShouldBe(S7_1500Profile.SmokeF32SeedValue, tolerance: 0.0001f);
|
||||
Convert.ToBoolean(snapshots[3].Value).ShouldBeTrue();
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,11 @@
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Docker\**\*" CopyToOutputDirectory="PreserveNewest"/>
|
||||
<!-- PR-S7-D1 / #299 — TIA Portal CSV + STEP 7 Classic AWL fixtures used by the
|
||||
symbol-import integration test. -->
|
||||
<None Update="Fixtures\sample_tia_export.csv" CopyToOutputDirectory="PreserveNewest"/>
|
||||
<None Update="Fixtures\sample_tia_export_de_locale.csv" CopyToOutputDirectory="PreserveNewest"/>
|
||||
<None Update="Fixtures\sample_step7_classic.awl" CopyToOutputDirectory="PreserveNewest"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user