diff --git a/.claude/skills/class-object-engineering/SKILL.md b/.claude/skills/class-object-engineering/SKILL.md index 53826cd..98b44ff 100644 --- a/.claude/skills/class-object-engineering/SKILL.md +++ b/.claude/skills/class-object-engineering/SKILL.md @@ -1,20 +1,38 @@ --- name: class-object-engineering description: >- - CI Server R1.03 PROCESS Service classes, objects and trigger groups. Use when the user wants - to create a trigger group, write or compile a class (traditional language), create objects - from a class, or load classes and objects with quick load files. Sources IM 36K10G10-01EN - (Tutorial) and IM 36K10J10-01EN; to be extended with IM 36K10L10, P10 and P11 in phase 6. + CI Server R1.03 PROCESS Service: trigger groups, classes and objects. Use when the user wants + to create a trigger group, write, compile or change a class (Traditional PROCESS language or + Java), use signals, attributes, prompts, timers or template items in a class, create objects + from a class (with prompt answers), let an object create its own items, reset a class after a + change, read or change object attribute values, see which item a signal uses, load or remove + classes and objects with quick load files, or check PROCESS Service with opcdbg (database + check, object status, executor statistics). Sources IM 36K10L10-01EN, IM 36K10P10-01EN, + IM 36K10P11-01EN, IM 36K10G10-01EN (Tutorial). --- # Class and object engineering (R1.03) -Background: `knowledge/manuals/IM36K10G10-01EN.md` (chapter 5) and -`knowledge/manuals/IM36K10J10-01EN.md` (sections 2.4 and 5.3). Known issues for PROCESS -Service: `knowledge/manuals/IM36K01A50-01EN.md`. +Background: `knowledge/manuals/IM36K10L10-01EN.md` (processes, `opc.sup`, `opcdbg`, data +store), `IM36K10P10-01EN.md` (Traditional language), `IM36K10P11-01EN.md` (Java), +`IM36K10G10-01EN.md` chapter 5 (Tutorial). Known issues for PROCESS Service: +`knowledge/manuals/IM36K01A50-01EN.md` (PROCESS 1.10). -Rules: run `system-check` first; creating classes and objects changes the running system. +Rules: +- Run `system-check` first; follow the user's chosen way of working. +- Creating, changing or resetting classes and objects changes the running system; objects can + write to items (and through them to devices). Test on a test system or with the user's + approval. +- Deleting an object deletes the items it created (and their history links). +- `opcdbg`: read-only actions only, unless the user approves (task `opcdbg-checks.md`). | Task | File | Status | |---|---|---| -| Trigger group, class (compiled on load) and object via quick load | `tasks/load-class-object.md` | verified | +| Trigger group, class (compiled on load) and object via quick load; compile errors; remove | `tasks/load-class-object.md` | verified | +| Traditional class with prompts/attributes, signals from the object's section, items created from a template, input check; change an attribute at runtime | `tasks/traditional-class.md` | verified | +| Java class: attach and create items, signal trigger, system log message | `tasks/java-class.md` | verified | +| Change a class that has objects: compile, reset with `opcdbg` | `tasks/change-reset-class.md` | verified (`dssqld` reset does not work, ISS-028) | +| `opcdbg` checks: database check, class/object details, object status, executor statistics, dumps | `tasks/opcdbg-checks.md` | verified | +| Language reference (statements, operators, built-ins, DSS routines; Java API) | P10 / P11 summaries | from docs, main parts verified | +| `opc.sup` settings (executors, priorities, statistics, PRINT) | L10 summary §2 | read-only check; changing not practiced | +| Containment, inheritance, timers, alarms, STEP state machines, DSS routines | P10 / P11 summaries | from docs | diff --git a/.claude/skills/class-object-engineering/tasks/change-reset-class.md b/.claude/skills/class-object-engineering/tasks/change-reset-class.md new file mode 100644 index 0000000..a9fbfc5 --- /dev/null +++ b/.claude/skills/class-object-engineering/tasks/change-reset-class.md @@ -0,0 +1,64 @@ +--- +task: Change a class that already has objects (compile and reset) +version: R1.03 +source: IM 36K10L10-01EN §4 (Reset class); IM 36K10P11-01EN §2.3, §10.4; practiced with CI-Eng-Sample class CIENG_TANK 2026-09-30 +status: verified +--- + +# Change a class that has objects + +Objects keep running the **old** compiled code until their class is reset (verified). A reset +restarts every object of the class; by the manual, `ONCE` trigger groups fire again. Items the +objects created were kept, with their values (verified). + +## 1. New source and compile + +`dssqld -m` with the class name, `COMPILE` 1 and the new `METHOD`: + +``` +@FIELDS +NAME,COMPILE,METHOD + +@CLASS_DF +"CIENG_TANK",1,@" +CLASS CIENG_TANK; + … +ENDCLASS CIENG_TANK; +"@ +``` + +`Errors` 0 = compiled. On a compile error the old code stays; see `load-class-object.md` for +reading the error listing. + +Export the class (`load-class-object.md` §2): after the compile `RESET_REQUIRED` = 1 and +`OBJECTS_RESET` = 0 of `OBJECTS` n. Verified: the object still printed the old text. + +## 2. Reset the class + +**Works** — `opcdbg`, Classes, action 8 *Reset class*: class name, node (0 = this node), file +for a reset report (empty = none; this prompt is not in the manual): + +``` +printf '2\n8\n\n0\n\n-1\n-1\n' | timeout 30 opcdbg 0 +``` +(Bash. Interactively, type the same answers.) Keep the time-out: `opcdbg` repeats its last +prompt forever when the input runs out. + +Afterwards `RESET_REQUIRED` = 0 and the object used the new code at once (verified). + +The Engineering Module also resets classes (class properties); not practiced. + +**Does not work** (verified 2026-09-30, ISS-028): +- `dssqld -m` with `NAME,RESET` = `"",1` (also with `RESET_NODE` = the host node name): + accepted with 0 errors but nothing happens. +- `dssqld -m` on `OBJECT_DF` with `RESET` 1: refused with `OPC-E-OBJ_RSTREQ, The class needs to + be reset first`. +- `CLASS_RESET_COMMAND` (system-wide reset used by the Engineering Module) was not tried. + +## 3. Changing prompts or signals + +Only a change in the method bodies was practiced. When the class **prolog** changes (new +signals, prompts, attributes, created items), check `EXTENDED_RESET_REQUIRED` in `CLASS_DF` +after compiling; what an extended reset does was not tested. The safe way is to recreate the +objects (remove, load) — note that removing an object deletes the items it created, with their +history links. diff --git a/.claude/skills/class-object-engineering/tasks/java-class.md b/.claude/skills/class-object-engineering/tasks/java-class.md new file mode 100644 index 0000000..a6e533f --- /dev/null +++ b/.claude/skills/class-object-engineering/tasks/java-class.md @@ -0,0 +1,87 @@ +--- +task: Write and load a Java PROCESS Service class +version: R1.03 +source: IM 36K10P11-01EN §1–§5, §10; IM 36K10L10-01EN §1; practiced with CI-Eng-Sample class CIENG_JFLOW 2026-09-30 +status: verified +--- + +# Java class + +Worked example: class `CIENG_JFLOW`, object `CI-Eng-Sample.TANK1.JFLOW` +(`examples/CI-Eng-Sample/06_class_df.qli`, `07_object_df.qli`). Language reference: +`knowledge/manuals/IM36K10P11-01EN.md`. Loading and removing: `load-class-object.md`. + +Choose Java when you need loops, arrays of signals, inheritance, libraries, or signals that may +stay unattached; otherwise the Traditional language is simpler. + +## 1. Class record + +Same as a Traditional class but `PF_LANGUAGE` = `"Java"` (cannot be changed later) and Java +source in `METHOD`. The Java class name must equal the `CLASS_DF` name exactly. + +``` +@FIELDS +NAME,DESCRIPTION,PF_LANGUAGE,TRIGGER_1,COMPILE,LISTING_WANTED,METHOD + +@CLASS_DF +"CIENG_JFLOW","Inflow per minute (Java)","Java","",1,0,@" +import fasttools.processfast.*; + +public class CIENG_JFLOW extends ProcessClass { + + Signal sInflow = defineDoubleSignal(Signal.Trigger.VALUE); + Signal sPerMin = defineDoubleSignal(); + + public void create() { + attachItemToSignal(sInflow, getSectionsPath() + ".INFLOW"); + createItemForSignal(sPerMin, "CI-Eng-Sample.TEMPLATES.TPL_REAL", + "DESCRIPTION", "Tank inflow (m3/min), class CIENG_JFLOW"); + } + + public void signalEvent(Signal signal) { + double mInflow = sInflow.getValueAsDouble(); + sPerMin.setValue(mInflow / 60.0); + systemMessage("CIENG_JFLOW " + getTag() + ": inflow " + mInflow); + } +} +"@ +``` + +`OPCMAN` starts the Java compiler `OPCJCOM` on demand; allow ~15 s, then export the class and +check `VALID_METHOD` = 1 (as in `load-class-object.md`). + +## 2. Object + +``` +@FIELDS +NAME,DESCRIPTION,CLASS + +@OBJECT_DF +"CI-Eng-Sample.TANK1.JFLOW","Tank 1 inflow per minute (Java)","CIENG_JFLOW" +``` + +Prompts: `Attribute aX = defineStringAttributeForPrompt("…");` → answer in `ATTR_VALUE_n`; +refuse bad answers with `cancel("text")` in `create()`. + +## 3. Results on the test system + +- Signals: `sInflow` → `CI-Eng-Sample.TANK1.INFLOW`; `sPerMin` → created item + **`CI-Eng-Sample.TANK1.JFLOW.sPerMin`** — automatic names keep the identifier's case, and + `itmval` needs that exact case (`…SPERMIN` is not found). Give a `"NAME"` if you want + upper-case item names. +- `INFLOW` 120 → `sPerMin` 2; 90 → 1.5. +- `systemMessage()` appears in `umhlog.log` from `OPCJEXE` as + `UMH-I-INFO, (: )`. +- The first object ran without resetting the new class, although the manual asks for a reset + (ISS-029). After changing a Java class that has objects, compile **and reset** it + (`change-reset-class.md`). +- Deleting the object deleted `…JFLOW.sPerMin` and section `…TANK1.JFLOW`; `INFLOW` stayed. + +## 4. Pitfalls (manual) + +- Definitions (`define…()`) only at class level, without `public`/`private`. +- `create()`/`destroy()` run in a different process than the trigger methods: only attributes + keep values between them; no timers or signal values in `create()`. +- Never sleep or loop long in a trigger method: it blocks all objects of the same priority. +- No anonymous listener classes (fail at object start with `NoClassDefFoundError`). +- Dataset access: get the session with `getDssSession()` and never close it (release notes). diff --git a/.claude/skills/class-object-engineering/tasks/load-class-object.md b/.claude/skills/class-object-engineering/tasks/load-class-object.md index 9aca5ba..7ab7527 100644 --- a/.claude/skills/class-object-engineering/tasks/load-class-object.md +++ b/.claude/skills/class-object-engineering/tasks/load-class-object.md @@ -1,16 +1,18 @@ --- -task: Create a trigger group, class and object with quick load files +task: Create trigger groups, classes and objects with quick load files version: R1.03 -source: IM 36K10G10-01EN §5.1–5.3; IM 36K10J10-01EN §5.6; practiced with CI-Eng-Sample 2026-09-30 +source: IM 36K10G10-01EN §5.1–5.3; IM 36K10L10-01EN §3; IM 36K10J10-01EN §5.6; practiced with CI-Eng-Sample 2026-09-30 (full remove/reload with three classes and objects) status: verified --- -# Trigger group, class and object via quick load +# Trigger groups, classes and objects via quick load -Load in this order (each with `dssqld -i .qli -l .qlo`, check `Errors` = 0); -remove in reverse (object, class, trigger group) with `NAME`-only files and `dssqld -r`. +Load in this order, each with `dssqld -i .qli -l .qlo` and check `Errors` = 0: +items the classes need (template items, attached items) → trigger groups → classes → objects. +Remove in reverse (objects, classes, trigger groups) with `NAME`-only files and `dssqld -r`. +Run `dssqld` from the folder that holds the files and use short relative names (ISS-020). -**1. Trigger group** (`TRIGGER_DF`, name max 16 characters): +## 1. Trigger group (`TRIGGER_DF`, name max 16 characters) ``` @FIELDS @@ -20,17 +22,23 @@ NAME,DESCRIPTION,TRIGGER_INTERVAL "CIENG_1S","CI-Eng-Sample one second trigger","1 seconds" ``` -**2. Class** (`CLASS_DF`, name max 16 characters). The source goes in the `METHOD` memo field, -between `@"` and `"@` on their own lines; `COMPILE` 1 compiles it on load; `TRIGGER_1` -attaches a trigger group: +Other fields: `ACTIVATION_TIME`, `DEACTIVATION_TIME`, `TRIGGER_ONCE` (1 = run once when an +object is activated), `CORRECT_DAYLIGHT`. A class or object without a trigger group only runs +on signal triggers, timers and `TRIGGER` statements. + +## 2. Class (`CLASS_DF`, name max 16 characters; the language allows 15) + +The source goes in the `METHOD` memo field between `@"` and `"@` on their own lines. +`COMPILE` 1 compiles it on load; `PF_LANGUAGE` is `Traditional` (default) or `Java` and cannot +be changed later; `TRIGGER_1`…`TRIGGER_8` attach trigger groups; `PRIORITY` 0–999 picks the +executor (installed: `OPCEXE1` 0–249 … `OPCEXE4` 750–999). ``` @FIELDS NAME,DESCRIPTION,PF_LANGUAGE,TRIGGER_1,COMPILE,LISTING_WANTED,METHOD @CLASS_DF -"CIENG_INCR","Count CI-Eng-Sample.DEMO.COUNTER 1..100","Traditional","CIENG_1S",1,1,\ -@" +"CIENG_INCR","Count CI-Eng-Sample.DEMO.COUNTER 1..100","Traditional","CIENG_1S",1,1,@" CLASS CIENG_INCR; PROLOG SIGNAL INPUT := "CI-Eng-Sample.DEMO.COUNTER"; @@ -46,23 +54,70 @@ ENDCLASS CIENG_INCR; "@ ``` -The item a `SIGNAL` names must exist first (or be created by the class with `FROM … MAKE`). +Several classes (also mixed languages) can share one file and one `@FIELDS` line; leave unused +fields as `""`. See `examples/CI-Eng-Sample/06_class_df.qli`. -**3. Object** (`OBJECT_DF`): full name in its section, and the class: +**Check the compile**: export the class with a filter file and read the flags after the source: +`VALID_METHOD` = 1 means compiled; `ATTR_PROMPT_n` shows the class's prompts; +`RESET_REQUIRED`, `OBJECTS`, `OBJECTS_RESET` matter when changing a class (`change-reset-class.md`). + +``` +@SELECT +'NAME = "CIENG_TANK"' +@CLASS_DF +``` +`dssqld -e cls.qli filter.qli -l cls.lst` + +**Compile errors** (verified, Traditional): with `COMPILE` 1 on insert, a class that does not +compile is **not inserted at all** — the `.qlo` only says `DSI-E-OPCCOMERR, Compilation failed +with n error(s)`. To see the errors, insert the class with `COMPILE` 0, then update it with +`dssqld -m` and `NAME,COMPILE,LISTING_WANTED` = `"",1,1`: the update fails the same way +but the class's `LISTING` field (export as above) now shows the numbered source with +`**** ERROR: …` after the faulty line. Fix the `METHOD` field and compile again. +Class language: `traditional-class.md` and `java-class.md`. + +## 3. Object (`OBJECT_DF`) + +Full name (its section must exist), class, and `ATTR_VALUE_n` = answer to the class's n-th +prompt: ``` @FIELDS -NAME,DESCRIPTION,CLASS +NAME,DESCRIPTION,CLASS,ATTR_VALUE_1 @OBJECT_DF -"CI-Eng-Sample.DEMO.INCR1","Counts DEMO.COUNTER every second","CIENG_INCR" +"CI-Eng-Sample.DEMO.INCR1","Counts DEMO.COUNTER every second","CIENG_INCR","" +"CI-Eng-Sample.TANK1.CALC","Tank 1 volume (capacity 200 m3)","CIENG_TANK","200" ``` +Other fields: `TRIGGER_1`…`8` (object's own trigger groups), `PRIORITY`, `CONTROL_ITEM` +(item whose status blocks/stops the object and whose value is `STEP`), `ITEMS_MAY_EXIST` +(allow linking to items that already exist instead of creating them), `LEAVE_ITEMS` (keep +created items when the object is deleted), `DEBUG`. + +The item a plain `SIGNAL` names must exist. If the class refuses the object (`ERROR` in the +prolog, Java `cancel()`, missing item) the row counts as an error and the `.qlo` shows the +reason (e.g. `OPC-E-INFO, `); nothing is left behind. + ## Check -Run `itmval -g -n CI-Eng-Sample.DEMO.COUNTER` a few seconds apart: the value rises by one per -second. To inspect a class, export it with a filter file (`@SELECT`, then -`'NAME = ""'`, then `@CLASS_DF`). +- Items the object writes: `itmval -g -n ` a few seconds apart (sample: `DEMO.COUNTER` + rises by one per second). +- Which item each signal got: export `OBJECT_SIGNAL_DF` with filter + `'OBJECT = ""'`; attribute values: `OBJECT_ATTR_VAL` (same filter). +- Run state: `opcdbg` (task `opcdbg-checks.md`). -Example files: `examples/CI-Eng-Sample/05_trigger_df.qli`, `06_class_df.qli`, `07_object_df.qli`, -`86_` to `88_remove_*.qli`. +## Remove + +``` +@FIELDS +NAME + +@OBJECT_DF +"CI-Eng-Sample.TANK1.CALC" +``` +Then `CLASS_DF`, then `TRIGGER_DF`. Deleting an object also deletes the items and sections it +created (verified); items it only attached stay. + +Example files: `examples/CI-Eng-Sample/05_trigger_df.qli`, `06_class_df.qli`, +`07_object_df.qli`, `86_` to `88_remove_*.qli`. diff --git a/.claude/skills/class-object-engineering/tasks/opcdbg-checks.md b/.claude/skills/class-object-engineering/tasks/opcdbg-checks.md new file mode 100644 index 0000000..00ffa84 --- /dev/null +++ b/.claude/skills/class-object-engineering/tasks/opcdbg-checks.md @@ -0,0 +1,47 @@ +--- +task: Check PROCESS Service with opcdbg (database check, classes, objects, performance) +version: R1.03 +source: IM 36K10L10-01EN §4; practiced on the test system with CI-Eng-Sample 2026-09-30 +status: verified (read-only actions and Reset class) +--- + +# PROCESS Service checks with `opcdbg` + +`opcdbg` is interactive. Answers can be piped in, one per line, in Bash; always add a time-out +and end with `-1` lines, because on end of input it repeats the last prompt forever. `opcdbg 0 +` starts in a menu on node 0 (this node). Times are printed in **GMT**. + +Only the actions below are read-only. Do not use insert/modify/delete, *Database repair*, +*Reset* (utilities) or *Modify attribute value* without the user's approval. + +| Check | Command (Bash) | Output | +|---|---|---| +| Database consistency | `printf '5\n-1\n-1\n' \| timeout 60 opcdbg 0 5` | Counts per store (trigger groups, classes, sources, code, objects, signals, attributes), then checks; warnings such as `No compiled code found for class (cls_id = …)` | +| Class details | `printf '2\n5\nN\n\n-1\n-1\n' \| timeout 20 opcdbg 0` | Language, priority, modified/compiled times, cls_id, objects derived / reset, hidden | +| Class by id (from a warning) | `printf '2\n5\nI\n\n\n-1\n-1\n' \| timeout 20 opcdbg 0` | Same; `Compiled at : 0` = never compiled | +| Object details | `printf '3\n4\nN\n\n-1\n-1\n' \| timeout 20 opcdbg 0` | Priority, control item id, times, cls_id/obj_id | +| Object status | `printf '3\n18\n\n-1\n-1\n' \| timeout 20 opcdbg 0` | Total runs, executor (`Running in : 1, OPCEXE1`) | +| Object signals / attributes | `3` then `14` / `12`, object name | Signal → item id; attribute → type (LOCAL/GLOBAL) | +| Executor statistics | `printf '0\nOPCEXE1\n1\n-1\n-1\n' \| timeout 20 opcdbg 0 4` | Active classes/objects/trigger groups/items, number of executions; times stay 0 unless `STATISTICS = YES` in `opc.sup` | + +Executor names on R1.03: `OPCEXE1`…`OPCEXE4` (Traditional, priority ranges 0–249 … 750–999) +and `OPCJEXE` (Java). The prompt's default `OPCEXE` does not exist. + +Easier for names: the datasets `OBJECT_SIGNAL_DF` (object:signal → item name) and +`OBJECT_ATTR_VAL` / `CLASS_ATTR_VAL` (attribute values) via `dssqld -e` with a filter — see +`traditional-class.md` §3. + +## Dumps + +*Utilities* 3 / 4 (`printf '3\nclasses.qli\n4\nobjects.qli\n-1\n-1\n' | timeout 30 opcdbg 0 5`) +write all class sources / objects to files in the current folder. The format is an old one +(`NAME,"description",priority` then source lines starting with `- `) and **`dssqld -i` rejects +it** (`DSS-E-UNK_DS_NM`, ISS-027). To move classes and objects to another system, export +`CLASS_DF` and `OBJECT_DF` with `dssqld -e` instead (task `load-class-object.md`; migration in +`knowledge/manuals/IM36K10J10-01EN.md` §5.6). + +## Observed on the test system + +The database check reported one warning for a class `SINUS` (not from this repo) that was +never compiled; everything else was consistent. A class like that is harmless but can be +compiled or removed by its owner. diff --git a/.claude/skills/class-object-engineering/tasks/traditional-class.md b/.claude/skills/class-object-engineering/tasks/traditional-class.md new file mode 100644 index 0000000..f77dae3 --- /dev/null +++ b/.claude/skills/class-object-engineering/tasks/traditional-class.md @@ -0,0 +1,91 @@ +--- +task: Write a Traditional class with prompts, signals built from the object name, and items created from a template +version: R1.03 +source: IM 36K10P10-01EN §1–§5, §8, §10, §11.2.8; IM 36K10L10-01EN; practiced with CI-Eng-Sample class CIENG_TANK 2026-09-30 +status: verified +--- + +# Traditional class: prompts, signals, created items + +Worked example: class `CIENG_TANK` and object `CI-Eng-Sample.TANK1.CALC` +(`examples/CI-Eng-Sample/06_class_df.qli`, `07_object_df.qli`). Loading and removing: task +`load-class-object.md`. Language reference: `knowledge/manuals/IM36K10P10-01EN.md`. + +## 1. Design + +One class = one kind of equipment; one object per piece of equipment. Put the variable parts +(which items, which settings) in the **class prolog** so they are fixed when each object is +created: + +| Need | Use | +|---|---| +| Setting per object, asked at creation | `ATTRIBUTE x OBJECT FLOAT;` + `PROMPT x QUERY "…";` → `ATTR_VALUE_n` in `OBJECT_DF` | +| Setting shared by all objects | `ATTRIBUTE x CLASS …;` | +| Existing item next to the object | `SIGNAL s := SECTION || "." TRIGGER VALUE;` | +| New item per object | `SIGNAL s := FROM "