Extend class-object-engineering skill: language, Java, reset, opcdbg tasks
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
e6911796f7
commit
f99490378c
6 changed files with 391 additions and 29 deletions
|
|
@ -1,20 +1,38 @@
|
||||||
---
|
---
|
||||||
name: class-object-engineering
|
name: class-object-engineering
|
||||||
description: >-
|
description: >-
|
||||||
CI Server R1.03 PROCESS Service classes, objects and trigger groups. Use when the user wants
|
CI Server R1.03 PROCESS Service: trigger groups, classes and objects. Use when the user wants
|
||||||
to create a trigger group, write or compile a class (traditional language), create objects
|
to create a trigger group, write, compile or change a class (Traditional PROCESS language or
|
||||||
from a class, or load classes and objects with quick load files. Sources IM 36K10G10-01EN
|
Java), use signals, attributes, prompts, timers or template items in a class, create objects
|
||||||
(Tutorial) and IM 36K10J10-01EN; to be extended with IM 36K10L10, P10 and P11 in phase 6.
|
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)
|
# Class and object engineering (R1.03)
|
||||||
|
|
||||||
Background: `knowledge/manuals/IM36K10G10-01EN.md` (chapter 5) and
|
Background: `knowledge/manuals/IM36K10L10-01EN.md` (processes, `opc.sup`, `opcdbg`, data
|
||||||
`knowledge/manuals/IM36K10J10-01EN.md` (sections 2.4 and 5.3). Known issues for PROCESS
|
store), `IM36K10P10-01EN.md` (Traditional language), `IM36K10P11-01EN.md` (Java),
|
||||||
Service: `knowledge/manuals/IM36K01A50-01EN.md`.
|
`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 |
|
| 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 |
|
||||||
|
|
|
||||||
|
|
@ -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<CLASS>\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` = `"<class>",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.
|
||||||
87
.claude/skills/class-object-engineering/tasks/java-class.md
Normal file
87
.claude/skills/class-object-engineering/tasks/java-class.md
Normal file
|
|
@ -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, (<object>: <text>)`.
|
||||||
|
- 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).
|
||||||
|
|
@ -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
|
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
|
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 <file>.qli -l <file>.qlo`, check `Errors` = 0);
|
Load in this order, each with `dssqld -i <file>.qli -l <file>.qlo` and check `Errors` = 0:
|
||||||
remove in reverse (object, class, trigger group) with `NAME`-only files and `dssqld -r`.
|
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
|
@FIELDS
|
||||||
|
|
@ -20,17 +22,23 @@ NAME,DESCRIPTION,TRIGGER_INTERVAL
|
||||||
"CIENG_1S","CI-Eng-Sample one second trigger","1 seconds"
|
"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,
|
Other fields: `ACTIVATION_TIME`, `DEACTIVATION_TIME`, `TRIGGER_ONCE` (1 = run once when an
|
||||||
between `@"` and `"@` on their own lines; `COMPILE` 1 compiles it on load; `TRIGGER_1`
|
object is activated), `CORRECT_DAYLIGHT`. A class or object without a trigger group only runs
|
||||||
attaches a trigger group:
|
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
|
@FIELDS
|
||||||
NAME,DESCRIPTION,PF_LANGUAGE,TRIGGER_1,COMPILE,LISTING_WANTED,METHOD
|
NAME,DESCRIPTION,PF_LANGUAGE,TRIGGER_1,COMPILE,LISTING_WANTED,METHOD
|
||||||
|
|
||||||
@CLASS_DF
|
@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;
|
CLASS CIENG_INCR;
|
||||||
PROLOG
|
PROLOG
|
||||||
SIGNAL INPUT := "CI-Eng-Sample.DEMO.COUNTER";
|
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` = `"<class>",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
|
@FIELDS
|
||||||
NAME,DESCRIPTION,CLASS
|
NAME,DESCRIPTION,CLASS,ATTR_VALUE_1
|
||||||
|
|
||||||
@OBJECT_DF
|
@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, <text>`); nothing is left behind.
|
||||||
|
|
||||||
## Check
|
## Check
|
||||||
|
|
||||||
Run `itmval -g -n CI-Eng-Sample.DEMO.COUNTER` a few seconds apart: the value rises by one per
|
- Items the object writes: `itmval -g -n <item>` a few seconds apart (sample: `DEMO.COUNTER`
|
||||||
second. To inspect a class, export it with a filter file (`@SELECT`, then
|
rises by one per second).
|
||||||
`'NAME = "<class>"'`, then `@CLASS_DF`).
|
- Which item each signal got: export `OBJECT_SIGNAL_DF` with filter
|
||||||
|
`'OBJECT = "<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`,
|
## Remove
|
||||||
`86_` to `88_remove_*.qli`.
|
|
||||||
|
```
|
||||||
|
@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`.
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
<menu>` 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<CLASS>\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<sec>\n<seq>\n-1\n-1\n' \| timeout 20 opcdbg 0` | Same; `Compiled at : 0` = never compiled |
|
||||||
|
| Object details | `printf '3\n4\nN\n<object>\n-1\n-1\n' \| timeout 20 opcdbg 0` | Priority, control item id, times, cls_id/obj_id |
|
||||||
|
| Object status | `printf '3\n18\n<object>\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.
|
||||||
|
|
@ -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 || ".<TAG>" TRIGGER VALUE;` |
|
||||||
|
| New item per object | `SIGNAL s := FROM "<template item>" MAKE "FIELD" EQUAL value …;` |
|
||||||
|
| Refuse bad input | `IF … THEN ERROR "text"; ENDIF;` in the class prolog |
|
||||||
|
| Periodic run | trigger group on the class (`TRIGGER_1`) or object |
|
||||||
|
| Run on a change | `TRIGGER VALUE` (or STATUS, UPDATE …) on the signal |
|
||||||
|
|
||||||
|
Template items: keep them in their own section (sample: `CI-Eng-Sample.TEMPLATES.TPL_REAL`)
|
||||||
|
and load them before the class.
|
||||||
|
|
||||||
|
## 2. Example
|
||||||
|
|
||||||
|
```
|
||||||
|
CLASS CIENG_TANK;
|
||||||
|
PROLOG
|
||||||
|
ATTRIBUTE CAPACITY OBJECT FLOAT;
|
||||||
|
PROMPT CAPACITY QUERY "Tank capacity (m3)";
|
||||||
|
SIGNAL LEVEL := SECTION || ".LEVEL" TRIGGER VALUE;
|
||||||
|
SIGNAL VOLUME := FROM "CI-Eng-Sample.TEMPLATES.TPL_REAL" MAKE
|
||||||
|
"DESCRIPTION" EQUAL "Tank volume (m3), class CIENG_TANK";
|
||||||
|
IF CAPACITY <= 0 THEN
|
||||||
|
ERROR "CIENG_TANK: capacity must be > 0";
|
||||||
|
ENDIF;
|
||||||
|
BODY
|
||||||
|
METHOD CALC;
|
||||||
|
BODY
|
||||||
|
VOLUME := LEVEL * CAPACITY / 100.0;
|
||||||
|
IF LEVEL >=: 80.0 THEN
|
||||||
|
PRINT "CIENG_TANK ", SECTION, ": level reached 80 pct, volume ", VOLUME;
|
||||||
|
ENDIF;
|
||||||
|
ENDMETHOD CALC;
|
||||||
|
ENDCLASS CIENG_TANK;
|
||||||
|
```
|
||||||
|
|
||||||
|
Object `CI-Eng-Sample.TANK1.CALC` with `ATTR_VALUE_1` = `"200"`:
|
||||||
|
|
||||||
|
- `SECTION` = `CI-Eng-Sample.TANK1`, so `LEVEL` → `CI-Eng-Sample.TANK1.LEVEL`.
|
||||||
|
- `VOLUME` has no `"NAME"`, so the item is `CI-Eng-Sample.TANK1.CALC.VOLUME`; the section
|
||||||
|
`TANK1.CALC` is created too. Both are deleted with the object.
|
||||||
|
- `LEVEL` 50 → `VOLUME` 100; 82 → 164.
|
||||||
|
- `>=:` prints once when the level **crosses** 80 (message in `umhlog.log`, sender `OPCEXE1`).
|
||||||
|
|
||||||
|
Rules learned on the test system:
|
||||||
|
- Do not put `%` in `PRINT` text: the message is cut at that point (ISS-025).
|
||||||
|
- An object at root level has an empty `SECTION`; build names with an `IF` then (release notes).
|
||||||
|
- Item names in `SIGNAL` strings must match exactly; an item that does not exist makes the
|
||||||
|
object creation fail.
|
||||||
|
|
||||||
|
## 3. Check and operate
|
||||||
|
|
||||||
|
- Signals → items: export `OBJECT_SIGNAL_DF` with filter `'OBJECT = "<object>"'`
|
||||||
|
(sample: `…CALC:LEVEL` → `CI-Eng-Sample.TANK1.LEVEL`, `…CALC:VOLUME` → `…CALC.VOLUME`).
|
||||||
|
- Attribute values: export `OBJECT_ATTR_VAL` (same filter); record name
|
||||||
|
`<object>:<attribute>`, field `ATTR_VALUE`.
|
||||||
|
- **Change an attribute of a running object** (verified): `dssqld -m` on `OBJECT_ATTR_VAL`:
|
||||||
|
```
|
||||||
|
@FIELDS
|
||||||
|
NAME,ATTR_VALUE
|
||||||
|
|
||||||
|
@OBJECT_ATTR_VAL
|
||||||
|
"CI-Eng-Sample.TANK1.CALC:CAPACITY","400"
|
||||||
|
```
|
||||||
|
The new value is used from the next run (level 50 → volume 200). Do not change attributes
|
||||||
|
that were used to build signal names: the signal keeps its old item (P10 §8.3).
|
||||||
|
- Class-wide attributes: `CLASS_ATTR_VAL` (`<class>:<attribute>`), not practiced.
|
||||||
|
- Refused object: loading `ATTR_VALUE_1` = `"0"` gave `Errors 1` with
|
||||||
|
`OPC-E-INFO, CIENG_TANK: capacity must be > 0` in the `.qlo`; nothing was created.
|
||||||
|
|
||||||
|
Changing the class source later: task `change-reset-class.md`.
|
||||||
Loading…
Add table
Reference in a new issue