diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..e777862 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,235 @@ +# GitHub Copilot Instructions — OpenProtocolInterpreter + +## Project Overview + +**OpenProtocolInterpreter** is a zero-dependency .NET library that bidirectionally serializes/deserializes Atlas Copco Open Protocol MID messages (fixed-width ASCII) to typed C# objects and back. +NuGet package: `OpenProtocolInterpreter` · Version: `6.1.1` +Multi-targeted: `netstandard2.0; net6.0; net8.0; net10.0` + +--- + +## Repository Layout + +``` +src/ + OpenProtocolInterpreter/ ← main library + _internals/ ← infrastructure (MessagesTemplate, MidCompiledInstance) + Enums/ ← all shared enums (~50 files) + {Category}/ ← one folder per MID domain (Alarm, Tightening, Job, …) + I{Category}.cs ← empty marker interface + {Category}Messages.cs ← internal MID registry for the category + Mid{NNNN}.cs ← one file per MID number + MID.cs ← abstract base class + Header.cs ← 20-char header model + DataField.cs ← single field descriptor + OpenProtocolConvert.cs ← all type-conversion utilities + MidInterpreter.cs ← public entry point + MidInterpreterMessagesExtensions.cs ← fluent registration API + MIDTesters.Core/ ← MSTest test project (net10.0) +sample/ ← WinForms sample driver (not part of the library) +docs/ ← vendor protocol specs (Atlas Copco, Desoutter) +``` + +--- + +## Core Abstractions + +### Header (20 chars, always present) +| Position | Field | Width | +|---|---|---| +| 0–3 | Length | 4 | +| 4–7 | Mid | 4 | +| 8–10 | Revision | 3 | +| 11 | NoAckFlag | 1 | +| 12–13 | StationId | 2 | +| 14–15 | SpindleId | 2 | +| 16–17 | SequenceNumber | 2 | +| 18 | NumberOfMessages | 1 | +| 19 | MessageNumber | 1 | + +### DataField +Describes one field within a MID. Key members: `Field` (enum hash), `Index` (absolute offset from byte 0), `Size`, `HasPrefix`, `Value`. +Use factory statics — **never call the constructor directly**: +- `DataField.String(field, index, size)` — space-padded +- `DataField.Number(field, index, size)` — zero-padded +- `DataField.Boolean(field, index)` — size 1 +- `DataField.Timestamp(field, index)` — size 19, format `yyyy-MM-dd:HH:mm:ss` +- `DataField.Volatile(field, index)` — variable-length + +### OpenProtocolConvert +The **only** permitted conversion utility. Never use `int.Parse`, `DateTime.Parse`, etc. in MID code. +Key pairs: `ToBoolean`/`ToString(bool)`, `ToDateTime`/`ToString(DateTime)`, `ToDecimal`/`ToString(decimal)`, `ToInt32`, `ToInt64`, `TruncatedDecimalToString`/`ToTruncatedDecimal`, `TruncatePadded`, `GetBit`/`ToByte`. + +--- + +## MID Class Conventions (mandatory) + +Every concrete MID **must** follow this exact pattern: + +```csharp +// Namespace: OpenProtocolInterpreter.{Category} +public class Mid0071 : Mid, IAlarm, IController, IAcknowledgeable +{ + public const int MID = 71; // always present + + // --- Properties --- + // Simple string / bool + public string ErrorCode + { + get => GetField(1, DataFields.ErrorCode).Value; + set => GetField(1, DataFields.ErrorCode).SetValue(value); + } + // Typed (non-string) — use OpenProtocolConvert + public bool ControllerReadyStatus + { + get => GetField(1, DataFields.ControllerReadyStatus).GetValue(OpenProtocolConvert.ToBoolean); + set => GetField(1, DataFields.ControllerReadyStatus).SetValue(OpenProtocolConvert.ToString, value); + } + + // --- Constructors (all three required, enforced by tests) --- + public Mid0071() : this(DEFAULT_REVISION) { } + public Mid0071(Header header) : base(header) { HandleRevision(); } + public Mid0071(int revision) : this(new Header() { Revision = revision, Mid = MID }) { } + + // --- Parse override (only when HandleRevision must run before ProcessDataFields) --- + public override Mid Parse(string package) + { + Header = ProcessHeader(package); + HandleRevision(); + ProcessDataFields(package); + return this; + } + + // --- Field declarations per revision --- + protected override Dictionary> RegisterDatafields() + { + return new Dictionary>() + { + { + 1, new List() + { + DataField.String(DataFields.ErrorCode, 20, 4, PaddingOrientation.LeftPadded), + DataField.Boolean(DataFields.ControllerReadyStatus, 26), + DataField.Boolean(DataFields.ToolReadyStatus, 29), + DataField.Timestamp(DataFields.Time, 32) + } + }, + { + 2, new List() { DataField.String(DataFields.AlarmText, 54, 50) } + } + }; + } + + // --- Field identity enum (private or protected, nested inside the class) --- + protected enum DataFields { ErrorCode, ControllerReadyStatus, ToolReadyStatus, Time, AlarmText } +} +``` + +**Rules:** +1. Class name: `Mid{NNNN}` with 4-digit zero-padded number. +2. Three required constructors (parameterless, `(Header)`, `(int revision)`) — validated by `DefaultMidTests`. +3. `const int MID = N` must be present. +4. `DataFields` enum is **nested and private/protected** — never a public top-level enum. +5. `RegisterDatafields()` keys are **1-based revision numbers**. +6. Index values in `RegisterDatafields()` are **absolute offsets** from position 0 of the full raw string (header occupies 0–19). +7. Use `DataField` factory methods, not constructors. +8. Property getters/setters delegate to `GetField` / `GetValue` / `SetValue` — no local parsing. +9. Apply the correct **category marker interface** (`IAlarm`, `ITightening`, etc.) and **role interface** (`IController` or `IIntegrator`). +10. Apply **behavior interfaces** as per the spec: `IAcknowledgeable`, `IAnswerableBy`, `IAcceptableCommand`, `IDeclinableCommand`, `ISubscription`, `IUnsubscription`. + +--- + +## Adding a New Category + +1. Create folder `src/OpenProtocolInterpreter/{Category}/`. +2. Add `I{Category}.cs` — empty marker interface. +3. Add `{Category}Messages.cs` — `internal class {Category}Messages : MessagesTemplate` with: + - MID-number dictionary of `MidCompiledInstance` + - `IsAssignableTo(int mid)` range expression + - Three constructors (no-arg, `InterpreterMode`, `IEnumerable`) +4. Add extension method `Use{Category}Messages(...)` to `MidInterpreterMessagesExtensions.cs`. + +--- + +## Registering a New MID in an Existing Category + +In `{Category}Messages.cs`, add to the dictionary: +```csharp +{ Mid{NNNN}.MID, new MidCompiledInstance(typeof(Mid{NNNN})) } +``` +Extend `IsAssignableTo` if the MID number falls outside the current range expression. + +--- + +## MidInterpreter Usage + +```csharp +// Register all categories +var interpreter = new MidInterpreter().UseAllMessages(); + +// Or selectively, with role filtering +var interpreter = new MidInterpreter() + .UseAlarmMessages(InterpreterMode.Controller) + .UseTighteningMessages(InterpreterMode.Integrator); + +// Parse +Mid parsed = interpreter.Parse(rawString); // untyped +Mid0061 typed = interpreter.Parse(rawString); // typed +``` + +--- + +## Test Conventions + +Tests live in `src/MIDTesters.Core/`. Framework: **MSTest** on `net10.0`. + +Hierarchy: +``` +MidTester (base, creates shared MidInterpreter) + └── DefaultMidTests (enforces parameterless + Header constructors) + └── TestMid{NNNN} : DefaultMidTests +``` + +Per-MID test pattern: +```csharp +[TestClass, TestCategory("{Category}")] +public class TestMid0071 : DefaultMidTests +{ + [TestMethod, TestCategory("Revision 1"), TestCategory("ASCII")] + public void Mid0071Revision1() + { + string pack = @"00530071001 01E851021031042017-12-01:20:12:45"; + var mid = _midInterpreter.Parse(pack); + Assert.AreEqual("E851", mid.ErrorCode); + // ... assert every field + AssertEqualPackages(pack, mid); // mandatory round-trip check + } + + [TestMethod, TestCategory("Revision 1"), TestCategory("ByteArray")] + public void Mid0071ByteRevision1() + { + string pack = @"00530071001 01E851021031042017-12-01:20:12:45"; + var mid = _midInterpreter.Parse(_midInterpreter.GetAsciiBytes(pack)); + Assert.AreEqual("E851", mid.ErrorCode); + AssertEqualPackages(pack, mid); + } +} +``` + +**Rules:** +- Each revision gets its own test method. +- Each revision gets both an ASCII and a ByteArray test method. +- Test fixtures must be real wire strings taken from the vendor protocol spec. +- Always call `AssertEqualPackages` to verify round-trip fidelity. +- Add `[TestCategory("{Category}")]` matching the domain folder name. + +--- + +## Hard Constraints + +- **Zero external NuGet dependencies** in `OpenProtocolInterpreter.csproj`. Do not add any. +- **`LangVersion: latest`** — modern C# features are allowed. +- All type conversions in MID code go through `OpenProtocolConvert`. Never call `int.Parse`, `double.Parse`, `DateTime.Parse`, `Convert.ToXxx`, etc. directly. +- Do not use `Reflection` or `dynamic` outside of `_internals/`. +- Do not change `Header` parsing logic — it is shared by all MIDs. +- Field index values are absolute offsets from position 0. The header consumes positions 0–19; the first data field always starts at ≥ 20. diff --git a/HE-TestTodoList.md b/HE-TestTodoList.md new file mode 100644 index 0000000..e0b3a6c --- /dev/null +++ b/HE-TestTodoList.md @@ -0,0 +1,78 @@ +# HE Test Checklist — Rexroth/NEXO MIDs + +Manual testing checklist for all newly implemented vendor-specific MIDs. +Mark each MID as tested against a real Rexroth/NEXO controller. + +## AutomaticManualMode + +| MID | Description | Direction | Tested | Notes | +|-----|-------------|-----------|--------|-------| +| 0404 | Select automatic/manual mode | Int → Ctl | ☐ | | + +## HVO (Hand-guided Visual Output) + +| MID | Description | Direction | Tested | Notes | +|-----|-------------|-----------|--------|-------| +| 0510 | Subscribe HVO signals | Int → Ctl | ☐ | | +| 0512 | Acknowledge HVO upload | Int → Ctl | ☐ | | +| 0513 | Unsubscribe HVO signals | Int → Ctl | ☐ | | +| 0515 | Set HVO signal (Rev1: 4 lamps) | Int → Ctl | ☐ | | +| 0515 | Set HVO signal (Rev2: light#/status) | Int → Ctl | ☐ | | + +## SocketTray + +| MID | Description | Direction | Tested | Notes | +|-----|-------------|-----------|--------|-------| +| 0520 | Subscribe socket tray | Int → Ctl | ☐ | | +| 0522 | Acknowledge socket tray upload | Int → Ctl | ☐ | | +| 0523 | Unsubscribe socket tray | Int → Ctl | ☐ | | +| 0524 | Socket tray status (8 sockets) | Ctl → Int | ☐ | | + +## RexrothJob + +| MID | Description | Direction | Tested | Notes | +|-----|-------------|-----------|--------|-------| +| 0554 | Subscribe job result | Int → Ctl | ☐ | | +| 0555 | Job result upload | Ctl → Int | ☐ | | +| 0556 | Acknowledge job result | Int → Ctl | ☐ | | +| 0557 | Unsubscribe job result | Int → Ctl | ☐ | | +| 0570 | Activate job | Int → Ctl | ☐ | | +| 0571 | Start job | Int → Ctl | ☐ | | +| 0573 | Select job number | Int → Ctl | ☐ | | +| 0574 | Job manipulate | Int → Ctl | ☐ | | + +## Battery + +| MID | Description | Direction | Tested | Notes | +|-----|-------------|-----------|--------|-------| +| 0800 | Request battery status | Int → Ctl | ☐ | | +| 0801 | Battery status reply | Ctl → Int | ☐ | | +| 0802 | Subscribe battery (change level) | Int → Ctl | ☐ | | +| 0803 | Battery status upload | Ctl → Int | ☐ | | +| 0804 | Unsubscribe battery | Int → Ctl | ☐ | | + +## Wifi + +| MID | Description | Direction | Tested | Notes | +|-----|-------------|-----------|--------|-------| +| 0805 | Request WiFi quality | Int → Ctl | ☐ | | +| 0806 | WiFi quality reply | Ctl → Int | ☐ | | +| 0807 | Subscribe WiFi (change level) | Int → Ctl | ☐ | | +| 0808 | WiFi quality upload | Ctl → Int | ☐ | | +| 0809 | Unsubscribe WiFi | Int → Ctl | ☐ | | + +--- + +## Deferred (Not Implemented) + +| MID | Description | Reason | +|-----|-------------|--------| +| 0500–0504 | Rexroth I/O signals | Conflicts with standard Motor Tuning MIDs | +| 0511 | HVO state change upload | No field layout available | + +--- + +**Legend:** +- Int → Ctl = Integrator sends to Controller +- Ctl → Int = Controller sends to Integrator +- ☐ = Not tested | ☑ = Tested OK | ☒ = Test failed diff --git a/HE.changelog.md b/HE.changelog.md new file mode 100644 index 0000000..07164b2 --- /dev/null +++ b/HE.changelog.md @@ -0,0 +1,30 @@ +# HallerErne.OpenProtocolInterpreter Changelog + +All notable changes to the Haller + Erne fork of OpenProtocolInterpreter. + +Forked from [Rickedb/OpenProtocolInterpreter](https://github.com/Rickedb/OpenProtocolInterpreter) v6.1.1. + +--- + +## [6.1.1] — 2026-05-06 + +### Added + +- **AutomaticManualMode**: Mid0404 — Select automatic/manual mode (Integrator → Controller) +- **Hvo** (Hand-guided Visual Output): Mid0510 (subscribe), Mid0512 (acknowledge), Mid0513 (unsubscribe), Mid0515 (set HVO signal, Rev1: 4 lamps, Rev2: light number + status) +- **SocketTray**: Mid0520 (subscribe), Mid0522 (acknowledge), Mid0523 (unsubscribe), Mid0524 (socket tray status, 8 socket fields) +- **RexrothJob**: Mid0554 (subscribe job result), Mid0555 (job result upload), Mid0556 (acknowledge), Mid0557 (unsubscribe), Mid0570 (activate job), Mid0571 (start job), Mid0573 (select job number), Mid0574 (job manipulate) +- **Battery**: Mid0800 (request), Mid0801 (response: capacity + state), Mid0802 (subscribe with change level), Mid0803 (upload), Mid0804 (unsubscribe) +- **Wifi**: Mid0805 (request), Mid0806 (response: reception quality), Mid0807 (subscribe with change level), Mid0808 (upload), Mid0809 (unsubscribe) + +### Changed + +- Package renamed to `HallerErne.OpenProtocolInterpreter` +- Author/Company set to Haller + Erne GmbH +- `MidInterpreterMessagesExtensions`: added `UseBatteryMessages`, `UseHvoMessages`, `UseRexrothJobMessages`, `UseSocketTrayMessages`, `UseWifiMessages` with XML documentation +- `UseAllMessages()` now includes all five new categories + +### Notes + +- MID 500–504 (Rexroth I/O signals) deferred — conflicts with standard Motor Tuning MIDs at those numbers +- Field layouts sourced from Nexo V1400 Open Protocol specification and heOPTester reference implementation diff --git a/docs/OpenProtocol_Specification_R_2.21.1.pdf b/docs/OpenProtocol_Specification_R_2.21.1.pdf new file mode 100644 index 0000000..8a63779 Binary files /dev/null and b/docs/OpenProtocol_Specification_R_2.21.1.pdf differ diff --git a/src/MIDTesters.Core/AutomaticManualMode/TestMid0404.cs b/src/MIDTesters.Core/AutomaticManualMode/TestMid0404.cs new file mode 100644 index 0000000..a7f98b8 --- /dev/null +++ b/src/MIDTesters.Core/AutomaticManualMode/TestMid0404.cs @@ -0,0 +1,44 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenProtocolInterpreter.AutomaticManualMode; + +namespace MIDTesters.AutomaticManualMode +{ + [TestClass] + [TestCategory("AutomaticManualMode")] + public class TestMid0404 : DefaultMidTests + { + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ASCII")] + public void Mid0404Revision1() + { + string package = "00210404 1"; + var mid = _midInterpreter.Parse(package); + + Assert.IsTrue(mid.ManualAutomaticMode); + AssertEqualPackages(package, mid, true); + } + + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ByteArray")] + public void Mid0404ByteRevision1() + { + string package = "00210404 1"; + byte[] bytes = GetAsciiBytes(package); + var mid = _midInterpreter.Parse(bytes); + + Assert.IsTrue(mid.ManualAutomaticMode); + AssertEqualPackages(bytes, mid, true); + } + + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ASCII")] + public void Mid0404Revision1AutomaticMode() + { + string package = "00210404 0"; + var mid = _midInterpreter.Parse(package); + + Assert.IsFalse(mid.ManualAutomaticMode); + AssertEqualPackages(package, mid, true); + } + } +} diff --git a/src/MIDTesters.Core/Battery/TestBatteryMids.cs b/src/MIDTesters.Core/Battery/TestBatteryMids.cs new file mode 100644 index 0000000..f8e2760 --- /dev/null +++ b/src/MIDTesters.Core/Battery/TestBatteryMids.cs @@ -0,0 +1,149 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenProtocolInterpreter.Battery; + +namespace MIDTesters.Battery +{ + [TestClass] + [TestCategory("Battery")] + public class TestMid0800 : DefaultMidTests + { + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ASCII")] + public void Mid0800Revision1() + { + string package = "00200800 "; + var mid = _midInterpreter.Parse(package); + + Assert.AreEqual(typeof(Mid0800), mid.GetType()); + AssertEqualPackages(package, mid, true); + } + + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ByteArray")] + public void Mid0800ByteRevision1() + { + string package = "00200800 "; + byte[] bytes = GetAsciiBytes(package); + var mid = _midInterpreter.Parse(bytes); + + Assert.AreEqual(typeof(Mid0800), mid.GetType()); + AssertEqualPackages(bytes, mid, true); + } + } + + [TestClass] + [TestCategory("Battery")] + public class TestMid0801 : DefaultMidTests + { + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ASCII")] + public void Mid0801Revision1() + { + string package = "00280801 01030023"; + var mid = _midInterpreter.Parse(package); + + Assert.AreEqual(30, mid.Capacity); + Assert.AreEqual(3, mid.State); + AssertEqualPackages(package, mid, true); + } + + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ByteArray")] + public void Mid0801ByteRevision1() + { + string package = "00280801 01030023"; + byte[] bytes = GetAsciiBytes(package); + var mid = _midInterpreter.Parse(bytes); + + Assert.AreEqual(30, mid.Capacity); + Assert.AreEqual(3, mid.State); + AssertEqualPackages(bytes, mid, true); + } + } + + [TestClass] + [TestCategory("Battery")] + public class TestMid0802 : DefaultMidTests + { + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ASCII")] + public void Mid0802Revision1() + { + string package = "00220802 25"; + var mid = _midInterpreter.Parse(package); + + Assert.AreEqual(25, mid.ChangeLevel); + AssertEqualPackages(package, mid, true); + } + + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ByteArray")] + public void Mid0802ByteRevision1() + { + string package = "00220802 25"; + byte[] bytes = GetAsciiBytes(package); + var mid = _midInterpreter.Parse(bytes); + + Assert.AreEqual(25, mid.ChangeLevel); + AssertEqualPackages(bytes, mid, true); + } + } + + [TestClass] + [TestCategory("Battery")] + public class TestMid0803 : DefaultMidTests + { + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ASCII")] + public void Mid0803Revision1() + { + string package = "00280803 01030023"; + var mid = _midInterpreter.Parse(package); + + Assert.AreEqual(30, mid.Capacity); + Assert.AreEqual(3, mid.State); + AssertEqualPackages(package, mid, true); + } + + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ByteArray")] + public void Mid0803ByteRevision1() + { + string package = "00280803 01030023"; + byte[] bytes = GetAsciiBytes(package); + var mid = _midInterpreter.Parse(bytes); + + Assert.AreEqual(30, mid.Capacity); + Assert.AreEqual(3, mid.State); + AssertEqualPackages(bytes, mid, true); + } + } + + [TestClass] + [TestCategory("Battery")] + public class TestMid0804 : DefaultMidTests + { + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ASCII")] + public void Mid0804Revision1() + { + string package = "00200804 "; + var mid = _midInterpreter.Parse(package); + + Assert.AreEqual(typeof(Mid0804), mid.GetType()); + AssertEqualPackages(package, mid, true); + } + + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ByteArray")] + public void Mid0804ByteRevision1() + { + string package = "00200804 "; + byte[] bytes = GetAsciiBytes(package); + var mid = _midInterpreter.Parse(bytes); + + Assert.AreEqual(typeof(Mid0804), mid.GetType()); + AssertEqualPackages(bytes, mid, true); + } + } +} diff --git a/src/MIDTesters.Core/Hvo/TestMid0510.cs b/src/MIDTesters.Core/Hvo/TestMid0510.cs new file mode 100644 index 0000000..e44d42a --- /dev/null +++ b/src/MIDTesters.Core/Hvo/TestMid0510.cs @@ -0,0 +1,33 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenProtocolInterpreter.Hvo; + +namespace MIDTesters.Hvo +{ + [TestClass] + [TestCategory("Hvo")] + public class TestMid0510 : DefaultMidTests + { + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ASCII")] + public void Mid0510Revision1() + { + string package = "00200510 "; + var mid = _midInterpreter.Parse(package); + + Assert.AreEqual(typeof(Mid0510), mid.GetType()); + AssertEqualPackages(package, mid, true); + } + + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ByteArray")] + public void Mid0510ByteRevision1() + { + string package = "00200510 "; + byte[] bytes = GetAsciiBytes(package); + var mid = _midInterpreter.Parse(bytes); + + Assert.AreEqual(typeof(Mid0510), mid.GetType()); + AssertEqualPackages(bytes, mid, true); + } + } +} diff --git a/src/MIDTesters.Core/Hvo/TestMid0512_0513.cs b/src/MIDTesters.Core/Hvo/TestMid0512_0513.cs new file mode 100644 index 0000000..f990544 --- /dev/null +++ b/src/MIDTesters.Core/Hvo/TestMid0512_0513.cs @@ -0,0 +1,55 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenProtocolInterpreter.Hvo; + +namespace MIDTesters.Hvo +{ + [TestClass] + [TestCategory("Hvo")] + public class TestMid0512 : DefaultMidTests + { + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ASCII")] + public void Mid0512Revision1() + { + string package = "00200512 "; + var mid = _midInterpreter.Parse(package); + Assert.AreEqual(typeof(Mid0512), mid.GetType()); + AssertEqualPackages(package, mid, true); + } + + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ByteArray")] + public void Mid0512ByteRevision1() + { + string package = "00200512 "; + var mid = _midInterpreter.Parse(GetAsciiBytes(package)); + Assert.AreEqual(typeof(Mid0512), mid.GetType()); + AssertEqualPackages(GetAsciiBytes(package), mid, true); + } + } + + [TestClass] + [TestCategory("Hvo")] + public class TestMid0513 : DefaultMidTests + { + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ASCII")] + public void Mid0513Revision1() + { + string package = "00200513 "; + var mid = _midInterpreter.Parse(package); + Assert.AreEqual(typeof(Mid0513), mid.GetType()); + AssertEqualPackages(package, mid, true); + } + + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ByteArray")] + public void Mid0513ByteRevision1() + { + string package = "00200513 "; + var mid = _midInterpreter.Parse(GetAsciiBytes(package)); + Assert.AreEqual(typeof(Mid0513), mid.GetType()); + AssertEqualPackages(GetAsciiBytes(package), mid, true); + } + } +} diff --git a/src/MIDTesters.Core/Hvo/TestMid0515.cs b/src/MIDTesters.Core/Hvo/TestMid0515.cs new file mode 100644 index 0000000..02bf7e0 --- /dev/null +++ b/src/MIDTesters.Core/Hvo/TestMid0515.cs @@ -0,0 +1,64 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenProtocolInterpreter.Hvo; + +namespace MIDTesters.Hvo +{ + [TestClass] + [TestCategory("Hvo")] + public class TestMid0515 : DefaultMidTests + { + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ASCII")] + public void Mid0515Revision1() + { + string package = "00320515001 011022033044"; + var mid = _midInterpreter.Parse(package); + + Assert.AreEqual(1, mid.Lamp1); + Assert.AreEqual(2, mid.Lamp2); + Assert.AreEqual(3, mid.Lamp3); + Assert.AreEqual(4, mid.Lamp4); + AssertEqualPackages(package, mid); + } + + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ByteArray")] + public void Mid0515ByteRevision1() + { + string package = "00320515001 011022033044"; + byte[] bytes = GetAsciiBytes(package); + var mid = _midInterpreter.Parse(bytes); + + Assert.AreEqual(1, mid.Lamp1); + Assert.AreEqual(2, mid.Lamp2); + Assert.AreEqual(3, mid.Lamp3); + Assert.AreEqual(4, mid.Lamp4); + AssertEqualPackages(bytes, mid); + } + + [TestMethod] + [TestCategory("Revision 2"), TestCategory("ASCII")] + public void Mid0515Revision2() + { + string package = "00300515002 0100102003"; + var mid = _midInterpreter.Parse(package); + + Assert.AreEqual(1, mid.LightNumber); + Assert.AreEqual(3, mid.LightStatus); + AssertEqualPackages(package, mid); + } + + [TestMethod] + [TestCategory("Revision 2"), TestCategory("ByteArray")] + public void Mid0515ByteRevision2() + { + string package = "00300515002 0100102003"; + byte[] bytes = GetAsciiBytes(package); + var mid = _midInterpreter.Parse(bytes); + + Assert.AreEqual(1, mid.LightNumber); + Assert.AreEqual(3, mid.LightStatus); + AssertEqualPackages(bytes, mid); + } + } +} diff --git a/src/MIDTesters.Core/RexrothJob/TestRexrothJobHeaderOnlyMids.cs b/src/MIDTesters.Core/RexrothJob/TestRexrothJobHeaderOnlyMids.cs new file mode 100644 index 0000000..b9c5fd9 --- /dev/null +++ b/src/MIDTesters.Core/RexrothJob/TestRexrothJobHeaderOnlyMids.cs @@ -0,0 +1,80 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenProtocolInterpreter.RexrothJob; + +namespace MIDTesters.RexrothJob +{ + [TestClass] + [TestCategory("RexrothJob")] + public class TestMid0554 : DefaultMidTests + { + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ASCII")] + public void Mid0554Revision1() + { + string package = "00200554 "; + var mid = _midInterpreter.Parse(package); + Assert.AreEqual(typeof(Mid0554), mid.GetType()); + AssertEqualPackages(package, mid, true); + } + + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ByteArray")] + public void Mid0554ByteRevision1() + { + string package = "00200554 "; + var mid = _midInterpreter.Parse(GetAsciiBytes(package)); + Assert.AreEqual(typeof(Mid0554), mid.GetType()); + AssertEqualPackages(GetAsciiBytes(package), mid, true); + } + } + + [TestClass] + [TestCategory("RexrothJob")] + public class TestMid0556 : DefaultMidTests + { + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ASCII")] + public void Mid0556Revision1() + { + string package = "00200556 "; + var mid = _midInterpreter.Parse(package); + Assert.AreEqual(typeof(Mid0556), mid.GetType()); + AssertEqualPackages(package, mid, true); + } + + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ByteArray")] + public void Mid0556ByteRevision1() + { + string package = "00200556 "; + var mid = _midInterpreter.Parse(GetAsciiBytes(package)); + Assert.AreEqual(typeof(Mid0556), mid.GetType()); + AssertEqualPackages(GetAsciiBytes(package), mid, true); + } + } + + [TestClass] + [TestCategory("RexrothJob")] + public class TestMid0557 : DefaultMidTests + { + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ASCII")] + public void Mid0557Revision1() + { + string package = "00200557 "; + var mid = _midInterpreter.Parse(package); + Assert.AreEqual(typeof(Mid0557), mid.GetType()); + AssertEqualPackages(package, mid, true); + } + + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ByteArray")] + public void Mid0557ByteRevision1() + { + string package = "00200557 "; + var mid = _midInterpreter.Parse(GetAsciiBytes(package)); + Assert.AreEqual(typeof(Mid0557), mid.GetType()); + AssertEqualPackages(GetAsciiBytes(package), mid, true); + } + } +} diff --git a/src/MIDTesters.Core/RexrothJob/TestRexrothJobMids.cs b/src/MIDTesters.Core/RexrothJob/TestRexrothJobMids.cs new file mode 100644 index 0000000..e24e4d8 --- /dev/null +++ b/src/MIDTesters.Core/RexrothJob/TestRexrothJobMids.cs @@ -0,0 +1,147 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenProtocolInterpreter.RexrothJob; + +namespace MIDTesters.RexrothJob +{ + [TestClass] + [TestCategory("RexrothJob")] + public class TestMid0555 : DefaultMidTests + { + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ASCII")] + public void Mid0555Revision1() + { + string package = "00280555 01001025"; + var mid = _midInterpreter.Parse(package); + + Assert.AreEqual(1, mid.JobResultNumber); + Assert.AreEqual(5, mid.JobResultValue); + AssertEqualPackages(package, mid, true); + } + + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ByteArray")] + public void Mid0555ByteRevision1() + { + string package = "00280555 01001025"; + byte[] bytes = GetAsciiBytes(package); + var mid = _midInterpreter.Parse(bytes); + + Assert.AreEqual(1, mid.JobResultNumber); + Assert.AreEqual(5, mid.JobResultValue); + AssertEqualPackages(bytes, mid, true); + } + } + + [TestClass] + [TestCategory("RexrothJob")] + public class TestMid0570 : DefaultMidTests + { + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ASCII")] + public void Mid0570Revision1() + { + string package = "00230570 011"; + var mid = _midInterpreter.Parse(package); + + Assert.IsTrue(mid.JobStatus); + AssertEqualPackages(package, mid, true); + } + + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ByteArray")] + public void Mid0570ByteRevision1() + { + string package = "00230570 011"; + byte[] bytes = GetAsciiBytes(package); + var mid = _midInterpreter.Parse(bytes); + + Assert.IsTrue(mid.JobStatus); + AssertEqualPackages(bytes, mid, true); + } + } + + [TestClass] + [TestCategory("RexrothJob")] + public class TestMid0571 : DefaultMidTests + { + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ASCII")] + public void Mid0571Revision1() + { + string package = "00230571 011"; + var mid = _midInterpreter.Parse(package); + + Assert.IsTrue(mid.JobStart); + AssertEqualPackages(package, mid, true); + } + + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ByteArray")] + public void Mid0571ByteRevision1() + { + string package = "00230571 011"; + byte[] bytes = GetAsciiBytes(package); + var mid = _midInterpreter.Parse(bytes); + + Assert.IsTrue(mid.JobStart); + AssertEqualPackages(bytes, mid, true); + } + } + + [TestClass] + [TestCategory("RexrothJob")] + public class TestMid0573 : DefaultMidTests + { + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ASCII")] + public void Mid0573Revision1() + { + string package = "00230573 001"; + var mid = _midInterpreter.Parse(package); + + Assert.AreEqual(1, mid.JobNumber); + AssertEqualPackages(package, mid, true); + } + + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ByteArray")] + public void Mid0573ByteRevision1() + { + string package = "00230573 001"; + byte[] bytes = GetAsciiBytes(package); + var mid = _midInterpreter.Parse(bytes); + + Assert.AreEqual(1, mid.JobNumber); + AssertEqualPackages(bytes, mid, true); + } + } + + [TestClass] + [TestCategory("RexrothJob")] + public class TestMid0574 : DefaultMidTests + { + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ASCII")] + public void Mid0574Revision1() + { + string package = "00240574 0101"; + var mid = _midInterpreter.Parse(package); + + Assert.AreEqual(1, mid.ActionCode); + AssertEqualPackages(package, mid, true); + } + + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ByteArray")] + public void Mid0574ByteRevision1() + { + string package = "00240574 0101"; + byte[] bytes = GetAsciiBytes(package); + var mid = _midInterpreter.Parse(bytes); + + Assert.AreEqual(1, mid.ActionCode); + AssertEqualPackages(bytes, mid, true); + } + } +} diff --git a/src/MIDTesters.Core/SocketTray/TestMid0520.cs b/src/MIDTesters.Core/SocketTray/TestMid0520.cs new file mode 100644 index 0000000..941659e --- /dev/null +++ b/src/MIDTesters.Core/SocketTray/TestMid0520.cs @@ -0,0 +1,33 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenProtocolInterpreter.SocketTray; + +namespace MIDTesters.SocketTray +{ + [TestClass] + [TestCategory("SocketTray")] + public class TestMid0520 : DefaultMidTests + { + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ASCII")] + public void Mid0520Revision1() + { + string package = "00200520 "; + var mid = _midInterpreter.Parse(package); + + Assert.AreEqual(typeof(Mid0520), mid.GetType()); + AssertEqualPackages(package, mid, true); + } + + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ByteArray")] + public void Mid0520ByteRevision1() + { + string package = "00200520 "; + byte[] bytes = GetAsciiBytes(package); + var mid = _midInterpreter.Parse(bytes); + + Assert.AreEqual(typeof(Mid0520), mid.GetType()); + AssertEqualPackages(bytes, mid, true); + } + } +} diff --git a/src/MIDTesters.Core/SocketTray/TestMid0522_0523.cs b/src/MIDTesters.Core/SocketTray/TestMid0522_0523.cs new file mode 100644 index 0000000..62212f4 --- /dev/null +++ b/src/MIDTesters.Core/SocketTray/TestMid0522_0523.cs @@ -0,0 +1,55 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenProtocolInterpreter.SocketTray; + +namespace MIDTesters.SocketTray +{ + [TestClass] + [TestCategory("SocketTray")] + public class TestMid0522 : DefaultMidTests + { + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ASCII")] + public void Mid0522Revision1() + { + string package = "00200522 "; + var mid = _midInterpreter.Parse(package); + Assert.AreEqual(typeof(Mid0522), mid.GetType()); + AssertEqualPackages(package, mid, true); + } + + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ByteArray")] + public void Mid0522ByteRevision1() + { + string package = "00200522 "; + var mid = _midInterpreter.Parse(GetAsciiBytes(package)); + Assert.AreEqual(typeof(Mid0522), mid.GetType()); + AssertEqualPackages(GetAsciiBytes(package), mid, true); + } + } + + [TestClass] + [TestCategory("SocketTray")] + public class TestMid0523 : DefaultMidTests + { + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ASCII")] + public void Mid0523Revision1() + { + string package = "00200523 "; + var mid = _midInterpreter.Parse(package); + Assert.AreEqual(typeof(Mid0523), mid.GetType()); + AssertEqualPackages(package, mid, true); + } + + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ByteArray")] + public void Mid0523ByteRevision1() + { + string package = "00200523 "; + var mid = _midInterpreter.Parse(GetAsciiBytes(package)); + Assert.AreEqual(typeof(Mid0523), mid.GetType()); + AssertEqualPackages(GetAsciiBytes(package), mid, true); + } + } +} diff --git a/src/MIDTesters.Core/SocketTray/TestMid0524.cs b/src/MIDTesters.Core/SocketTray/TestMid0524.cs new file mode 100644 index 0000000..61c8516 --- /dev/null +++ b/src/MIDTesters.Core/SocketTray/TestMid0524.cs @@ -0,0 +1,47 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenProtocolInterpreter.SocketTray; + +namespace MIDTesters.SocketTray +{ + [TestClass] + [TestCategory("SocketTray")] + public class TestMid0524 : DefaultMidTests + { + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ASCII")] + public void Mid0524Revision1() + { + string package = "00440524 011022033044055066077081"; + var mid = _midInterpreter.Parse(package); + + Assert.AreEqual(1, mid.Socket1); + Assert.AreEqual(2, mid.Socket2); + Assert.AreEqual(3, mid.Socket3); + Assert.AreEqual(4, mid.Socket4); + Assert.AreEqual(5, mid.Socket5); + Assert.AreEqual(6, mid.Socket6); + Assert.AreEqual(7, mid.Socket7); + Assert.AreEqual(1, mid.Socket8); + AssertEqualPackages(package, mid, true); + } + + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ByteArray")] + public void Mid0524ByteRevision1() + { + string package = "00440524 011022033044055066077081"; + byte[] bytes = GetAsciiBytes(package); + var mid = _midInterpreter.Parse(bytes); + + Assert.AreEqual(1, mid.Socket1); + Assert.AreEqual(2, mid.Socket2); + Assert.AreEqual(3, mid.Socket3); + Assert.AreEqual(4, mid.Socket4); + Assert.AreEqual(5, mid.Socket5); + Assert.AreEqual(6, mid.Socket6); + Assert.AreEqual(7, mid.Socket7); + Assert.AreEqual(1, mid.Socket8); + AssertEqualPackages(bytes, mid, true); + } + } +} diff --git a/src/MIDTesters.Core/Wifi/TestWifiMids.cs b/src/MIDTesters.Core/Wifi/TestWifiMids.cs new file mode 100644 index 0000000..e6bf9ac --- /dev/null +++ b/src/MIDTesters.Core/Wifi/TestWifiMids.cs @@ -0,0 +1,145 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenProtocolInterpreter.Wifi; + +namespace MIDTesters.Wifi +{ + [TestClass] + [TestCategory("Wifi")] + public class TestMid0805 : DefaultMidTests + { + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ASCII")] + public void Mid0805Revision1() + { + string package = "00200805 "; + var mid = _midInterpreter.Parse(package); + + Assert.AreEqual(typeof(Mid0805), mid.GetType()); + AssertEqualPackages(package, mid, true); + } + + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ByteArray")] + public void Mid0805ByteRevision1() + { + string package = "00200805 "; + byte[] bytes = GetAsciiBytes(package); + var mid = _midInterpreter.Parse(bytes); + + Assert.AreEqual(typeof(Mid0805), mid.GetType()); + AssertEqualPackages(bytes, mid, true); + } + } + + [TestClass] + [TestCategory("Wifi")] + public class TestMid0806 : DefaultMidTests + { + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ASCII")] + public void Mid0806Revision1() + { + string package = "00260806 01-080"; + var mid = _midInterpreter.Parse(package); + + Assert.AreEqual("-080", mid.ReceptionQuality); + AssertEqualPackages(package, mid, true); + } + + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ByteArray")] + public void Mid0806ByteRevision1() + { + string package = "00260806 01-080"; + byte[] bytes = GetAsciiBytes(package); + var mid = _midInterpreter.Parse(bytes); + + Assert.AreEqual("-080", mid.ReceptionQuality); + AssertEqualPackages(bytes, mid, true); + } + } + + [TestClass] + [TestCategory("Wifi")] + public class TestMid0807 : DefaultMidTests + { + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ASCII")] + public void Mid0807Revision1() + { + string package = "00220807 10"; + var mid = _midInterpreter.Parse(package); + + Assert.AreEqual(10, mid.ChangeLevel); + AssertEqualPackages(package, mid, true); + } + + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ByteArray")] + public void Mid0807ByteRevision1() + { + string package = "00220807 10"; + byte[] bytes = GetAsciiBytes(package); + var mid = _midInterpreter.Parse(bytes); + + Assert.AreEqual(10, mid.ChangeLevel); + AssertEqualPackages(bytes, mid, true); + } + } + + [TestClass] + [TestCategory("Wifi")] + public class TestMid0808 : DefaultMidTests + { + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ASCII")] + public void Mid0808Revision1() + { + string package = "00260808 01-080"; + var mid = _midInterpreter.Parse(package); + + Assert.AreEqual("-080", mid.ReceptionQuality); + AssertEqualPackages(package, mid, true); + } + + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ByteArray")] + public void Mid0808ByteRevision1() + { + string package = "00260808 01-080"; + byte[] bytes = GetAsciiBytes(package); + var mid = _midInterpreter.Parse(bytes); + + Assert.AreEqual("-080", mid.ReceptionQuality); + AssertEqualPackages(bytes, mid, true); + } + } + + [TestClass] + [TestCategory("Wifi")] + public class TestMid0809 : DefaultMidTests + { + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ASCII")] + public void Mid0809Revision1() + { + string package = "00200809 "; + var mid = _midInterpreter.Parse(package); + + Assert.AreEqual(typeof(Mid0809), mid.GetType()); + AssertEqualPackages(package, mid, true); + } + + [TestMethod] + [TestCategory("Revision 1"), TestCategory("ByteArray")] + public void Mid0809ByteRevision1() + { + string package = "00200809 "; + byte[] bytes = GetAsciiBytes(package); + var mid = _midInterpreter.Parse(bytes); + + Assert.AreEqual(typeof(Mid0809), mid.GetType()); + AssertEqualPackages(bytes, mid, true); + } + } +} diff --git a/src/OpenProtocolInterpreter/AutomaticManualMode/AutomaticManualModeMessages.cs b/src/OpenProtocolInterpreter/AutomaticManualMode/AutomaticManualModeMessages.cs index 07d63e8..e8bd9c8 100644 --- a/src/OpenProtocolInterpreter/AutomaticManualMode/AutomaticManualModeMessages.cs +++ b/src/OpenProtocolInterpreter/AutomaticManualMode/AutomaticManualModeMessages.cs @@ -17,6 +17,7 @@ public AutomaticManualModeMessages() : base() { Mid0401.MID, new MidCompiledInstance(typeof(Mid0401)) }, { Mid0402.MID, new MidCompiledInstance(typeof(Mid0402)) }, { Mid0403.MID, new MidCompiledInstance(typeof(Mid0403)) }, + { Mid0404.MID, new MidCompiledInstance(typeof(Mid0404)) }, { Mid0410.MID, new MidCompiledInstance(typeof(Mid0410)) }, { Mid0411.MID, new MidCompiledInstance(typeof(Mid0411)) } }; diff --git a/src/OpenProtocolInterpreter/AutomaticManualMode/Mid0404.cs b/src/OpenProtocolInterpreter/AutomaticManualMode/Mid0404.cs new file mode 100644 index 0000000..3ae7eff --- /dev/null +++ b/src/OpenProtocolInterpreter/AutomaticManualMode/Mid0404.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; + +namespace OpenProtocolInterpreter.AutomaticManualMode +{ + /// + /// Select automatic/manual mode + /// + /// The operating mode is changed. This is a Rexroth/NEXO vendor extension (FW ≥1300). + /// + /// Message sent by: Integrator + /// + /// Answer: Command accepted + /// + /// + public class Mid0404 : Mid, IAutomaticManualMode, IIntegrator, IAcceptableCommand + { + public const int MID = 404; + + /// + /// Automatic Mode = false (0) + /// Manual Mode = true (1) + /// + public bool ManualAutomaticMode + { + get => GetField(1, DataFields.ManualAutomaticMode).GetValue(OpenProtocolConvert.ToBoolean); + set => GetField(1, DataFields.ManualAutomaticMode).SetValue(OpenProtocolConvert.ToString, value); + } + + public Mid0404() : this(DEFAULT_REVISION) { } + + public Mid0404(Header header) : base(header) + { + } + + public Mid0404(int revision) : this(new Header() { Mid = MID, Revision = revision }) + { + } + + protected override Dictionary> RegisterDatafields() + { + return new Dictionary>() + { + { + 1, new List() + { + DataField.Boolean(DataFields.ManualAutomaticMode, 20, false) + } + } + }; + } + + protected enum DataFields + { + ManualAutomaticMode + } + } +} diff --git a/src/OpenProtocolInterpreter/Battery/BatteryMessages.cs b/src/OpenProtocolInterpreter/Battery/BatteryMessages.cs new file mode 100644 index 0000000..c84da14 --- /dev/null +++ b/src/OpenProtocolInterpreter/Battery/BatteryMessages.cs @@ -0,0 +1,36 @@ +using OpenProtocolInterpreter.Messages; +using System; +using System.Collections.Generic; + +namespace OpenProtocolInterpreter.Battery +{ + /// + /// Template for implementers. + /// + internal class BatteryMessages : MessagesTemplate + { + public BatteryMessages() : base() + { + _templates = new Dictionary() + { + { Mid0800.MID, new MidCompiledInstance(typeof(Mid0800)) }, + { Mid0801.MID, new MidCompiledInstance(typeof(Mid0801)) }, + { Mid0802.MID, new MidCompiledInstance(typeof(Mid0802)) }, + { Mid0803.MID, new MidCompiledInstance(typeof(Mid0803)) }, + { Mid0804.MID, new MidCompiledInstance(typeof(Mid0804)) } + }; + } + + public BatteryMessages(IEnumerable selectedMids) : this() + { + FilterSelectedMids(selectedMids); + } + + public BatteryMessages(InterpreterMode mode) : this() + { + FilterSelectedMids(mode); + } + + public override bool IsAssignableTo(int mid) => mid > 799 && mid < 805; + } +} diff --git a/src/OpenProtocolInterpreter/Battery/IBattery.cs b/src/OpenProtocolInterpreter/Battery/IBattery.cs new file mode 100644 index 0000000..4edb224 --- /dev/null +++ b/src/OpenProtocolInterpreter/Battery/IBattery.cs @@ -0,0 +1,10 @@ +namespace OpenProtocolInterpreter.Battery +{ + /// + /// Battery message category. Every battery mid must implement . + /// Rexroth/NEXO vendor extension for battery level monitoring (FW ≥1100). + /// + public interface IBattery + { + } +} diff --git a/src/OpenProtocolInterpreter/Battery/Mid0800.cs b/src/OpenProtocolInterpreter/Battery/Mid0800.cs new file mode 100644 index 0000000..64ce6fb --- /dev/null +++ b/src/OpenProtocolInterpreter/Battery/Mid0800.cs @@ -0,0 +1,19 @@ +namespace OpenProtocolInterpreter.Battery +{ + /// + /// Battery level request + /// Request the current battery level from the controller. + /// Message sent by: Integrator + /// Answer: Battery level response + /// + public class Mid0800 : Mid, IBattery, IIntegrator, IAnswerableBy + { + public const int MID = 800; + + public Mid0800() : this(DEFAULT_REVISION) { } + + public Mid0800(Header header) : base(header) { } + + public Mid0800(int revision) : this(new Header() { Mid = MID, Revision = revision }) { } + } +} diff --git a/src/OpenProtocolInterpreter/Battery/Mid0801.cs b/src/OpenProtocolInterpreter/Battery/Mid0801.cs new file mode 100644 index 0000000..61e77f0 --- /dev/null +++ b/src/OpenProtocolInterpreter/Battery/Mid0801.cs @@ -0,0 +1,67 @@ +using System.Collections.Generic; + +namespace OpenProtocolInterpreter.Battery +{ + /// + /// Battery level response + /// + /// The controller transmits the current battery level including capacity percentage and state. + /// + /// Message sent by: Controller + /// Answer: None + /// + public class Mid0801 : Mid, IBattery, IController + { + public const int MID = 801; + + /// + /// Battery pack capacity in percent (000-100). + /// + public int Capacity + { + get => GetField(1, DataFields.Capacity).GetValue(OpenProtocolConvert.ToInt32); + set => GetField(1, DataFields.Capacity).SetValue(OpenProtocolConvert.ToString, value); + } + + /// + /// State of the battery pack: + /// 0 = Battery pack not inserted + /// 1 = Battery level critical (system shutdown) + /// 2 = Battery insufficient for tightening + /// 3 = Battery level okay + /// 4 = Battery reinserted (checking charge) + /// 5 = Battery warning level reached + /// + public int State + { + get => GetField(1, DataFields.State).GetValue(OpenProtocolConvert.ToInt32); + set => GetField(1, DataFields.State).SetValue(OpenProtocolConvert.ToString, value); + } + + public Mid0801() : this(DEFAULT_REVISION) { } + + public Mid0801(Header header) : base(header) { } + + public Mid0801(int revision) : this(new Header() { Mid = MID, Revision = revision }) { } + + protected override Dictionary> RegisterDatafields() + { + return new Dictionary>() + { + { + 1, new List() + { + DataField.Number(DataFields.Capacity, 20, 3), + DataField.Number(DataFields.State, 25, 1) + } + } + }; + } + + protected enum DataFields + { + Capacity, + State + } + } +} diff --git a/src/OpenProtocolInterpreter/Battery/Mid0802.cs b/src/OpenProtocolInterpreter/Battery/Mid0802.cs new file mode 100644 index 0000000..e5a946c --- /dev/null +++ b/src/OpenProtocolInterpreter/Battery/Mid0802.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; + +namespace OpenProtocolInterpreter.Battery +{ + /// + /// Battery level changes subscribe + /// + /// Subscribe to battery level change notifications. After subscription, the controller + /// sends when the battery level changes by the specified threshold. + /// + /// Message sent by: Integrator + /// + /// Answer: Command accepted or + /// Command error, subscription already exists + /// + /// + public class Mid0802 : Mid, IBattery, IIntegrator, ISubscription, IAcceptableCommand, IDeclinableCommand + { + public const int MID = 802; + + public IEnumerable DocumentedPossibleErrors => new Error[] { Error.SubscriptionAlreadyExists }; + + /// + /// Change threshold in percent of maximum capacity (00-99). + /// When the capacity changes by this amount, a notification is sent. + /// + public int ChangeLevel + { + get => GetField(1, DataFields.ChangeLevel).GetValue(OpenProtocolConvert.ToInt32); + set => GetField(1, DataFields.ChangeLevel).SetValue(OpenProtocolConvert.ToString, value); + } + + public Mid0802() : this(DEFAULT_REVISION) { } + + public Mid0802(Header header) : base(header) { } + + public Mid0802(int revision) : this(new Header() { Mid = MID, Revision = revision }) { } + + protected override Dictionary> RegisterDatafields() + { + return new Dictionary>() + { + { + 1, new List() + { + DataField.Number(DataFields.ChangeLevel, 20, 2, false) + } + } + }; + } + + protected enum DataFields + { + ChangeLevel + } + } +} diff --git a/src/OpenProtocolInterpreter/Battery/Mid0803.cs b/src/OpenProtocolInterpreter/Battery/Mid0803.cs new file mode 100644 index 0000000..a2c746c --- /dev/null +++ b/src/OpenProtocolInterpreter/Battery/Mid0803.cs @@ -0,0 +1,68 @@ +using System.Collections.Generic; + +namespace OpenProtocolInterpreter.Battery +{ + /// + /// Battery level changes upload + /// + /// The controller reports the current battery level when it changes. + /// Same data format as . + /// + /// Message sent by: Controller + /// Answer: None + /// + public class Mid0803 : Mid, IBattery, IController + { + public const int MID = 803; + + /// + /// Battery pack capacity in percent (000-100). + /// + public int Capacity + { + get => GetField(1, DataFields.Capacity).GetValue(OpenProtocolConvert.ToInt32); + set => GetField(1, DataFields.Capacity).SetValue(OpenProtocolConvert.ToString, value); + } + + /// + /// State of the battery pack: + /// 0 = Battery pack not inserted + /// 1 = Battery level critical (system shutdown) + /// 2 = Battery insufficient for tightening + /// 3 = Battery level okay + /// 4 = Battery reinserted (checking charge) + /// 5 = Battery warning level reached + /// + public int State + { + get => GetField(1, DataFields.State).GetValue(OpenProtocolConvert.ToInt32); + set => GetField(1, DataFields.State).SetValue(OpenProtocolConvert.ToString, value); + } + + public Mid0803() : this(DEFAULT_REVISION) { } + + public Mid0803(Header header) : base(header) { } + + public Mid0803(int revision) : this(new Header() { Mid = MID, Revision = revision }) { } + + protected override Dictionary> RegisterDatafields() + { + return new Dictionary>() + { + { + 1, new List() + { + DataField.Number(DataFields.Capacity, 20, 3), + DataField.Number(DataFields.State, 25, 1) + } + } + }; + } + + protected enum DataFields + { + Capacity, + State + } + } +} diff --git a/src/OpenProtocolInterpreter/Battery/Mid0804.cs b/src/OpenProtocolInterpreter/Battery/Mid0804.cs new file mode 100644 index 0000000..092e645 --- /dev/null +++ b/src/OpenProtocolInterpreter/Battery/Mid0804.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; + +namespace OpenProtocolInterpreter.Battery +{ + /// + /// Cancel battery level changes subscription + /// Cancel the subscription for battery level change notifications. + /// Message sent by: Integrator + /// + /// Answer: Command accepted or + /// Command error, subscription does not exist + /// + /// + public class Mid0804 : Mid, IBattery, IIntegrator, IUnsubscription, IAcceptableCommand, IDeclinableCommand + { + public const int MID = 804; + + public IEnumerable DocumentedPossibleErrors => new Error[] { Error.SubscriptionDoesntExists }; + + public Mid0804() : this(DEFAULT_REVISION) { } + + public Mid0804(Header header) : base(header) { } + + public Mid0804(int revision) : this(new Header() { Mid = MID, Revision = revision }) { } + } +} diff --git a/src/OpenProtocolInterpreter/Hvo/HvoMessages.cs b/src/OpenProtocolInterpreter/Hvo/HvoMessages.cs new file mode 100644 index 0000000..8d2dc2c --- /dev/null +++ b/src/OpenProtocolInterpreter/Hvo/HvoMessages.cs @@ -0,0 +1,35 @@ +using OpenProtocolInterpreter.Messages; +using System; +using System.Collections.Generic; + +namespace OpenProtocolInterpreter.Hvo +{ + /// + /// Template for implementers. + /// + internal class HvoMessages : MessagesTemplate + { + public HvoMessages() : base() + { + _templates = new Dictionary() + { + { Mid0510.MID, new MidCompiledInstance(typeof(Mid0510)) }, + { Mid0512.MID, new MidCompiledInstance(typeof(Mid0512)) }, + { Mid0513.MID, new MidCompiledInstance(typeof(Mid0513)) }, + { Mid0515.MID, new MidCompiledInstance(typeof(Mid0515)) } + }; + } + + public HvoMessages(IEnumerable selectedMids) : this() + { + FilterSelectedMids(selectedMids); + } + + public HvoMessages(InterpreterMode mode) : this() + { + FilterSelectedMids(mode); + } + + public override bool IsAssignableTo(int mid) => mid > 509 && mid < 516; + } +} diff --git a/src/OpenProtocolInterpreter/Hvo/IHvo.cs b/src/OpenProtocolInterpreter/Hvo/IHvo.cs new file mode 100644 index 0000000..32739e5 --- /dev/null +++ b/src/OpenProtocolInterpreter/Hvo/IHvo.cs @@ -0,0 +1,10 @@ +namespace OpenProtocolInterpreter.Hvo +{ + /// + /// HVO (Hand-guided Visual Output) message category. Every HVO mid must implement . + /// Rexroth/NEXO vendor extension for visual operator guidance signals. + /// + public interface IHvo + { + } +} diff --git a/src/OpenProtocolInterpreter/Hvo/Mid0510.cs b/src/OpenProtocolInterpreter/Hvo/Mid0510.cs new file mode 100644 index 0000000..7e98c58 --- /dev/null +++ b/src/OpenProtocolInterpreter/Hvo/Mid0510.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; + +namespace OpenProtocolInterpreter.Hvo +{ + /// + /// HVO signal change subscribe + /// + /// Subscribe to HVO (Hand-guided Visual Output) button change notifications. + /// After subscription, the controller sends MID 0511 on each HVO state change. + /// + /// Message sent by: Integrator + /// + /// Answer: Command accepted or + /// Command error + /// + /// + public class Mid0510 : Mid, IHvo, IIntegrator, ISubscription, IAcceptableCommand, IDeclinableCommand + { + public const int MID = 510; + + public IEnumerable DocumentedPossibleErrors => new Error[] { Error.SubscriptionAlreadyExists }; + + public Mid0510() : this(DEFAULT_REVISION) { } + + public Mid0510(Header header) : base(header) { } + + public Mid0510(int revision) : this(new Header() { Mid = MID, Revision = revision }) { } + } +} diff --git a/src/OpenProtocolInterpreter/Hvo/Mid0512.cs b/src/OpenProtocolInterpreter/Hvo/Mid0512.cs new file mode 100644 index 0000000..27f2f89 --- /dev/null +++ b/src/OpenProtocolInterpreter/Hvo/Mid0512.cs @@ -0,0 +1,19 @@ +namespace OpenProtocolInterpreter.Hvo +{ + /// + /// HVO signal change acknowledge + /// Acknowledgement of HVO signal change upload (MID 0511). + /// Message sent by: Integrator + /// Answer: None + /// + public class Mid0512 : Mid, IHvo, IIntegrator, IAcknowledge + { + public const int MID = 512; + + public Mid0512() : this(DEFAULT_REVISION) { } + + public Mid0512(Header header) : base(header) { } + + public Mid0512(int revision) : this(new Header() { Mid = MID, Revision = revision }) { } + } +} diff --git a/src/OpenProtocolInterpreter/Hvo/Mid0513.cs b/src/OpenProtocolInterpreter/Hvo/Mid0513.cs new file mode 100644 index 0000000..a356189 --- /dev/null +++ b/src/OpenProtocolInterpreter/Hvo/Mid0513.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; + +namespace OpenProtocolInterpreter.Hvo +{ + /// + /// HVO signal change unsubscribe + /// Cancel the subscription for HVO signal change notifications. + /// Message sent by: Integrator + /// + /// Answer: Command accepted or + /// Command error + /// + /// + public class Mid0513 : Mid, IHvo, IIntegrator, IUnsubscription, IAcceptableCommand, IDeclinableCommand + { + public const int MID = 513; + + public IEnumerable DocumentedPossibleErrors => new Error[] { Error.SubscriptionDoesntExists }; + + public Mid0513() : this(DEFAULT_REVISION) { } + + public Mid0513(Header header) : base(header) { } + + public Mid0513(int revision) : this(new Header() { Mid = MID, Revision = revision }) { } + } +} diff --git a/src/OpenProtocolInterpreter/Hvo/Mid0515.cs b/src/OpenProtocolInterpreter/Hvo/Mid0515.cs new file mode 100644 index 0000000..b04a94d --- /dev/null +++ b/src/OpenProtocolInterpreter/Hvo/Mid0515.cs @@ -0,0 +1,147 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenProtocolInterpreter.Hvo +{ + /// + /// Set HVO signal + /// + /// Command to set the HVO (Hand-guided Visual Output) lamp signals. + /// Revision 1: Controls 4 individual lamp signals. + /// Revision 2: Controls a numbered light with a status value. + /// + /// Message sent by: Integrator + /// Answer: None + /// + public class Mid0515 : Mid, IHvo, IIntegrator + { + public const int MID = 515; + + /// + /// Revision 1: Lamp 1 signal value (0-9). + /// + public int Lamp1 + { + get => GetField(1, DataFields.Lamp1).GetValue(OpenProtocolConvert.ToInt32); + set => GetField(1, DataFields.Lamp1).SetValue(OpenProtocolConvert.ToString, value); + } + + /// + /// Revision 1: Lamp 2 signal value (0-9). + /// + public int Lamp2 + { + get => GetField(1, DataFields.Lamp2).GetValue(OpenProtocolConvert.ToInt32); + set => GetField(1, DataFields.Lamp2).SetValue(OpenProtocolConvert.ToString, value); + } + + /// + /// Revision 1: Lamp 3 signal value (0-9). + /// + public int Lamp3 + { + get => GetField(1, DataFields.Lamp3).GetValue(OpenProtocolConvert.ToInt32); + set => GetField(1, DataFields.Lamp3).SetValue(OpenProtocolConvert.ToString, value); + } + + /// + /// Revision 1: Lamp 4 signal value (0-9). + /// + public int Lamp4 + { + get => GetField(1, DataFields.Lamp4).GetValue(OpenProtocolConvert.ToInt32); + set => GetField(1, DataFields.Lamp4).SetValue(OpenProtocolConvert.ToString, value); + } + + /// + /// Revision 2: Light number (1-999). + /// + public int LightNumber + { + get => GetField(2, DataFields.LightNumber).GetValue(OpenProtocolConvert.ToInt32); + set => GetField(2, DataFields.LightNumber).SetValue(OpenProtocolConvert.ToString, value); + } + + /// + /// Revision 2: Light status value (1-999). + /// + public int LightStatus + { + get => GetField(2, DataFields.LightStatus).GetValue(OpenProtocolConvert.ToInt32); + set => GetField(2, DataFields.LightStatus).SetValue(OpenProtocolConvert.ToString, value); + } + + public Mid0515() : this(DEFAULT_REVISION) { } + + public Mid0515(int revision) : this(new Header() + { + Mid = MID, + Revision = revision + }) + { + } + + public Mid0515(Header header) : base(header) { } + + /// + /// Revision 2 is a replacement format, not additive. Only process the current revision's fields. + /// + protected override void ProcessDataFields(string package) + { + ProcessDataFields(Header.StandardizedRevision, package); + } + + public override string Pack() + { + if (!RevisionsByFields.Any()) + return BuildHeader(); + + int revision = Header.StandardizedRevision; + if (RevisionsByFields.TryGetValue(revision, out var dataFields)) + { + Header.Length = Header.DefaultSize; + foreach (var dataField in dataFields) + Header.Length += (dataField.HasPrefix ? 2 : 0) + dataField.Size; + } + + var builder = new StringBuilder(Header.ToString()); + int prefixIndex = 1; + builder.Append(Pack(revision, ref prefixIndex)); + return builder.ToString(); + } + + protected override Dictionary> RegisterDatafields() + { + return new Dictionary>() + { + { + 1, new List() + { + DataField.Number(DataFields.Lamp1, 20, 1), + DataField.Number(DataFields.Lamp2, 23, 1), + DataField.Number(DataFields.Lamp3, 26, 1), + DataField.Number(DataFields.Lamp4, 29, 1) + } + }, + { + 2, new List() + { + DataField.Number(DataFields.LightNumber, 20, 3), + DataField.Number(DataFields.LightStatus, 25, 3) + } + } + }; + } + + protected enum DataFields + { + Lamp1, + Lamp2, + Lamp3, + Lamp4, + LightNumber, + LightStatus + } + } +} diff --git a/src/OpenProtocolInterpreter/MidInterpreterMessagesExtensions.cs b/src/OpenProtocolInterpreter/MidInterpreterMessagesExtensions.cs index 90ddcc6..d0c0512 100644 --- a/src/OpenProtocolInterpreter/MidInterpreterMessagesExtensions.cs +++ b/src/OpenProtocolInterpreter/MidInterpreterMessagesExtensions.cs @@ -3,7 +3,9 @@ using OpenProtocolInterpreter.ApplicationSelector; using OpenProtocolInterpreter.ApplicationToolLocationSystem; using OpenProtocolInterpreter.AutomaticManualMode; +using OpenProtocolInterpreter.Battery; using OpenProtocolInterpreter.Communication; +using OpenProtocolInterpreter.Hvo; using OpenProtocolInterpreter.IOInterface; using OpenProtocolInterpreter.Job; using OpenProtocolInterpreter.Job.Advanced; @@ -15,13 +17,16 @@ using OpenProtocolInterpreter.ParameterSet; using OpenProtocolInterpreter.PLCUserData; using OpenProtocolInterpreter.PowerMACS; +using OpenProtocolInterpreter.RexrothJob; using OpenProtocolInterpreter.Result; +using OpenProtocolInterpreter.SocketTray; using OpenProtocolInterpreter.Statistic; using OpenProtocolInterpreter.Tightening; using OpenProtocolInterpreter.Time; using OpenProtocolInterpreter.Tool; using OpenProtocolInterpreter.UserInterface; using OpenProtocolInterpreter.Vin; +using OpenProtocolInterpreter.Wifi; using System; using System.Collections.Generic; using System.Linq; @@ -48,10 +53,13 @@ public static MidInterpreter UseAllMessages(this MidInterpreter midInterpreter, .UseApplicationSelectorMessages(mode) .UseApplicationToolLocationSystemMessages(mode) .UseAutomaticManualModeMessages(mode) + .UseBatteryMessages(mode) .UseCommunicationMessages(mode) + .UseHvoMessages(mode) .UseIOInterfaceMessages(mode) .UseJobMessages(mode) .UseAdvancedJobMessages(mode) + .UseRexrothJobMessages(mode) .UseLinkCommunicationMessages(mode) .UseMotorTuningMessages(mode) .UseMultipleIdentifiersMessages(mode) @@ -61,12 +69,14 @@ public static MidInterpreter UseAllMessages(this MidInterpreter midInterpreter, .UsePLCUserDataMessages(mode) .UsePowerMACSMessages(mode) .UseResultMessages(mode) + .UseSocketTrayMessages(mode) .UseStatisticMessages(mode) .UseTighteningMessages(mode) .UseTimeMessages(mode) .UseToolMessages(mode) .UseUserInterfaceMessages(mode) - .UseVinMessages(mode); + .UseVinMessages(mode) + .UseWifiMessages(mode); } /// @@ -86,10 +96,13 @@ public static MidInterpreter UseAllMessages(this MidInterpreter midInterpreter, .UseApplicationSelectorMessages(mids.Where(x => DoesImplementInterface(x, typeof(IApplicationSelector)))) .UseApplicationToolLocationSystemMessages(mids.Where(x => DoesImplementInterface(x, typeof(IApplicationToolLocationSystem)))) .UseAutomaticManualModeMessages(mids.Where(x => DoesImplementInterface(x, typeof(IAutomaticManualMode)))) + .UseBatteryMessages(mids.Where(x => DoesImplementInterface(x, typeof(IBattery)))) .UseCommunicationMessages(mids.Where(x => DoesImplementInterface(x, typeof(ICommunication)))) + .UseHvoMessages(mids.Where(x => DoesImplementInterface(x, typeof(IHvo)))) .UseIOInterfaceMessages(mids.Where(x => DoesImplementInterface(x, typeof(IIOInterface)))) .UseJobMessages(mids.Where(x => DoesImplementInterface(x, typeof(IJob)))) .UseAdvancedJobMessages(mids.Where(x => DoesImplementInterface(x, typeof(IAdvancedJob)))) + .UseRexrothJobMessages(mids.Where(x => DoesImplementInterface(x, typeof(IRexrothJob)))) .UseLinkCommunicationMessages(mids.Where(x => DoesImplementInterface(x, typeof(ILinkCommunication)))) .UseMotorTuningMessages(mids.Where(x => DoesImplementInterface(x, typeof(IMotorTuning)))) .UseMultipleIdentifiersMessages(mids.Where(x => DoesImplementInterface(x, typeof(IMultipleIdentifier)))) @@ -99,12 +112,14 @@ public static MidInterpreter UseAllMessages(this MidInterpreter midInterpreter, .UsePLCUserDataMessages(mids.Where(x => DoesImplementInterface(x, typeof(IPLCUserData)))) .UsePowerMACSMessages(mids.Where(x => DoesImplementInterface(x, typeof(IPowerMACS)))) .UseResultMessages(mids.Where(x => DoesImplementInterface(x, typeof(IResult)))) + .UseSocketTrayMessages(mids.Where(x => DoesImplementInterface(x, typeof(ISocketTray)))) .UseStatisticMessages(mids.Where(x => DoesImplementInterface(x, typeof(IStatistic)))) .UseTighteningMessages(mids.Where(x => DoesImplementInterface(x, typeof(ITightening)))) .UseTimeMessages(mids.Where(x => DoesImplementInterface(x, typeof(ITime)))) .UseToolMessages(mids.Where(x => DoesImplementInterface(x, typeof(ITool)))) .UseUserInterfaceMessages(mids.Where(x => DoesImplementInterface(x, typeof(IUserInterface)))) - .UseVinMessages(mids.Where(x => DoesImplementInterface(x, typeof(IVin)))); + .UseVinMessages(mids.Where(x => DoesImplementInterface(x, typeof(IVin)))) + .UseWifiMessages(mids.Where(x => DoesImplementInterface(x, typeof(IWifi)))); } /// @@ -998,6 +1013,196 @@ public static MidInterpreter UseUserInterfaceMessages(this MidInterpreter midInt return midInterpreter; } + /// + /// Include MIDs into interpreter + /// + /// MidInterpreter instance + /// Are you the integrator or controller? + /// MidInterpreter instance + public static MidInterpreter UseBatteryMessages(this MidInterpreter midInterpreter, InterpreterMode mode = InterpreterMode.Both) + { + midInterpreter.UseTemplate(mode); + return midInterpreter; + } + + /// + /// Include only a specific collection of MIDs into interpreter + /// + /// MidInterpreter instance + /// Mids that you want to be available for parsing + /// MidInterpreter instance + public static MidInterpreter UseBatteryMessages(this MidInterpreter midInterpreter, IEnumerable mids) + { + ThrowIfInvalid(mids); + midInterpreter.UseTemplate(mids); + return midInterpreter; + } + + /// + /// Add all if not added yet and override specified Mids + /// + /// MidInterpreter instance + /// Dictionary with Mid x your custom type to override + /// MidInterpreter instance + public static MidInterpreter UseBatteryMessages(this MidInterpreter midInterpreter, IDictionary mids) + { + ThrowIfInvalid(mids); + midInterpreter.UseTemplate(mids); + return midInterpreter; + } + + /// + /// Include MIDs into interpreter + /// + /// MidInterpreter instance + /// Are you the integrator or controller? + /// MidInterpreter instance + public static MidInterpreter UseHvoMessages(this MidInterpreter midInterpreter, InterpreterMode mode = InterpreterMode.Both) + { + midInterpreter.UseTemplate(mode); + return midInterpreter; + } + + /// + /// Include only a specific collection of MIDs into interpreter + /// + /// MidInterpreter instance + /// Mids that you want to be available for parsing + /// MidInterpreter instance + public static MidInterpreter UseHvoMessages(this MidInterpreter midInterpreter, IEnumerable mids) + { + ThrowIfInvalid(mids); + midInterpreter.UseTemplate(mids); + return midInterpreter; + } + + /// + /// Add all if not added yet and override specified Mids + /// + /// MidInterpreter instance + /// Dictionary with Mid x your custom type to override + /// MidInterpreter instance + public static MidInterpreter UseHvoMessages(this MidInterpreter midInterpreter, IDictionary mids) + { + ThrowIfInvalid(mids); + midInterpreter.UseTemplate(mids); + return midInterpreter; + } + + /// + /// Include MIDs into interpreter + /// + /// MidInterpreter instance + /// Are you the integrator or controller? + /// MidInterpreter instance + public static MidInterpreter UseRexrothJobMessages(this MidInterpreter midInterpreter, InterpreterMode mode = InterpreterMode.Both) + { + midInterpreter.UseTemplate(mode); + return midInterpreter; + } + + /// + /// Include only a specific collection of MIDs into interpreter + /// + /// MidInterpreter instance + /// Mids that you want to be available for parsing + /// MidInterpreter instance + public static MidInterpreter UseRexrothJobMessages(this MidInterpreter midInterpreter, IEnumerable mids) + { + ThrowIfInvalid(mids); + midInterpreter.UseTemplate(mids); + return midInterpreter; + } + + /// + /// Add all if not added yet and override specified Mids + /// + /// MidInterpreter instance + /// Dictionary with Mid x your custom type to override + /// MidInterpreter instance + public static MidInterpreter UseRexrothJobMessages(this MidInterpreter midInterpreter, IDictionary mids) + { + ThrowIfInvalid(mids); + midInterpreter.UseTemplate(mids); + return midInterpreter; + } + + /// + /// Include MIDs into interpreter + /// + /// MidInterpreter instance + /// Are you the integrator or controller? + /// MidInterpreter instance + public static MidInterpreter UseSocketTrayMessages(this MidInterpreter midInterpreter, InterpreterMode mode = InterpreterMode.Both) + { + midInterpreter.UseTemplate(mode); + return midInterpreter; + } + + /// + /// Include only a specific collection of MIDs into interpreter + /// + /// MidInterpreter instance + /// Mids that you want to be available for parsing + /// MidInterpreter instance + public static MidInterpreter UseSocketTrayMessages(this MidInterpreter midInterpreter, IEnumerable mids) + { + ThrowIfInvalid(mids); + midInterpreter.UseTemplate(mids); + return midInterpreter; + } + + /// + /// Add all if not added yet and override specified Mids + /// + /// MidInterpreter instance + /// Dictionary with Mid x your custom type to override + /// MidInterpreter instance + public static MidInterpreter UseSocketTrayMessages(this MidInterpreter midInterpreter, IDictionary mids) + { + ThrowIfInvalid(mids); + midInterpreter.UseTemplate(mids); + return midInterpreter; + } + + /// + /// Include MIDs into interpreter + /// + /// MidInterpreter instance + /// Are you the integrator or controller? + /// MidInterpreter instance + public static MidInterpreter UseWifiMessages(this MidInterpreter midInterpreter, InterpreterMode mode = InterpreterMode.Both) + { + midInterpreter.UseTemplate(mode); + return midInterpreter; + } + + /// + /// Include only a specific collection of MIDs into interpreter + /// + /// MidInterpreter instance + /// Mids that you want to be available for parsing + /// MidInterpreter instance + public static MidInterpreter UseWifiMessages(this MidInterpreter midInterpreter, IEnumerable mids) + { + ThrowIfInvalid(mids); + midInterpreter.UseTemplate(mids); + return midInterpreter; + } + + /// + /// Add all if not added yet and override specified Mids + /// + /// MidInterpreter instance + /// Dictionary with Mid x your custom type to override + /// MidInterpreter instance + public static MidInterpreter UseWifiMessages(this MidInterpreter midInterpreter, IDictionary mids) + { + ThrowIfInvalid(mids); + midInterpreter.UseTemplate(mids); + return midInterpreter; + } + /// /// Include MIDs into interpreter /// diff --git a/src/OpenProtocolInterpreter/OpenProtocolInterpreter.csproj b/src/OpenProtocolInterpreter/OpenProtocolInterpreter.csproj index 22e57ae..72154a8 100644 --- a/src/OpenProtocolInterpreter/OpenProtocolInterpreter.csproj +++ b/src/OpenProtocolInterpreter/OpenProtocolInterpreter.csproj @@ -4,16 +4,17 @@ netstandard2.0;net6.0;net8.0;net10.0 latest 6.1.1 - Converts the ugly package that came from Open Protocol to an object - Copyright © 2026 - Henrique Dal Bello Batista - Henrique Dal Bello Batista - https://github.com/Rickedb/OpenProtocolInterpreter - https://github.com/Rickedb/OpenProtocolInterpreter + HallerErne.OpenProtocolInterpreter + Bidirectional serializer/deserializer for Atlas Copco Open Protocol MID messages. Forked from Rickedb/OpenProtocolInterpreter with Rexroth/NEXO vendor-specific MID extensions. + Copyright © 2026 Haller + Erne GmbH + Haller + Erne GmbH + Haller + Erne GmbH + https://github.com/hallererne/OpenProtocolInterpreter + https://github.com/hallererne/OpenProtocolInterpreter MIT - CSharp Open Protocol Atlas Copco + CSharp Open Protocol Atlas Copco Rexroth NEXO true - See release notes at: https://github.com/Rickedb/OpenProtocolInterpreter/releases/tag/6.1.0 + Forked from https://github.com/Rickedb/OpenProtocolInterpreter. Added Rexroth/NEXO vendor-specific MIDs (0404, 0510-0515, 0520-0524, 0554-0574, 0800-0809). icon.png diff --git a/src/OpenProtocolInterpreter/RexrothJob/IRexrothJob.cs b/src/OpenProtocolInterpreter/RexrothJob/IRexrothJob.cs new file mode 100644 index 0000000..06c5779 --- /dev/null +++ b/src/OpenProtocolInterpreter/RexrothJob/IRexrothJob.cs @@ -0,0 +1,10 @@ +namespace OpenProtocolInterpreter.RexrothJob +{ + /// + /// Rexroth Job message category. Every Rexroth job mid must implement . + /// Rexroth/NEXO vendor extension for advanced job control (activate, start, select, manipulate). + /// + public interface IRexrothJob + { + } +} diff --git a/src/OpenProtocolInterpreter/RexrothJob/Mid0554.cs b/src/OpenProtocolInterpreter/RexrothJob/Mid0554.cs new file mode 100644 index 0000000..0f2412e --- /dev/null +++ b/src/OpenProtocolInterpreter/RexrothJob/Mid0554.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; + +namespace OpenProtocolInterpreter.RexrothJob +{ + /// + /// Rexroth job result subscribe + /// + /// Subscribe to job result notifications. After subscription, the controller sends + /// on each job result. + /// + /// Message sent by: Integrator + /// + /// Answer: Command accepted or + /// Command error + /// + /// + public class Mid0554 : Mid, IRexrothJob, IIntegrator, ISubscription, IAcceptableCommand, IDeclinableCommand + { + public const int MID = 554; + + public IEnumerable DocumentedPossibleErrors => new Error[] { Error.SubscriptionAlreadyExists }; + + public Mid0554() : this(DEFAULT_REVISION) { } + + public Mid0554(Header header) : base(header) { } + + public Mid0554(int revision) : this(new Header() { Mid = MID, Revision = revision }) { } + } +} diff --git a/src/OpenProtocolInterpreter/RexrothJob/Mid0555.cs b/src/OpenProtocolInterpreter/RexrothJob/Mid0555.cs new file mode 100644 index 0000000..dee3333 --- /dev/null +++ b/src/OpenProtocolInterpreter/RexrothJob/Mid0555.cs @@ -0,0 +1,61 @@ +using System.Collections.Generic; + +namespace OpenProtocolInterpreter.RexrothJob +{ + /// + /// Rexroth job result data upload + /// + /// The controller reports a job result including the job result number and result value. + /// + /// Message sent by: Controller + /// Answer: Rexroth job result acknowledge + /// + public class Mid0555 : Mid, IRexrothJob, IController, IAcknowledgeable + { + public const int MID = 555; + + /// + /// Job result number (3 digits, 000-999). + /// + public int JobResultNumber + { + get => GetField(1, DataFields.JobResultNumber).GetValue(OpenProtocolConvert.ToInt32); + set => GetField(1, DataFields.JobResultNumber).SetValue(OpenProtocolConvert.ToString, value); + } + + /// + /// Job result value (single digit). + /// + public int JobResultValue + { + get => GetField(1, DataFields.JobResultValue).GetValue(OpenProtocolConvert.ToInt32); + set => GetField(1, DataFields.JobResultValue).SetValue(OpenProtocolConvert.ToString, value); + } + + public Mid0555() : this(DEFAULT_REVISION) { } + + public Mid0555(Header header) : base(header) { } + + public Mid0555(int revision) : this(new Header() { Mid = MID, Revision = revision }) { } + + protected override Dictionary> RegisterDatafields() + { + return new Dictionary>() + { + { + 1, new List() + { + DataField.Number(DataFields.JobResultNumber, 20, 3), + DataField.Number(DataFields.JobResultValue, 25, 1) + } + } + }; + } + + protected enum DataFields + { + JobResultNumber, + JobResultValue + } + } +} diff --git a/src/OpenProtocolInterpreter/RexrothJob/Mid0556.cs b/src/OpenProtocolInterpreter/RexrothJob/Mid0556.cs new file mode 100644 index 0000000..05a5588 --- /dev/null +++ b/src/OpenProtocolInterpreter/RexrothJob/Mid0556.cs @@ -0,0 +1,19 @@ +namespace OpenProtocolInterpreter.RexrothJob +{ + /// + /// Rexroth job result acknowledge + /// Acknowledgement of job result upload (). + /// Message sent by: Integrator + /// Answer: None + /// + public class Mid0556 : Mid, IRexrothJob, IIntegrator, IAcknowledge + { + public const int MID = 556; + + public Mid0556() : this(DEFAULT_REVISION) { } + + public Mid0556(Header header) : base(header) { } + + public Mid0556(int revision) : this(new Header() { Mid = MID, Revision = revision }) { } + } +} diff --git a/src/OpenProtocolInterpreter/RexrothJob/Mid0557.cs b/src/OpenProtocolInterpreter/RexrothJob/Mid0557.cs new file mode 100644 index 0000000..097cbc6 --- /dev/null +++ b/src/OpenProtocolInterpreter/RexrothJob/Mid0557.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; + +namespace OpenProtocolInterpreter.RexrothJob +{ + /// + /// Rexroth job result unsubscribe + /// Cancel the subscription for job result notifications. + /// Message sent by: Integrator + /// + /// Answer: Command accepted or + /// Command error + /// + /// + public class Mid0557 : Mid, IRexrothJob, IIntegrator, IUnsubscription, IAcceptableCommand, IDeclinableCommand + { + public const int MID = 557; + + public IEnumerable DocumentedPossibleErrors => new Error[] { Error.SubscriptionDoesntExists }; + + public Mid0557() : this(DEFAULT_REVISION) { } + + public Mid0557(Header header) : base(header) { } + + public Mid0557(int revision) : this(new Header() { Mid = MID, Revision = revision }) { } + } +} diff --git a/src/OpenProtocolInterpreter/RexrothJob/Mid0570.cs b/src/OpenProtocolInterpreter/RexrothJob/Mid0570.cs new file mode 100644 index 0000000..68e2719 --- /dev/null +++ b/src/OpenProtocolInterpreter/RexrothJob/Mid0570.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; + +namespace OpenProtocolInterpreter.RexrothJob +{ + /// + /// Activate job + /// + /// Enable or disable the job function of the tightening channel. + /// Requires the JobEnable signal to be applied to the OP module in the PLC assignment table. + /// + /// Message sent by: Integrator + /// + /// Answer: Command accepted or + /// Command error, request timeout or PLC signal not assigned + /// + /// + public class Mid0570 : Mid, IRexrothJob, IIntegrator, IAcceptableCommand, IDeclinableCommand + { + public const int MID = 570; + + public IEnumerable DocumentedPossibleErrors => new Error[] { Error.ControllerInternalRequestTimeout }; + + /// + /// Job Deactivated = false (0) + /// Job Activated = true (1) + /// + public bool JobStatus + { + get => GetField(1, DataFields.JobStatus).GetValue(OpenProtocolConvert.ToBoolean); + set => GetField(1, DataFields.JobStatus).SetValue(OpenProtocolConvert.ToString, value); + } + + public Mid0570() : this(DEFAULT_REVISION) { } + + public Mid0570(Header header) : base(header) { } + + public Mid0570(int revision) : this(new Header() { Mid = MID, Revision = revision }) { } + + protected override Dictionary> RegisterDatafields() + { + return new Dictionary>() + { + { + 1, new List() + { + DataField.Boolean(DataFields.JobStatus, 20) + } + } + }; + } + + protected enum DataFields + { + JobStatus + } + } +} diff --git a/src/OpenProtocolInterpreter/RexrothJob/Mid0571.cs b/src/OpenProtocolInterpreter/RexrothJob/Mid0571.cs new file mode 100644 index 0000000..ac865e1 --- /dev/null +++ b/src/OpenProtocolInterpreter/RexrothJob/Mid0571.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; + +namespace OpenProtocolInterpreter.RexrothJob +{ + /// + /// Start job sequence + /// + /// Start or stop the job function of the tightening channel. + /// Requires the JobStart signal to be applied to the OP module in the PLC assignment table. + /// + /// Message sent by: Integrator + /// + /// Answer: Command accepted or + /// Command error, request timeout or PLC signal not assigned + /// + /// + public class Mid0571 : Mid, IRexrothJob, IIntegrator, IAcceptableCommand, IDeclinableCommand + { + public const int MID = 571; + + public IEnumerable DocumentedPossibleErrors => new Error[] { Error.ControllerInternalRequestTimeout }; + + /// + /// Job Stop = false (0) + /// Job Start = true (1) + /// + public bool JobStart + { + get => GetField(1, DataFields.JobStart).GetValue(OpenProtocolConvert.ToBoolean); + set => GetField(1, DataFields.JobStart).SetValue(OpenProtocolConvert.ToString, value); + } + + public Mid0571() : this(DEFAULT_REVISION) { } + + public Mid0571(Header header) : base(header) { } + + public Mid0571(int revision) : this(new Header() { Mid = MID, Revision = revision }) { } + + protected override Dictionary> RegisterDatafields() + { + return new Dictionary>() + { + { + 1, new List() + { + DataField.Boolean(DataFields.JobStart, 20) + } + } + }; + } + + protected enum DataFields + { + JobStart + } + } +} diff --git a/src/OpenProtocolInterpreter/RexrothJob/Mid0573.cs b/src/OpenProtocolInterpreter/RexrothJob/Mid0573.cs new file mode 100644 index 0000000..4fffb96 --- /dev/null +++ b/src/OpenProtocolInterpreter/RexrothJob/Mid0573.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; + +namespace OpenProtocolInterpreter.RexrothJob +{ + /// + /// Select job number + /// + /// Select a job by its number on the tightening channel. + /// Requires JobEnable, JobStart, and Job0-7 signals to be applied to the OP module. + /// + /// Message sent by: Integrator + /// + /// Answer: Command accepted or + /// Command error, request timeout or PLC signal not assigned + /// + /// + public class Mid0573 : Mid, IRexrothJob, IIntegrator, IAcceptableCommand, IDeclinableCommand + { + public const int MID = 573; + + public IEnumerable DocumentedPossibleErrors => new Error[] { Error.ControllerInternalRequestTimeout }; + + /// + /// Job number to select (000-999). + /// + public int JobNumber + { + get => GetField(1, DataFields.JobNumber).GetValue(OpenProtocolConvert.ToInt32); + set => GetField(1, DataFields.JobNumber).SetValue(OpenProtocolConvert.ToString, value); + } + + public Mid0573() : this(DEFAULT_REVISION) { } + + public Mid0573(Header header) : base(header) { } + + public Mid0573(int revision) : this(new Header() { Mid = MID, Revision = revision }) { } + + protected override Dictionary> RegisterDatafields() + { + return new Dictionary>() + { + { + 1, new List() + { + DataField.Number(DataFields.JobNumber, 20, 3, false) + } + } + }; + } + + protected enum DataFields + { + JobNumber + } + } +} diff --git a/src/OpenProtocolInterpreter/RexrothJob/Mid0574.cs b/src/OpenProtocolInterpreter/RexrothJob/Mid0574.cs new file mode 100644 index 0000000..9d889f4 --- /dev/null +++ b/src/OpenProtocolInterpreter/RexrothJob/Mid0574.cs @@ -0,0 +1,53 @@ +using System.Collections.Generic; + +namespace OpenProtocolInterpreter.RexrothJob +{ + /// + /// Job manipulate (abort/increment/decrement) + /// + /// Manipulate the current job: abort, increment, or decrement. + /// + /// Message sent by: Integrator + /// Answer: None + /// + public class Mid0574 : Mid, IRexrothJob, IIntegrator + { + public const int MID = 574; + + /// + /// Action code: + /// 01 = Abort job + /// 02 = Increment job + /// 03 = Decrement job + /// + public int ActionCode + { + get => GetField(1, DataFields.ActionCode).GetValue(OpenProtocolConvert.ToInt32); + set => GetField(1, DataFields.ActionCode).SetValue(OpenProtocolConvert.ToString, value); + } + + public Mid0574() : this(DEFAULT_REVISION) { } + + public Mid0574(Header header) : base(header) { } + + public Mid0574(int revision) : this(new Header() { Mid = MID, Revision = revision }) { } + + protected override Dictionary> RegisterDatafields() + { + return new Dictionary>() + { + { + 1, new List() + { + DataField.Number(DataFields.ActionCode, 20, 2) + } + } + }; + } + + protected enum DataFields + { + ActionCode + } + } +} diff --git a/src/OpenProtocolInterpreter/RexrothJob/RexrothJobMessages.cs b/src/OpenProtocolInterpreter/RexrothJob/RexrothJobMessages.cs new file mode 100644 index 0000000..9dab907 --- /dev/null +++ b/src/OpenProtocolInterpreter/RexrothJob/RexrothJobMessages.cs @@ -0,0 +1,39 @@ +using OpenProtocolInterpreter.Messages; +using System; +using System.Collections.Generic; + +namespace OpenProtocolInterpreter.RexrothJob +{ + /// + /// Template for implementers. + /// + internal class RexrothJobMessages : MessagesTemplate + { + public RexrothJobMessages() : base() + { + _templates = new Dictionary() + { + { Mid0554.MID, new MidCompiledInstance(typeof(Mid0554)) }, + { Mid0555.MID, new MidCompiledInstance(typeof(Mid0555)) }, + { Mid0556.MID, new MidCompiledInstance(typeof(Mid0556)) }, + { Mid0557.MID, new MidCompiledInstance(typeof(Mid0557)) }, + { Mid0570.MID, new MidCompiledInstance(typeof(Mid0570)) }, + { Mid0571.MID, new MidCompiledInstance(typeof(Mid0571)) }, + { Mid0573.MID, new MidCompiledInstance(typeof(Mid0573)) }, + { Mid0574.MID, new MidCompiledInstance(typeof(Mid0574)) } + }; + } + + public RexrothJobMessages(IEnumerable selectedMids) : this() + { + FilterSelectedMids(selectedMids); + } + + public RexrothJobMessages(InterpreterMode mode) : this() + { + FilterSelectedMids(mode); + } + + public override bool IsAssignableTo(int mid) => (mid > 553 && mid < 558) || (mid > 569 && mid < 575); + } +} diff --git a/src/OpenProtocolInterpreter/SocketTray/ISocketTray.cs b/src/OpenProtocolInterpreter/SocketTray/ISocketTray.cs new file mode 100644 index 0000000..4b92ba3 --- /dev/null +++ b/src/OpenProtocolInterpreter/SocketTray/ISocketTray.cs @@ -0,0 +1,10 @@ +namespace OpenProtocolInterpreter.SocketTray +{ + /// + /// Socket Tray message category. Every socket tray mid must implement . + /// Rexroth/NEXO vendor extension for socket chamber/tray management. + /// + public interface ISocketTray + { + } +} diff --git a/src/OpenProtocolInterpreter/SocketTray/Mid0520.cs b/src/OpenProtocolInterpreter/SocketTray/Mid0520.cs new file mode 100644 index 0000000..b8387fe --- /dev/null +++ b/src/OpenProtocolInterpreter/SocketTray/Mid0520.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; + +namespace OpenProtocolInterpreter.SocketTray +{ + /// + /// Socket tray change subscribe + /// + /// Subscribe to socket tray/chamber change notifications. + /// After subscription, the controller sends socket tray state changes. + /// + /// Message sent by: Integrator + /// + /// Answer: Command accepted or + /// Command error + /// + /// + public class Mid0520 : Mid, ISocketTray, IIntegrator, ISubscription, IAcceptableCommand, IDeclinableCommand + { + public const int MID = 520; + + public IEnumerable DocumentedPossibleErrors => new Error[] { Error.SubscriptionAlreadyExists }; + + public Mid0520() : this(DEFAULT_REVISION) { } + + public Mid0520(Header header) : base(header) { } + + public Mid0520(int revision) : this(new Header() { Mid = MID, Revision = revision }) { } + } +} diff --git a/src/OpenProtocolInterpreter/SocketTray/Mid0522.cs b/src/OpenProtocolInterpreter/SocketTray/Mid0522.cs new file mode 100644 index 0000000..db1cc15 --- /dev/null +++ b/src/OpenProtocolInterpreter/SocketTray/Mid0522.cs @@ -0,0 +1,19 @@ +namespace OpenProtocolInterpreter.SocketTray +{ + /// + /// Socket tray change acknowledge + /// Acknowledgement of socket tray change upload. + /// Message sent by: Integrator + /// Answer: None + /// + public class Mid0522 : Mid, ISocketTray, IIntegrator, IAcknowledge + { + public const int MID = 522; + + public Mid0522() : this(DEFAULT_REVISION) { } + + public Mid0522(Header header) : base(header) { } + + public Mid0522(int revision) : this(new Header() { Mid = MID, Revision = revision }) { } + } +} diff --git a/src/OpenProtocolInterpreter/SocketTray/Mid0523.cs b/src/OpenProtocolInterpreter/SocketTray/Mid0523.cs new file mode 100644 index 0000000..db5afc8 --- /dev/null +++ b/src/OpenProtocolInterpreter/SocketTray/Mid0523.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; + +namespace OpenProtocolInterpreter.SocketTray +{ + /// + /// Socket tray change unsubscribe + /// Cancel the subscription for socket tray change notifications. + /// Message sent by: Integrator + /// + /// Answer: Command accepted or + /// Command error + /// + /// + public class Mid0523 : Mid, ISocketTray, IIntegrator, IUnsubscription, IAcceptableCommand, IDeclinableCommand + { + public const int MID = 523; + + public IEnumerable DocumentedPossibleErrors => new Error[] { Error.SubscriptionDoesntExists }; + + public Mid0523() : this(DEFAULT_REVISION) { } + + public Mid0523(Header header) : base(header) { } + + public Mid0523(int revision) : this(new Header() { Mid = MID, Revision = revision }) { } + } +} diff --git a/src/OpenProtocolInterpreter/SocketTray/Mid0524.cs b/src/OpenProtocolInterpreter/SocketTray/Mid0524.cs new file mode 100644 index 0000000..a9face9 --- /dev/null +++ b/src/OpenProtocolInterpreter/SocketTray/Mid0524.cs @@ -0,0 +1,104 @@ +using System.Collections.Generic; + +namespace OpenProtocolInterpreter.SocketTray +{ + /// + /// Socket tray selection + /// + /// Send socket position selections to the controller. + /// Each of the 8 socket positions is represented by a single digit value. + /// + /// Message sent by: Integrator + /// Answer: None + /// + public class Mid0524 : Mid, ISocketTray, IIntegrator + { + public const int MID = 524; + + public int Socket1 + { + get => GetField(1, DataFields.Socket1).GetValue(OpenProtocolConvert.ToInt32); + set => GetField(1, DataFields.Socket1).SetValue(OpenProtocolConvert.ToString, value); + } + + public int Socket2 + { + get => GetField(1, DataFields.Socket2).GetValue(OpenProtocolConvert.ToInt32); + set => GetField(1, DataFields.Socket2).SetValue(OpenProtocolConvert.ToString, value); + } + + public int Socket3 + { + get => GetField(1, DataFields.Socket3).GetValue(OpenProtocolConvert.ToInt32); + set => GetField(1, DataFields.Socket3).SetValue(OpenProtocolConvert.ToString, value); + } + + public int Socket4 + { + get => GetField(1, DataFields.Socket4).GetValue(OpenProtocolConvert.ToInt32); + set => GetField(1, DataFields.Socket4).SetValue(OpenProtocolConvert.ToString, value); + } + + public int Socket5 + { + get => GetField(1, DataFields.Socket5).GetValue(OpenProtocolConvert.ToInt32); + set => GetField(1, DataFields.Socket5).SetValue(OpenProtocolConvert.ToString, value); + } + + public int Socket6 + { + get => GetField(1, DataFields.Socket6).GetValue(OpenProtocolConvert.ToInt32); + set => GetField(1, DataFields.Socket6).SetValue(OpenProtocolConvert.ToString, value); + } + + public int Socket7 + { + get => GetField(1, DataFields.Socket7).GetValue(OpenProtocolConvert.ToInt32); + set => GetField(1, DataFields.Socket7).SetValue(OpenProtocolConvert.ToString, value); + } + + public int Socket8 + { + get => GetField(1, DataFields.Socket8).GetValue(OpenProtocolConvert.ToInt32); + set => GetField(1, DataFields.Socket8).SetValue(OpenProtocolConvert.ToString, value); + } + + public Mid0524() : this(DEFAULT_REVISION) { } + + public Mid0524(Header header) : base(header) { } + + public Mid0524(int revision) : this(new Header() { Mid = MID, Revision = revision }) { } + + protected override Dictionary> RegisterDatafields() + { + return new Dictionary>() + { + { + 1, new List() + { + DataField.Number(DataFields.Socket1, 20, 1), + DataField.Number(DataFields.Socket2, 23, 1), + DataField.Number(DataFields.Socket3, 26, 1), + DataField.Number(DataFields.Socket4, 29, 1), + DataField.Number(DataFields.Socket5, 32, 1), + DataField.Number(DataFields.Socket6, 35, 1), + DataField.Number(DataFields.Socket7, 38, 1), + DataField.Number(DataFields.Socket8, 41, 1) + } + } + }; + } + + protected enum DataFields + { + Socket1, + Socket2, + Socket3, + Socket4, + Socket5, + Socket6, + Socket7, + Socket8 + } + } +} diff --git a/src/OpenProtocolInterpreter/SocketTray/SocketTrayMessages.cs b/src/OpenProtocolInterpreter/SocketTray/SocketTrayMessages.cs new file mode 100644 index 0000000..5dbb97d --- /dev/null +++ b/src/OpenProtocolInterpreter/SocketTray/SocketTrayMessages.cs @@ -0,0 +1,35 @@ +using OpenProtocolInterpreter.Messages; +using System; +using System.Collections.Generic; + +namespace OpenProtocolInterpreter.SocketTray +{ + /// + /// Template for implementers. + /// + internal class SocketTrayMessages : MessagesTemplate + { + public SocketTrayMessages() : base() + { + _templates = new Dictionary() + { + { Mid0520.MID, new MidCompiledInstance(typeof(Mid0520)) }, + { Mid0522.MID, new MidCompiledInstance(typeof(Mid0522)) }, + { Mid0523.MID, new MidCompiledInstance(typeof(Mid0523)) }, + { Mid0524.MID, new MidCompiledInstance(typeof(Mid0524)) } + }; + } + + public SocketTrayMessages(IEnumerable selectedMids) : this() + { + FilterSelectedMids(selectedMids); + } + + public SocketTrayMessages(InterpreterMode mode) : this() + { + FilterSelectedMids(mode); + } + + public override bool IsAssignableTo(int mid) => mid > 519 && mid < 525; + } +} diff --git a/src/OpenProtocolInterpreter/Wifi/IWifi.cs b/src/OpenProtocolInterpreter/Wifi/IWifi.cs new file mode 100644 index 0000000..02e8529 --- /dev/null +++ b/src/OpenProtocolInterpreter/Wifi/IWifi.cs @@ -0,0 +1,10 @@ +namespace OpenProtocolInterpreter.Wifi +{ + /// + /// WiFi/Reception Quality message category. Every WiFi mid must implement . + /// Rexroth/NEXO vendor extension for wireless reception quality monitoring (FW ≥1100). + /// + public interface IWifi + { + } +} diff --git a/src/OpenProtocolInterpreter/Wifi/Mid0805.cs b/src/OpenProtocolInterpreter/Wifi/Mid0805.cs new file mode 100644 index 0000000..6a2a369 --- /dev/null +++ b/src/OpenProtocolInterpreter/Wifi/Mid0805.cs @@ -0,0 +1,19 @@ +namespace OpenProtocolInterpreter.Wifi +{ + /// + /// Reception quality request + /// Request the current WiFi reception quality from the controller. + /// Message sent by: Integrator + /// Answer: Reception quality response + /// + public class Mid0805 : Mid, IWifi, IIntegrator, IAnswerableBy + { + public const int MID = 805; + + public Mid0805() : this(DEFAULT_REVISION) { } + + public Mid0805(Header header) : base(header) { } + + public Mid0805(int revision) : this(new Header() { Mid = MID, Revision = revision }) { } + } +} diff --git a/src/OpenProtocolInterpreter/Wifi/Mid0806.cs b/src/OpenProtocolInterpreter/Wifi/Mid0806.cs new file mode 100644 index 0000000..e2f1abd --- /dev/null +++ b/src/OpenProtocolInterpreter/Wifi/Mid0806.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; + +namespace OpenProtocolInterpreter.Wifi +{ + /// + /// Reception quality response + /// + /// The controller transmits the current WiFi reception quality in dBm. + /// + /// Message sent by: Controller + /// Answer: None + /// + public class Mid0806 : Mid, IWifi, IController + { + public const int MID = 806; + + /// + /// Reception quality in dBm (typically -45 to -90), transmitted as 4 ASCII characters (e.g. "-080"). + /// + public string ReceptionQuality + { + get => GetField(1, DataFields.ReceptionQuality).Value; + set => GetField(1, DataFields.ReceptionQuality).SetValue(value); + } + + public Mid0806() : this(DEFAULT_REVISION) { } + + public Mid0806(Header header) : base(header) { } + + public Mid0806(int revision) : this(new Header() { Mid = MID, Revision = revision }) { } + + protected override Dictionary> RegisterDatafields() + { + return new Dictionary>() + { + { + 1, new List() + { + DataField.String(DataFields.ReceptionQuality, 20, 4) + } + } + }; + } + + protected enum DataFields + { + ReceptionQuality + } + } +} diff --git a/src/OpenProtocolInterpreter/Wifi/Mid0807.cs b/src/OpenProtocolInterpreter/Wifi/Mid0807.cs new file mode 100644 index 0000000..bfe0c56 --- /dev/null +++ b/src/OpenProtocolInterpreter/Wifi/Mid0807.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; + +namespace OpenProtocolInterpreter.Wifi +{ + /// + /// Reception quality change subscribe + /// + /// Subscribe to reception quality change notifications. After subscription, the controller + /// sends when the reception quality changes by the specified threshold. + /// + /// Message sent by: Integrator + /// + /// Answer: Command accepted or + /// Command error, subscription already exists + /// + /// + public class Mid0807 : Mid, IWifi, IIntegrator, ISubscription, IAcceptableCommand, IDeclinableCommand + { + public const int MID = 807; + + public IEnumerable DocumentedPossibleErrors => new Error[] { Error.SubscriptionAlreadyExists }; + + /// + /// Change threshold in dBm (00-99). When the quality changes by this amount, a notification is sent. + /// + public int ChangeLevel + { + get => GetField(1, DataFields.ChangeLevel).GetValue(OpenProtocolConvert.ToInt32); + set => GetField(1, DataFields.ChangeLevel).SetValue(OpenProtocolConvert.ToString, value); + } + + public Mid0807() : this(DEFAULT_REVISION) { } + + public Mid0807(Header header) : base(header) { } + + public Mid0807(int revision) : this(new Header() { Mid = MID, Revision = revision }) { } + + protected override Dictionary> RegisterDatafields() + { + return new Dictionary>() + { + { + 1, new List() + { + DataField.Number(DataFields.ChangeLevel, 20, 2, false) + } + } + }; + } + + protected enum DataFields + { + ChangeLevel + } + } +} diff --git a/src/OpenProtocolInterpreter/Wifi/Mid0808.cs b/src/OpenProtocolInterpreter/Wifi/Mid0808.cs new file mode 100644 index 0000000..9e018c5 --- /dev/null +++ b/src/OpenProtocolInterpreter/Wifi/Mid0808.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; + +namespace OpenProtocolInterpreter.Wifi +{ + /// + /// Reception quality change upload + /// + /// The controller reports the current WiFi reception quality when it changes. + /// Same data format as . + /// + /// Message sent by: Controller + /// Answer: None + /// + public class Mid0808 : Mid, IWifi, IController + { + public const int MID = 808; + + /// + /// Reception quality in dBm (typically -45 to -90), transmitted as 4 ASCII characters (e.g. "-080"). + /// + public string ReceptionQuality + { + get => GetField(1, DataFields.ReceptionQuality).Value; + set => GetField(1, DataFields.ReceptionQuality).SetValue(value); + } + + public Mid0808() : this(DEFAULT_REVISION) { } + + public Mid0808(Header header) : base(header) { } + + public Mid0808(int revision) : this(new Header() { Mid = MID, Revision = revision }) { } + + protected override Dictionary> RegisterDatafields() + { + return new Dictionary>() + { + { + 1, new List() + { + DataField.String(DataFields.ReceptionQuality, 20, 4) + } + } + }; + } + + protected enum DataFields + { + ReceptionQuality + } + } +} diff --git a/src/OpenProtocolInterpreter/Wifi/Mid0809.cs b/src/OpenProtocolInterpreter/Wifi/Mid0809.cs new file mode 100644 index 0000000..c762058 --- /dev/null +++ b/src/OpenProtocolInterpreter/Wifi/Mid0809.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; + +namespace OpenProtocolInterpreter.Wifi +{ + /// + /// Cancel reception quality change subscription + /// Cancel the subscription for reception quality change notifications. + /// Message sent by: Integrator + /// + /// Answer: Command accepted or + /// Command error, subscription does not exist + /// + /// + public class Mid0809 : Mid, IWifi, IIntegrator, IUnsubscription, IAcceptableCommand, IDeclinableCommand + { + public const int MID = 809; + + public IEnumerable DocumentedPossibleErrors => new Error[] { Error.SubscriptionDoesntExists }; + + public Mid0809() : this(DEFAULT_REVISION) { } + + public Mid0809(Header header) : base(header) { } + + public Mid0809(int revision) : this(new Header() { Mid = MID, Revision = revision }) { } + } +} diff --git a/src/OpenProtocolInterpreter/Wifi/WifiMessages.cs b/src/OpenProtocolInterpreter/Wifi/WifiMessages.cs new file mode 100644 index 0000000..d18e913 --- /dev/null +++ b/src/OpenProtocolInterpreter/Wifi/WifiMessages.cs @@ -0,0 +1,36 @@ +using OpenProtocolInterpreter.Messages; +using System; +using System.Collections.Generic; + +namespace OpenProtocolInterpreter.Wifi +{ + /// + /// Template for implementers. + /// + internal class WifiMessages : MessagesTemplate + { + public WifiMessages() : base() + { + _templates = new Dictionary() + { + { Mid0805.MID, new MidCompiledInstance(typeof(Mid0805)) }, + { Mid0806.MID, new MidCompiledInstance(typeof(Mid0806)) }, + { Mid0807.MID, new MidCompiledInstance(typeof(Mid0807)) }, + { Mid0808.MID, new MidCompiledInstance(typeof(Mid0808)) }, + { Mid0809.MID, new MidCompiledInstance(typeof(Mid0809)) } + }; + } + + public WifiMessages(IEnumerable selectedMids) : this() + { + FilterSelectedMids(selectedMids); + } + + public WifiMessages(InterpreterMode mode) : this() + { + FilterSelectedMids(mode); + } + + public override bool IsAssignableTo(int mid) => mid > 804 && mid < 810; + } +}