@codesys/mcp-toolkit 2.2.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +85 -0
- package/README.md +109 -9
- package/README.zh-CN.md +72 -9
- package/dist/actions.d.ts +9 -4
- package/dist/actions.js +1 -1
- package/dist/actions.js.map +1 -1
- package/dist/codesys/debug.d.ts +5 -0
- package/dist/codesys/debug.js +89 -0
- package/dist/codesys/debug.js.map +1 -0
- package/dist/codesys/device-tools.d.ts +3 -0
- package/dist/codesys/device-tools.js +38 -0
- package/dist/codesys/device-tools.js.map +1 -0
- package/dist/codesys/graphical.d.ts +76 -0
- package/dist/codesys/graphical.js +226 -0
- package/dist/codesys/graphical.js.map +1 -0
- package/dist/codesys/lang.d.ts +39 -0
- package/dist/codesys/lang.js +177 -0
- package/dist/codesys/lang.js.map +1 -0
- package/dist/codesys/simtest.d.ts +48 -0
- package/dist/codesys/simtest.js +103 -0
- package/dist/codesys/simtest.js.map +1 -0
- package/dist/codesys/st.d.ts +1 -1
- package/dist/codesys/st.js.map +1 -1
- package/dist/codesys/trace.d.ts +19 -0
- package/dist/codesys/trace.js +139 -0
- package/dist/codesys/trace.js.map +1 -0
- package/dist/hmi/native.d.ts +89 -0
- package/dist/hmi/native.js +447 -0
- package/dist/hmi/native.js.map +1 -0
- package/dist/hmi/render.d.ts +90 -0
- package/dist/hmi/render.js +307 -0
- package/dist/hmi/render.js.map +1 -0
- package/dist/hmi/route.d.ts +32 -0
- package/dist/hmi/route.js +184 -0
- package/dist/hmi/route.js.map +1 -0
- package/dist/hmi/service.d.ts +45 -0
- package/dist/hmi/service.js +182 -0
- package/dist/hmi/service.js.map +1 -0
- package/dist/hmi/spec.d.ts +821 -0
- package/dist/hmi/spec.js +191 -0
- package/dist/hmi/spec.js.map +1 -0
- package/dist/hmi/templates.d.ts +11 -0
- package/dist/hmi/templates.js +92 -0
- package/dist/hmi/templates.js.map +1 -0
- package/dist/hmi/tools.d.ts +4 -0
- package/dist/hmi/tools.js +222 -0
- package/dist/hmi/tools.js.map +1 -0
- package/dist/hmi/value.d.ts +3 -0
- package/dist/hmi/value.js +26 -0
- package/dist/hmi/value.js.map +1 -0
- package/dist/panel/hmi.js +138 -0
- package/dist/panel.d.ts +3 -0
- package/dist/panel.js +17 -0
- package/dist/panel.js.map +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.js +7 -2
- package/dist/server.js.map +1 -1
- package/dist/tools.d.ts +5 -1
- package/dist/tools.js +18 -2
- package/dist/tools.js.map +1 -1
- package/dist/viewer.d.ts +1 -1
- package/dist/viewer.js +13 -2
- package/dist/viewer.js.map +1 -1
- package/package.json +1 -1
- package/watcher/mcp_alarms.py +134 -0
- package/watcher/mcp_debug.py +161 -0
- package/watcher/mcp_devices.py +83 -0
- package/watcher/mcp_lang.py +179 -0
- package/watcher/mcp_ops.py +3 -1
- package/watcher/mcp_trace.py +90 -0
- package/watcher/mcp_ui.py +54 -0
- package/watcher/mcp_visu.py +422 -0
- package/watcher/watcher.py +35 -1
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Devices from CODESYS's device repository: search the installed device
|
|
3
|
+
# descriptions (fieldbus masters and slaves, I/O modules) and add or plug one into
|
|
4
|
+
# the device tree. Documented scripting API (device_repository, ScriptDeviceObject).
|
|
5
|
+
# Offline only: nothing here goes online.
|
|
6
|
+
#
|
|
7
|
+
# Keep this file ASCII-only (IronPython 2.7 inside CODESYS).
|
|
8
|
+
import mcp_ops
|
|
9
|
+
import mcp_sim
|
|
10
|
+
from mcp_ops import Ctx, OpError, _safe
|
|
11
|
+
from mcp_compat import to_text
|
|
12
|
+
|
|
13
|
+
import scriptengine as se
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _desc(d):
|
|
17
|
+
did = _safe(lambda: d.device_id)
|
|
18
|
+
out = {
|
|
19
|
+
"name": to_text(_safe(lambda: d.name, "")),
|
|
20
|
+
"vendor": to_text(_safe(lambda: d.vendor, "")),
|
|
21
|
+
"description": to_text(_safe(lambda: d.description, "") or "")[:200],
|
|
22
|
+
}
|
|
23
|
+
if did is not None:
|
|
24
|
+
out["type"] = int(_safe(lambda: did.type, 0))
|
|
25
|
+
out["id"] = to_text(_safe(lambda: did.id, ""))
|
|
26
|
+
out["version"] = to_text(_safe(lambda: did.version, ""))
|
|
27
|
+
order = _safe(lambda: d.order_number)
|
|
28
|
+
if order:
|
|
29
|
+
out["order_number"] = to_text(order)
|
|
30
|
+
return out
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def op_devices_search(args):
|
|
34
|
+
repo = _safe(lambda: se.device_repository)
|
|
35
|
+
if repo is None:
|
|
36
|
+
raise OpError("unavailable", "This CODESYS has no device repository in scripting.")
|
|
37
|
+
text = args.get("text") or ""
|
|
38
|
+
found = repo.get_all_devices(name=text, source=None)
|
|
39
|
+
out = []
|
|
40
|
+
for d in found or []:
|
|
41
|
+
full = d
|
|
42
|
+
if not to_text(_safe(lambda: d.name, "") or ""):
|
|
43
|
+
did = _safe(lambda: d.device_id)
|
|
44
|
+
full = (_safe(lambda: repo.get_device(did)) if did is not None else None) or d
|
|
45
|
+
item = _desc(full)
|
|
46
|
+
if not item["name"]:
|
|
47
|
+
info = _safe(lambda: full.device_info)
|
|
48
|
+
item["name"] = to_text(_safe(lambda: info.name, "") or "")
|
|
49
|
+
item["vendor"] = item["vendor"] or to_text(_safe(lambda: info.vendor, "") or "")
|
|
50
|
+
item["description"] = item["description"] or to_text(_safe(lambda: info.description, "") or "")[:200]
|
|
51
|
+
out.append(item)
|
|
52
|
+
if len(out) >= int(args.get("limit") or 40):
|
|
53
|
+
break
|
|
54
|
+
return {"devices": out, "more": len(found or []) > len(out)}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def op_devices_add(args):
|
|
58
|
+
c = Ctx()
|
|
59
|
+
parent = c.resolve(args["parent"])
|
|
60
|
+
if not _safe(lambda: parent.is_device, False):
|
|
61
|
+
raise OpError("bad_path", "%s is not a device (add devices under a device or a connector's device, e.g. '/Device')." % args["parent"])
|
|
62
|
+
how = args.get("how") or "add"
|
|
63
|
+
module = args.get("module")
|
|
64
|
+
if how == "plug":
|
|
65
|
+
parent.plug(args["name"], int(args["type"]), args["id"], args["version"], module)
|
|
66
|
+
dev = parent
|
|
67
|
+
else:
|
|
68
|
+
fn = parent.add if how == "add" else parent.insert
|
|
69
|
+
if how == "insert":
|
|
70
|
+
parent.insert(args["name"], int(args.get("index") or 0), int(args["type"]), args["id"], args["version"], module)
|
|
71
|
+
else:
|
|
72
|
+
fn(args["name"], int(args["type"]), args["id"], args["version"], module)
|
|
73
|
+
dev = None
|
|
74
|
+
for ch in parent.get_children(False):
|
|
75
|
+
if to_text(_safe(lambda: ch.get_name(), "")).lower() == args["name"].lower():
|
|
76
|
+
dev = ch
|
|
77
|
+
if dev is None:
|
|
78
|
+
raise OpError("codesys_error", "CODESYS added nothing named %s under %s." % (args["name"], args["parent"]))
|
|
79
|
+
return {"path": c.path_of(dev), "saved": c.save_if(args)}
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
mcp_ops.OPS["devices.search"] = op_devices_search
|
|
83
|
+
mcp_ops.OPS["devices.add"] = mcp_sim._locked(op_devices_add)
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# What CODESYS's compiler knows about the code: the interface of any POU or type
|
|
3
|
+
# (including FBs from compiled libraries, which the scripting API can't read),
|
|
4
|
+
# and cross-references (where a name is read, written or called).
|
|
5
|
+
#
|
|
6
|
+
# Both use CODESYS's own services, reached through a plugin's APEnvironment:
|
|
7
|
+
# LanguageModelMgr.FindSignaturesByName and CrossReferenceService. They work on the
|
|
8
|
+
# compiled language model, so the application is built first when nothing is found.
|
|
9
|
+
#
|
|
10
|
+
# Keep this file ASCII-only (IronPython 2.7 inside CODESYS).
|
|
11
|
+
import mcp_ops
|
|
12
|
+
from mcp_ops import Ctx, OpError
|
|
13
|
+
from mcp_compat import to_text
|
|
14
|
+
|
|
15
|
+
_ENVS = ("_3S.CoDeSys.RecipeManObject.APEnvironment", "_3S.CoDeSys.VisualEditor.APEnvironment", "_3S.CoDeSys.SecurityManager.APEnvironment")
|
|
16
|
+
_CACHE = {}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _find_type(name):
|
|
20
|
+
if name in _CACHE:
|
|
21
|
+
return _CACHE[name]
|
|
22
|
+
try:
|
|
23
|
+
from System import AppDomain
|
|
24
|
+
except ImportError:
|
|
25
|
+
raise OpError("unavailable", "CODESYS's language services need CODESYS (not available in this engine).")
|
|
26
|
+
found = None
|
|
27
|
+
for asm in AppDomain.CurrentDomain.GetAssemblies():
|
|
28
|
+
try:
|
|
29
|
+
found = asm.GetType(name)
|
|
30
|
+
except Exception:
|
|
31
|
+
found = None
|
|
32
|
+
if found is not None:
|
|
33
|
+
break
|
|
34
|
+
_CACHE[name] = found
|
|
35
|
+
return found
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _service(prop):
|
|
39
|
+
try:
|
|
40
|
+
from System.Reflection import BindingFlags
|
|
41
|
+
except ImportError:
|
|
42
|
+
raise OpError("unavailable", "CODESYS's language services need CODESYS (not available in this engine).")
|
|
43
|
+
for tname in _ENVS:
|
|
44
|
+
t = _find_type(tname)
|
|
45
|
+
if t is None:
|
|
46
|
+
continue
|
|
47
|
+
p = t.GetProperty(prop, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)
|
|
48
|
+
if p is not None:
|
|
49
|
+
v = p.GetValue(None, None)
|
|
50
|
+
if v is not None:
|
|
51
|
+
return v
|
|
52
|
+
raise OpError("unavailable", "This CODESYS doesn't offer %s to scripts." % prop)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _get(o, name, default=None):
|
|
56
|
+
try:
|
|
57
|
+
return getattr(o, name)
|
|
58
|
+
except Exception:
|
|
59
|
+
try:
|
|
60
|
+
t = o.GetType()
|
|
61
|
+
for it in [t] + list(t.GetInterfaces()):
|
|
62
|
+
p = it.GetProperty(name)
|
|
63
|
+
if p is not None:
|
|
64
|
+
return p.GetValue(o, None)
|
|
65
|
+
except Exception:
|
|
66
|
+
pass
|
|
67
|
+
return default
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _caller(c):
|
|
71
|
+
"""A POU of the application to resolve names from (its scope sees the libraries)."""
|
|
72
|
+
for ch in c.app.get_children(True):
|
|
73
|
+
try:
|
|
74
|
+
if ch.has_textual_declaration and "PROGRAM" in to_text(ch.textual_declaration.text).upper()[:200]:
|
|
75
|
+
return ch
|
|
76
|
+
except Exception:
|
|
77
|
+
pass
|
|
78
|
+
return c.app
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _clean(s):
|
|
82
|
+
s = to_text(s or "").strip()
|
|
83
|
+
return " ".join(s.split()) if s else ""
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _var(v, section):
|
|
87
|
+
attrs = [to_text(a) for a in (_get(v, "Attributes") or [])]
|
|
88
|
+
out = {"name": to_text(_get(v, "OrgName") or _get(v, "Name")), "type": to_text(_get(v, "Type")), "section": section}
|
|
89
|
+
comment = _clean(_get(v, "Comment")).lstrip("| ").strip()
|
|
90
|
+
if comment:
|
|
91
|
+
out["comment"] = comment
|
|
92
|
+
if "hide" in attrs:
|
|
93
|
+
out["hidden"] = True
|
|
94
|
+
init = _get(v, "Initial")
|
|
95
|
+
if init is not None:
|
|
96
|
+
out["init"] = to_text(init)
|
|
97
|
+
return out
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _signature(lmm, c, sig):
|
|
101
|
+
ins = set(to_text(_get(v, "OrgName")) for v in (_get(sig, "Inputs") or []))
|
|
102
|
+
outs = set(to_text(_get(v, "OrgName")) for v in (_get(sig, "Outputs") or []))
|
|
103
|
+
variables = []
|
|
104
|
+
for v in lmm.GetAllVariables(sig, c.app.guid):
|
|
105
|
+
n = to_text(_get(v, "OrgName"))
|
|
106
|
+
variables.append(_var(v, "input" if n in ins else "output" if n in outs else "other"))
|
|
107
|
+
subs = []
|
|
108
|
+
try:
|
|
109
|
+
for s in sig.GetSubSignatures() or []:
|
|
110
|
+
subs.append(to_text(_get(s, "OrgName") or _get(s, "Name")))
|
|
111
|
+
except Exception:
|
|
112
|
+
pass
|
|
113
|
+
return {
|
|
114
|
+
"name": to_text(_get(sig, "OrgName") or _get(sig, "Name")),
|
|
115
|
+
"kind": to_text(_get(sig, "POUType")),
|
|
116
|
+
"library": to_text(_get(sig, "LibraryPath") or ""),
|
|
117
|
+
"comment": _clean(_get(sig, "Comment")),
|
|
118
|
+
"variables": variables,
|
|
119
|
+
"members": subs,
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def op_lang_signature(args):
|
|
124
|
+
c = Ctx()
|
|
125
|
+
lmm = _service("LanguageModelMgr")
|
|
126
|
+
caller = _caller(c)
|
|
127
|
+
built = False
|
|
128
|
+
out = []
|
|
129
|
+
for name in args["names"]:
|
|
130
|
+
sigs = lmm.FindSignaturesByName(c.proj.handle, c.app.guid, caller.guid, name)
|
|
131
|
+
if (sigs is None or len(sigs) == 0) and not built:
|
|
132
|
+
c.app.build()
|
|
133
|
+
built = True
|
|
134
|
+
sigs = lmm.FindSignaturesByName(c.proj.handle, c.app.guid, caller.guid, name)
|
|
135
|
+
if sigs is None or len(sigs) == 0:
|
|
136
|
+
out.append({"name": name, "error": "not found (check the spelling, and that the library is referenced)"})
|
|
137
|
+
continue
|
|
138
|
+
out.append(_signature(lmm, c, sigs[0]))
|
|
139
|
+
return {"signatures": out, "built": built}
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def op_lang_xref(args):
|
|
143
|
+
import System
|
|
144
|
+
from System import Guid
|
|
145
|
+
c = Ctx()
|
|
146
|
+
xs = _service("CrossReferenceService")
|
|
147
|
+
T = _find_type("_3S.CoDeSys.LanguageModelUtilities.CrossRefSearchType")
|
|
148
|
+
O = _find_type("_3S.CoDeSys.LanguageModelUtilities.CrossRefOccurence")
|
|
149
|
+
M = _find_type("_3S.CoDeSys.LanguageModelUtilities.CrossReferenceMatchType")
|
|
150
|
+
if T is None or O is None or M is None:
|
|
151
|
+
raise OpError("unavailable", "This CODESYS doesn't offer cross-references to scripts.")
|
|
152
|
+
if args.get("build", True):
|
|
153
|
+
c.app.build()
|
|
154
|
+
kind = {"variable": "Variables", "pou": "POUs", "type": "Types"}.get(args.get("kind") or "variable", "Variables")
|
|
155
|
+
try:
|
|
156
|
+
st = System.Enum.Parse(T, kind)
|
|
157
|
+
except Exception:
|
|
158
|
+
st = System.Enum.Parse(T, "Variables")
|
|
159
|
+
nodes = xs.GetCrossReferenceNodesWithinApplication(args["name"], "", Guid.Empty, st, System.Enum.Parse(O, "LanguageModel"), System.Enum.Parse(M, "Existing"), c.app.guid)
|
|
160
|
+
refs = []
|
|
161
|
+
for nd in nodes or []:
|
|
162
|
+
pos = _get(nd, "Position", 0) or 0
|
|
163
|
+
try:
|
|
164
|
+
pos = int(pos)
|
|
165
|
+
except Exception:
|
|
166
|
+
pos = 0
|
|
167
|
+
refs.append({
|
|
168
|
+
"access": to_text(_get(nd, "AccessText") or ""),
|
|
169
|
+
"pou": to_text(_get(nd, "POUName") or ""),
|
|
170
|
+
"location": to_text(_get(nd, "Location") or ""),
|
|
171
|
+
"text": _clean(_get(nd, "Text")),
|
|
172
|
+
})
|
|
173
|
+
return {"name": args["name"], "references": refs}
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
mcp_ops.OPS.update({
|
|
177
|
+
"lang.signature": op_lang_signature,
|
|
178
|
+
"lang.xref": op_lang_xref,
|
|
179
|
+
})
|
package/watcher/mcp_ops.py
CHANGED
|
@@ -542,6 +542,8 @@ def op_object_create(args):
|
|
|
542
542
|
obj = parent.create_dut(name, dt)
|
|
543
543
|
elif kind == "gvl":
|
|
544
544
|
obj = parent.create_gvl(name)
|
|
545
|
+
elif kind == "persistent_vars":
|
|
546
|
+
obj = parent.create_persistentvars(name)
|
|
545
547
|
elif kind == "folder":
|
|
546
548
|
obj = parent.create_folder(name)
|
|
547
549
|
else:
|
|
@@ -1097,7 +1099,7 @@ def _reflect_api(path):
|
|
|
1097
1099
|
def op_api_probe(args):
|
|
1098
1100
|
"""The scripting API this CODESYS offers: member names of the main objects, the
|
|
1099
1101
|
enums the watcher relies on, version-like values, and the object type GUIDs of
|
|
1100
|
-
the open project with their kinds. For comparing service packs (docs/sp22
|
|
1102
|
+
the open project with their kinds. For comparing service packs (docs/codesys-api-sp21-sp22.md)."""
|
|
1101
1103
|
c = Ctx(require_project=False)
|
|
1102
1104
|
objs = {"se": se, "system": _safe(lambda: se.system), "projects": _safe(lambda: se.projects), "project": c.proj, "application": c.app}
|
|
1103
1105
|
samples = {}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# CODESYS Trace in the simulation: a trace object records variables every cycle of a
|
|
3
|
+
# task; the data comes back as a table. Uses CODESYS's trace script driver
|
|
4
|
+
# (se.trace.create, open_editor().download/start/save), only while CODESYS's own
|
|
5
|
+
# simulation runs (mcp_sim checks the device is in simulation mode).
|
|
6
|
+
#
|
|
7
|
+
# Keep this file ASCII-only (IronPython 2.7 inside CODESYS).
|
|
8
|
+
import os
|
|
9
|
+
|
|
10
|
+
import mcp_ops
|
|
11
|
+
import mcp_sim
|
|
12
|
+
from mcp_ops import Ctx, OpError, name_of
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
import scriptengine as se
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _find(c, name):
|
|
19
|
+
for ch in c.app.get_children(True):
|
|
20
|
+
if name_of(ch).lower() == name.lower():
|
|
21
|
+
return ch
|
|
22
|
+
return None
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _first_task(c):
|
|
26
|
+
for ch in c.app.get_children(True):
|
|
27
|
+
try:
|
|
28
|
+
if ch.is_task:
|
|
29
|
+
return ch
|
|
30
|
+
except Exception:
|
|
31
|
+
pass
|
|
32
|
+
return None
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def op_trace_setup(args):
|
|
36
|
+
c = Ctx()
|
|
37
|
+
if not hasattr(se, "trace"):
|
|
38
|
+
raise OpError("unavailable", "This CODESYS has no trace scripting.")
|
|
39
|
+
name = args["name"]
|
|
40
|
+
old = _find(c, name)
|
|
41
|
+
if old is not None:
|
|
42
|
+
old.remove()
|
|
43
|
+
task = args.get("task")
|
|
44
|
+
if not task:
|
|
45
|
+
t = _first_task(c)
|
|
46
|
+
if t is None:
|
|
47
|
+
raise OpError("not_found", "The application has no task to record in.")
|
|
48
|
+
task = name_of(t)
|
|
49
|
+
tr = se.trace.create(c.app, name, task)
|
|
50
|
+
for v in args["variables"]:
|
|
51
|
+
tv = tr.variable_list.add()
|
|
52
|
+
tv.variable_name = v
|
|
53
|
+
if args.get("every_n_cycles"):
|
|
54
|
+
try:
|
|
55
|
+
tr.every_n_cycles = int(args["every_n_cycles"])
|
|
56
|
+
except Exception:
|
|
57
|
+
pass
|
|
58
|
+
return {"name": name, "task": task, "variables": list(args["variables"]), "saved": c.save_if(args)}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def op_trace_record(args):
|
|
62
|
+
c = Ctx()
|
|
63
|
+
mcp_sim._online() # raises unless the simulation runs
|
|
64
|
+
obj = _find(c, args["name"])
|
|
65
|
+
if obj is None:
|
|
66
|
+
raise OpError("not_found", "No trace named %s. Set it up with trace_setup before starting the simulation." % args["name"])
|
|
67
|
+
if not hasattr(obj, "open_editor"):
|
|
68
|
+
raise OpError("unavailable", "%s is not a trace this CODESYS can record from a script." % args["name"])
|
|
69
|
+
ed = obj.open_editor()
|
|
70
|
+
ed.download()
|
|
71
|
+
ed.start()
|
|
72
|
+
mcp_sim._pause(int(args.get("ms") or 3000))
|
|
73
|
+
path = args["path"]
|
|
74
|
+
folder = os.path.dirname(path)
|
|
75
|
+
if folder and not os.path.isdir(folder):
|
|
76
|
+
os.makedirs(folder)
|
|
77
|
+
ed.save(path)
|
|
78
|
+
try:
|
|
79
|
+
ed.stop()
|
|
80
|
+
except Exception:
|
|
81
|
+
pass
|
|
82
|
+
return {"path": path}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
mcp_ops.OPS["trace.setup"] = mcp_sim._locked(op_trace_setup)
|
|
86
|
+
mcp_ops.OPS["trace.record"] = op_trace_record
|
|
87
|
+
# The visualization builder changes the project too: not while the simulation runs.
|
|
88
|
+
for _op in ("visu.build", "visu.manager"):
|
|
89
|
+
if _op in mcp_ops.OPS:
|
|
90
|
+
mcp_ops.OPS[_op] = mcp_sim._locked(mcp_ops.OPS[_op])
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# --show-window extras: open the object a request just wrote in a CODESYS editor tab, so
|
|
3
|
+
# the user sees the code arrive in the window instead of only the project tree.
|
|
4
|
+
#
|
|
5
|
+
# CODESYS's scripting API has no call for this. It uses CODESYS's own (undocumented) .NET
|
|
6
|
+
# frame instead: IFrame.OpenEditorView, the call behind "Edit Object". Checked on CODESYS
|
|
7
|
+
# V3.5 SP21 and SP22. Best-effort: a failure is only logged and never changes a result.
|
|
8
|
+
#
|
|
9
|
+
# Keep this file ASCII-only (IronPython 2.7 inside CODESYS).
|
|
10
|
+
|
|
11
|
+
_CACHE = {}
|
|
12
|
+
|
|
13
|
+
# Any plugin's APEnvironment exposes the engine (with its frame) and the object manager.
|
|
14
|
+
_ENV_TYPES = ("_3S.CoDeSys.SecurityManager.APEnvironment", "_3S.CoDeSys.VisualEditor.APEnvironment")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _find_env():
|
|
18
|
+
from System import AppDomain
|
|
19
|
+
asms = list(AppDomain.CurrentDomain.GetAssemblies())
|
|
20
|
+
for name in _ENV_TYPES:
|
|
21
|
+
for asm in asms:
|
|
22
|
+
try:
|
|
23
|
+
t = asm.GetType(name)
|
|
24
|
+
except Exception:
|
|
25
|
+
t = None
|
|
26
|
+
if t is not None:
|
|
27
|
+
return t
|
|
28
|
+
return None
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _env():
|
|
32
|
+
if "env" not in _CACHE:
|
|
33
|
+
try:
|
|
34
|
+
_CACHE["env"] = _find_env()
|
|
35
|
+
except Exception:
|
|
36
|
+
_CACHE["env"] = None
|
|
37
|
+
return _CACHE["env"]
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def open_editor(se, obj):
|
|
41
|
+
"""Opens obj in its editor in the CODESYS window (or brings its tab forward).
|
|
42
|
+
|
|
43
|
+
Returns "opened", "fake" (the test engine) or "unavailable" (no frame found)."""
|
|
44
|
+
if hasattr(se, "FAKE"):
|
|
45
|
+
return "fake"
|
|
46
|
+
env = _env()
|
|
47
|
+
if env is None:
|
|
48
|
+
return "unavailable"
|
|
49
|
+
from System import Guid
|
|
50
|
+
engine = env.GetProperty("Engine").GetValue(None, None)
|
|
51
|
+
objects = env.GetProperty("ObjectMgr").GetValue(None, None)
|
|
52
|
+
stub = objects.GetMetaObjectStub(se.projects.primary.handle, obj.guid)
|
|
53
|
+
engine.Frame.OpenEditorView(stub, Guid.Empty, None)
|
|
54
|
+
return "opened"
|