From 269a0704a341a683e5d29e96a22dd2f646417d31 Mon Sep 17 00:00:00 2001 From: Thiago Alves Date: Thu, 14 May 2026 06:49:04 -0400 Subject: [PATCH] =?UTF-8?q?feat(libs):=20library=20system=20overhaul=20?= =?UTF-8?q?=E2=80=94=20disk-source=20pattern,=20OSCAT=20100%=20V3=20import?= =?UTF-8?q?,=20manifest=20hierarchy=20(#105)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(libs): add Additional Function Blocks library (RTC, INTEGRAL, DERIVATIVE, PID, RAMP, HYSTERESIS) Brings IEC 61131-3 Annex E "Additional Function Blocks" over from MatIEC's lib/*.txt as a new bundled .stlib archive. Sources live under libs/sources/additional-function-blocks/ for inspection and round-trip through the standard rebuild-libs script. The six blocks are ported verbatim from MatIEC where the ST is pure (INTEGRAL, DERIVATIVE, PID, RAMP, HYSTERESIS) and adapted minimally where MatIEC used compiler-specific extensions (RTC). RTC's MatIEC pragma `{__SET_VAR(data__->,CURRENT_TIME,,__CURRENT_TIME)}` is replaced with a plain call to a new STruC++ runtime function CURRENT_DT(), keeping the FB body in standard ST. Runtime additions: - CURRENT_DT() — wall-clock IEC_DT from std::chrono::system_clock, parallel to TIME() (scan-cycle elapsed). Registered in the std function registry. Type checker: - New IEC §6.6.2.2 date/time arithmetic rules: DT/DATE/TOD - DT/DATE/TOD = TIME (duration between instants) DT/DATE/TOD ± TIME = DT/DATE/TOD (instant offset) TIME + DT/DATE/TOD = DT/DATE/TOD (commutative addition) Without these, RTC's `OFFSET := PDT - CURRENT_TIME` (and any user date arithmetic) would fail type-check. C++ side already worked — these are int64_t aliases — so this is type-checker-only. Build wiring: - New script scripts/generate-additional-fb.mjs and matching npm run build:additional-fb that compiles the six .st sources into libs/additional-function-blocks.stlib, in dependency order (INTEGRAL/DERIVATIVE before PID). - rebuild-libs.mjs now rebuilds the new archive between iec-standard-fb and OSCAT, and copies it into vscode-extension/bundled-libs. Tests (24 new, all passing): - tests/library/additional-fb-library.test.ts (14): manifest contents, per-FB signatures, recompilation from embedded sources, end-to-end user-program integration for every FB. - tests/semantic/date-time-arithmetic.test.ts (10): the new DT arithmetic rule across all type pairs, plus negative cases that the rule must NOT permit (DT → TIME assignment, DT - DT → DT). Total: 1596 → 1620 tests, 0 regressions. * fix(libs): make RTC hardware-agnostic (drop CURRENT_DT() coupling) The previous RTC body called CURRENT_DT() to read wall-clock time on every scan, which would have prevented the FB from compiling on hardware-agnostic targets such as Arduino (no std::chrono). The block is supposed to be self-contained: count from absolute zero internally, re-anchor on the rising edge of IN to the user-supplied PDT, then advance from PDT at real-time rate. New behaviour: - Internal state: ANCHOR_DT (DT, defaulted to zero) + ANCHOR_TIME (TIME, defaulted to T#0s). - Every scan: CDT := ANCHOR_DT + (TIME() - ANCHOR_TIME). - On rising edge of IN: ANCHOR_DT := PDT, ANCHOR_TIME := TIME(). - Q := IN, mirroring the input as before. CURRENT_DT() stays in the runtime and the std-function registry — it remains useful for user code that wants wall-clock time on platforms that ship one. RTC just doesn't depend on it. Users who want RTC to reflect wall-clock time can drive PDT externally with `clock(IN := edge, PDT := CURRENT_DT())` on those platforms. Tests: - Updated the existing user-program integration test to exercise RTC across the rising edge in two scans (pre-anchor and post-anchor), rather than a single FALSE-IN snapshot. - Added a regression guard that scans the embedded rtc.st (with comments stripped) and asserts the executable body never calls CURRENT_DT() — catches accidental re-coupling in future edits. * fix(libs): RTC = MatIEC body verbatim with __CURRENT_TIME → TO_DT(TIME()) Earlier corrected one wrong assumption (CURRENT_DT() coupling), then overshot in the opposite direction with a ground-up rewrite around an ANCHOR_DT/ANCHOR_TIME pair. MatIEC's RTC was already hardware-agnostic: its `__CURRENT_TIME` global is the same monotonic scan-cycle quantity that STruC++ exposes through TIME(). The right move is a 1:1 substitution. Body now mirrors lib/rtc.txt directly: CURRENT_TIME : DT ; ... CURRENT_TIME := TO_DT(TIME()) ; (* was {__SET_VAR(__CURRENT_TIME)} *) IF IN THEN IF NOT PREV_IN THEN OFFSET := PDT - CURRENT_TIME ; END_IF ; CDT := CURRENT_TIME + OFFSET ; ELSE CDT := CURRENT_TIME ; END_IF ; Q := IN ; PREV_IN := IN ; The TO_DT() wrapper is the smallest accommodation STruC++ needs over MatIEC: STruC++'s type checker requires an explicit conversion where MatIEC's pragma did a raw bit-copy. Both reduce to the same int64 underneath, so the runtime semantics are identical. The earlier-added regression guard (the embedded rtc.st must not call CURRENT_DT() in its executable body) still applies and continues to pass. The two-step rising-edge integration test also still passes unchanged — RTC's external contract didn't change with this revert. * feat(libs): library.json metadata + per-block documentation Establishes libs/sources// as the canonical, on-disk source of truth for hand-authored libraries. Each lib's source directory now ships a library.json carrying every .stlib manifest field that isn't derivable from ST: name, version, namespace, description, isBuiltin, plus per-FB / per-function documentation strings surfaced in editor hover dialogs. Architecture: libs/sources/iec-standard-fb/ library.json edge_detection.st, bistable.st, counter.st, timer.st libs/sources/additional-function-blocks/ library.json integral.st, derivative.st, rtc.st, pid.st, ramp.st, hysteresis.st libs/.stlib ← pure build artifact The build flow: 1. Read library.json 2. Read .st files 3. compileStlib(sources, options-from-config) 4. Merge library.json's `blocks[name].documentation` (and `functions[name].documentation`) into the resulting manifest's functionBlocks[] / functions[] entries 5. Validate every doc'd name appears in the compiled manifest — unknown names fail the build (catches typos and stale entries when an FB is renamed) OSCAT stays on the legacy archive-round-trip path because its true upstream is the CODESYS .library file at tests/fixtures/codesys/oscat_basic_335_codesys3.library and the codesys-importer doesn't yet write disk sources at build time. A TODO in rebuild-libs.mjs notes the asymmetry as a follow-up. Documentation prose for the 22 standard FBs and the 6 additional FBs is taken from the openplc-editor's hardcoded library catalog (src/frontend/data/library/{standard,additional}-function-blocks.ts) verbatim, so the eventual migration of the editor onto these stlib archives surfaces identical hover text to existing users. New module: src/library/library-config.ts (LibraryConfig schema + loadLibraryConfig + applyLibraryConfigDocumentation, with full validation that fails loud on malformed JSON, missing required fields, or doc entries referencing unknown symbols). Manifest types: LibraryFBEntry and LibraryFunctionEntry gain optional `documentation: string` fields. The earlier-added per-variable documentation field on LibraryVarType was removed per the "forget per-input/output docs" decision — we'll revisit if/when there's a concrete use case. Tests (21 new): - tests/library/library-config.test.ts (18): loader validation, documentation merge, unknown-name reporting, case sensitivity. - tests/library/additional-fb-library.test.ts (+2): every FB has a documentation string; RTC's prose matches the editor's verbatim. - tests/library/std-fb-library.test.ts (+2): every FB has a documentation string; TON/TOF/TP prose matches the editor's verbatim. Total: 1621 → 1642 tests, 0 regressions. * build(libs): untrack hand-authored .stlib archives, make `npm run build` produce them The .stlib archives are pure build artefacts now that libs/sources// is the canonical source of truth (.st files + library.json). Tracking them in git creates stale-blob churn on every library or compiler change — every PR that touches semantics or a doc string would carry a 50-100KB binary diff. Untracked: libs/iec-standard-fb.stlib libs/additional-function-blocks.stlib Tracked exception (documented in .gitignore): libs/oscat-basic.stlib — kept until the codesys-importer can cleanly re-extract OSCAT from its CODESYS .library fixture. The importer currently drops the closing `*)` of trailing block comments on 397/559 sources, so a fresh re-import produces an archive that fails to recompile. Round-trip-from-archive remains the OSCAT path for now (already documented as a follow-up TODO). Build flow: npm install && npm run build → generates libs/*.stlib vitest globalSetup runs the same script before tests so the test suite always sees freshly-built archives. Build script changes: - "build" now runs scripts/rebuild-libs.mjs (which does tsc + lib generation in one step). The previous `tsc`-only behaviour is preserved as "build:tsc-only" for cases that genuinely just want type emission (rare). - "prepack" runs the full build so `npm pack` always sees libs. - "clean" now also wipes the gitignored .stlib outputs. vscode-extension/esbuild.mjs: previously did fs.cpSync(libs/, bundled-libs/, { recursive: true }) which would have copied the new libs/sources/ subtree into every .vsix at packaging time. Replaced with a selective copy that only picks up *.stlib at the top level of libs/. The recursive cp was a latent bug — sources are 50KB+ today and would only grow. LibraryConfig schema: added optional `globalConstants?: Record` so libraries with compile-time integer constants (e.g. OSCAT's STRING_LENGTH=254, LIST_LENGTH=254) can declare them in library.json. Validator rejects non-finite numbers and array shapes. Tests: +4 in tests/library/library-config.test.ts covering the new globalConstants validation paths. Suite: 1642 → 1646 (no regressions). Note on OSCAT migration follow-up: When the codesys-importer regression is fixed, OSCAT can move to libs/sources/oscat-basic/ with a library.json (already drafted in this branch but reverted along with the half-finished CODESYS-import build path), the .library fixture stays at tests/fixtures/codesys/, and rebuild-libs.mjs gains a third helper that runs the importer + compileStlib at build time. Round-trip path goes away. Until then, oscat-basic.stlib stays tracked. * fix(libs): bring OSCAT onto the disk-source-of-truth model OSCAT now follows the same pattern as the other libs: the canonical source-of-truth is on disk under libs/sources/oscat-basic/ (the binary CODESYS V3 .library file plus library.json), and the .stlib archive in libs/ is a pure build artefact regenerated by `npm run build`. The fresh CODESYS V3 OSCAT 3.35 .library file replaces the older fixture at tests/fixtures/codesys/oscat_basic_335_codesys3.library. The V2.3 .lib stays in tests/fixtures/codesys/ since it's only a v2.3-importer test fixture. To make this work, three problems in the V3 importer had to be addressed (the third is worked around, the first two are fixed): 1. Boundary record's column A was being dropped (used `i < boundary` instead of `i <= boundary`). For ~390 POUs whose trailing block comment closed at exactly the boundary record, the closing `*)` went missing and the source failed to recompile. Fix: src/library/codesys-import/v3-parser.ts, include the boundary record's column A. 2. Long implementations (> ~127 lines) overflow into the boundary record itself, with additional impl lines packed at stride-10 varint positions (varint[0], [10], [20], …). The previous parser never read those, leaving DCF77, _ARRAY_SORT, HOLIDAY, SEQUENCE_4/8, ESR_MON_B8, CRC_GEN, SUN_POS and several others truncated. Fix: read the boundary record's stride-10 overflow entries. 3. The V3 GVL extractor still misses OSCAT's VAR_GLOBAL block (which instantiates LANGUAGE/MATH/PHYS/SETUP/LOCATION as instances of the CONSTANTS_* struct types). HOLIDAY and SUN_POS fail to compile without those globals. Workaround: a hand-authored libs/sources/oscat-basic/globals.st carries the VAR_GLOBAL block. The build script now appends any .st files in the lib's source dir to the imported sources, so supplements drop in without script changes. When the V3 GVL extractor is fixed, globals.st can be removed. Two POUs (DCF77, UTC_TO_LTIME) still get truncated mid-revision-history even with the boundary + stride-10 fixes — the importer drops the trailing portion entirely. They're filtered out at build time with a warning; CALENDAR_CALC is filtered transitively because its body calls UTC_TO_LTIME and would otherwise leave an unresolved C++ symbol. The new oscat-v3-library.test.ts pins the exclusion list so a future parser fix surfaces here as a "this test should be removed" signal. Net change vs the old archive: 8 POUs gained from the fresher v3 source (FLOW_CONTROL, SEQUENCE_64, SRAMP, TMAX, TMIN, TOF_1, TP_1, TP_1D), 3 lost to the importer regression. The auto-generated OSCAT g++ instantiation test now passes against the rebuilt archive. LibraryConfig schema gains optional `globalConstants?: Record`; OSCAT's library.json declares STRING_LENGTH=254 and LIST_LENGTH=254 there. Validator rejects non-finite or non-numeric values. rebuild-libs.mjs: - rebuildLibraryFromCodesys() runs the V3 importer over the .library file in the lib's source dir, then runs the same compile-and-write path the disk-backed libs use. - Drops POUs with unbalanced block comments + transitive callers. - Appends supplemental .st files (alphabetical) after the imported sources so they can reference imported TYPEs. vscode-extension/esbuild.mjs: previously did fs.cpSync(libs/, bundled-libs/, { recursive: true }) which would have copied the new libs/sources/ tree into every .vsix. Replaced with a selective top-level *.stlib copy. Tests: +18 in tests/library/oscat-v3-library.test.ts (identity, known-good FBs/functions/types, the new v3-only POUs, the intentionally-skipped POUs). codesys-import.test.ts updated to point the V3 importer test fixture at libs/sources/oscat-basic/oscat_basic_335.library. Suite: 1646 → 1664 (+18, no regressions). * fix(libs): improve V3 parser; revert OSCAT migration to round-trip The previous commit moved OSCAT to libs/sources/oscat-basic/ and tried to build it from the fresh CODESYS V3 .library file via the codesys-importer. That worked for ~99.6% of OSCAT (557/559 POUs) once the V3 parser bugs below were fixed, but covering the remaining 0.4% required a stack of build-time workarounds (drop list, transitive filter, hand-authored globals.st supplement) that the user correctly pushed back on as hacky. After deeper investigation I confirmed there are two genuine reverse-engineering gaps in the V3 parser that I can't close without significantly more time on the binary format. The parser improvements themselves are real and worth keeping; the OSCAT migration is reverted until the gaps are closed. V3 PARSER IMPROVEMENTS (kept): src/library/codesys-import/v3-parser.ts 1. Boundary record off-by-one. The implementation extraction loop used `i < boundary` and dropped the column-A varint of the boundary record itself, which is frequently the closing `*)` of a trailing block comment. Loop is now `i <= boundary`. This alone resolves about 390 OSCAT POUs that previously ended mid-comment and failed to recompile. 2. Stride-10 overflow in fat boundary records. When a POU's body is longer than ~127 lines, CODESYS packs the overflow into the boundary record itself, with additional impl lines at varint positions [0], [10], [20], … The parser now reads those stride-10 positions, recovering ~60-150 additional impl lines per long POU. This resolves the bulk of HOLIDAY, SEQUENCE_4/8, ESR_MON_B8, CRC_GEN, _ARRAY_SORT, SUN_POS and friends. KNOWN GAPS (documented in v3-parser.ts module header): 1. The very longest POUs (DCF77 / UTC_TO_LTIME, both with R62/R97 boundary records of 1484/616+ varints) transition from stride-10 to a non-uniform stride (~11) partway through. Pure stride-10 over-reads (junk shared strings from later rows leak in); pure `varint > maxCol0` filtering under-reads (drops legitimate-but- -shared lines like `END_IF;`, `ELSE`, `*)`). 2/559 POUs. 2. VAR_GLOBAL extraction misses OSCAT's GVL that instantiates LANGUAGE/MATH/PHYS/SETUP/LOCATION as instances of the CONSTANTS_* struct types (the struct TYPEs themselves are extracted cleanly). OSCAT REVERT: libs/oscat-basic.stlib stays tracked again (gitignore exception). libs/sources/oscat-basic/ removed; the V3 .library fixture is back at tests/fixtures/codesys/oscat_basic_335_codesys3.library and the V3-importer tests reference it from there. rebuild-libs.mjs uses the simple round-trip-from-archive path for OSCAT (read embedded sources, recompile, write back) — no filter list, no transitive drop, no hand-authored supplements. The other two libs (iec-standard-fb, additional-function-blocks) keep building from libs/sources/ as before. When the two V3-parser gaps above are closed, OSCAT can move to libs/sources/oscat-basic/ alongside the other libs; the gitignore exception is removed; and rebuildOscatFromArchive goes away. The new tests/library/oscat-v3-library.test.ts is dropped — it codified an exclusion list that no longer applies. Test suite: 1646 passing (no change from prior commit), all clean. * fix(codesys-v3): extract VAR_GLOBAL blocks (gap #2 of 2 closed) The V3 .library format encodes a GVL the same way as a POU at the structural level — a 4-varint header record carries the section keyword in column B (varint[1]), and subsequent records hold the body in column A. The keyword is the only difference: `FUNCTION` / `FUNCTION_BLOCK` / `PROGRAM` / `TYPE Foo :` / `VAR_GLOBAL` (optionally CONSTANT, RETAIN, PERSISTENT). The header-detection loop in extractFromRecords only matched the first four. GVL objects fell through and were silently dropped; the only remaining classification path (handleBareGVL) checks for "VAR_GLOBAL"-prefixed declarations, but at that point the declaration text has already been built without the header line, so it never matched either. Fix: add `GVL_DECL_RE.test(headerStr)` to the header-detection condition. The classifyPOU GVL branch then picks it up and emits a proper `GVL_N.gvl.st` source with VAR_GLOBAL header + body lines + END_VAR — exactly what compileStlib expects. Recovered for OSCAT 3.35: - GVL_0: VAR_GLOBAL CONSTANT (STRING_LENGTH=250, LIST_LENGTH=250) - GVL_1: VAR_GLOBAL (MATH/PHYS/LANGUAGE/SETUP/LOCATION instances of the CONSTANTS_* struct types — required for HOLIDAY, SUN_POS and the date-localisation helpers to compile) - GVL_2: VAR_GLOBAL PERSISTENT RETAIN (empty) - GVL_3: VAR_GLOBAL RETAIN (empty) Why the V2.3 importer caught these and V3 didn't: V2.3 stores source text inline in the binary so a regex sweep over the raw bytes (`/VAR_GLOBAL.../`) finds the GVL block directly. V3 stores source as indexed entries in a separate string table and references them from per-POU .object files; the text never appears contiguously in the binary, so a regex sweep wouldn't work even if we tried it. The V3 parser had to reach the same conclusion structurally — this commit adds that one missing keyword to the header detector. The remaining V3 reverse-engineering gap (long-impl boundary records transitioning from stride-10 to non-uniform stride for DCF77 / UTC_TO_LTIME) is unchanged. OSCAT's .stlib stays tracked until that's also resolved. Tests: +2 in tests/library/codesys-import.test.ts pinning the GVL extraction (the CONSTANTS_* instances and the STRING_LENGTH / LIST_LENGTH constants). Suite: 1648 passing (was 1646, no regressions). * feat(libs): 100% OSCAT V3 import + folder hierarchy in manifests Two related changes that together bring OSCAT fully onto the disk-source-of-truth pattern the other bundled libs already use, with the .library file as canonical source. V3 codesys-importer: - Replace fixed stride-10 boundary-record extraction with a row- delimiter algorithm (rows terminate on a 7+ zero run). Long OSCAT POUs (DCF77, UTC_TO_LTIME) shift from 10-wide rows to 11-wide partway through the trailing comment block; the previous code over-read into junk. - Use R0[5] as the authoritative impl line count instead of inferring from boundary record length. - Header detection accepts both n=4 col-1 (FB / PROGRAM / TYPE / GVL) and n=3 col-0 (FUNCTION) shapes. - VAR_GLOBAL CONSTANT integer blocks promote to compileStlib's globalConstants option (constexpr template parameters) instead of emitting a runtime GVL the codegen can't use as a template argument. Empty PERSISTENT RETAIN GVLs are dropped. - Folder hierarchy from .meta files now surfaces as ExtractedPOU.category (e.g. "POUs/Time&Date"). Library hierarchy (manifest-only — codegen unchanged): - LibraryFunctionEntry / LibraryFBEntry / LibraryTypeEntry gain an optional category field (slash-separated path, undefined = root). archive.sources entries mirror it so --decompile-lib can recreate the folder layout without re-parsing source. - compileLibrary regex-derives POU-name → category from input sources and tags emitted manifest entries. Sources stay flat in the archive; only metadata describes hierarchy. - rebuildLibraryFromDisk walks subfolders recursively; a file at libs/sources//some_category/foo.st gets category "some_category". Existing flat libs (iec-standard-fb, additional-function-blocks) emit no category fields, so their archives stay byte-identical to pre-hierarchy. - CLI --compile-lib derives categories from relative paths; --decompile-lib recreates the folder tree on disk. Flat archives extract flat (backwards compatible). OSCAT migration: - libs/sources/oscat-basic/ now holds the canonical .library file plus library.json (codesysSource + STRING_LENGTH/LIST_LENGTH overrides for runtime compatibility). rebuild-libs runs the importer at build time. - libs/oscat-basic.stlib is no longer tracked; the .gitignore exception is removed. Build pipeline (vitest globalSetup, npm run build) refreshes it from the V3 source. - Removed the 1.2 MB duplicate .library file from tests/fixtures/codesys/; tests reference the canonical copy under libs/sources/. Verified: 1653 tests pass, OSCAT extracts with zero warnings, DCF77 and UTC_TO_LTIME compile cleanly, decompile round-trip recreates the OSCAT folder tree (POUs/Time&Date/DCF77.st, POUs/Buffer Management/ BUFFER_COMP.st, etc.) exactly as CODESYS displays it. Co-Authored-By: Claude Opus 4.7 (1M context) * feat(libs): auto-extract inline documentation blocks into manifest CODESYS V3 .library files don't carry documentation as a separate field — but every OSCAT POU embeds a structured `(* version X.Y / programmer / tested by / description … *)` block right after its VAR sections, and the same convention exists in the .object decl records. Parse it during compileStlib and surface it as the manifest entry's `documentation` field, eliminating the need for a hand-curated `blocks: {}` / `functions: {}` doc map in library.json for any codesys-imported library. Library compiler: - `extractDocBlock(region)` finds the first `(* … *)` whose body contains version/programmer/tested-by trigger words, skipping inline variable annotations like `(* Laufvariable Stack *)` that some POUs put earlier in the source. - `buildDocByPouName` segments multi-POU sources at every top- level POU header (counter.st in iec-standard-fb concatenates 15 counter variants; each region needs its own doc lookup). - Both this and `buildCategoryByPouName` now uppercase their map keys to bridge the parser's identifier-canonicalization gap — OSCAT's `FT_Profile` source name becomes `FT_PROFILE` in the manifest, and the lookup must hit either spelling. library.json's existing `applyLibraryConfigDocumentation` post-step still runs, so a hand-curated documentation entry there overrides whatever the auto-extractor pulled from inline source. This keeps the override path open for translations or curated rewrites without regressing the auto-extraction win. Coverage on OSCAT: 545/545 manifest entries (100%) of FUNCTIONs and FUNCTION_BLOCKs gain documentation. Hand-authored libs without inline doc blocks (iec-standard-fb, additional-function-blocks) are unaffected — their library.json docs continue to apply unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) * fix(codesys-v3): structural doc extraction (drop trigger-word regex) The previous doc extractor scanned source text for `(* … *)` blocks containing OSCAT-style trigger words ("version", "programmer", "tested by"). That heuristic was content-based and fragile: any hand-authored library that didn't follow OSCAT's convention would miss out, and a body comment that happened to contain those words could be mis-tagged as documentation. CODESYS actually reserves a deterministic structural slot for the POU's variables-pane comment: the records of the .object decl sub-object that come AFTER the last `END_VAR` (FBs / FUNCs / PROGs) or `END_TYPE` (TYPEs). Body comments live in the impl sub-object so they cannot bleed into this slot, and inline variable annotations like `(* Laufvariable Stack *)` always sit BEFORE the last END_VAR so they cannot shadow the doc either. Whatever `(* … *)` block lives in that trailing decl slot IS the POU's documentation, regardless of what words it happens to contain. Switch the V3 importer to extract from this slot at the record level in `extractDocFromDeclRecords`. Documentation now flows from ExtractedPOU.documentation → pouToSources → compileLibrary's `source.documentation` field → manifest entries. The library compiler no longer scans source text at all; if `source.documentation` isn't set the entry stays undocumented (and library.json's `applyLibraryConfigDocumentation` post-step still applies as the override mechanism for hand-authored libs). Coverage on OSCAT (auto-extracted, no library.json doc map needed): - 373/373 FUNCTIONs - 172/172 FUNCTION_BLOCKs - 13/14 TYPEs (FRACTION ships with no trailing comment, correctly extracted as undocumented) Tests pin both the structural correctness and the anti-fragility: BUFFER_COMP starts its body with `(* search for first character match *)` and we verify that comment does NOT appear in its documentation field — the V3 record split keeps body comments out of the doc slot by construction. LibraryTypeEntry now also carries `documentation?: string` (was a schema gap — TYPEs had `category` but no doc field). Co-Authored-By: Claude Opus 4.7 (1M context) * feat(libs): add SEMA to iec-standard-fb (parity with MatIEC) MatIEC's iec_std_FB.h ships 23 standard function blocks but our iec-standard-fb library only carried 22 — SEMA was overlooked when the disk-source pattern was first set up. The implementation comes straight from MatIEC's lib/sema.txt verbatim (it's a 2-line latch on top of CLAIM / RELEASE inputs producing a BUSY output) and the documentation string matches what openplc-editor's standard-function-blocks.ts already exposes for SEMA. After this commit our standard FB lib matches MatIEC byte-for-byte: - bistable.st → SR, RS (2) - sema.st → SEMA (1) - edge_detection.st → R_TRIG, F_TRIG (2) - counter.st → CTU/CTD/CTUD × {base,DINT,LINT, UDINT,ULINT} (15) - timer.st → TP, TON, TOF (3) Total: 23 The additional-function-blocks library was already complete (DERIVATIVE, HYSTERESIS, INTEGRAL, PID, RAMP, RTC) — verified against MatIEC's *_st.txt + rtc.txt set, all six FBs and their docs were already present. Tests updated: archive-FB-count assertion bumped 22→23, SEMA added to the cross-validation source list, and a new IO-signature test pins SEMA's CLAIM/RELEASE inputs and BUSY output. Co-Authored-By: Claude Opus 4.7 (1M context) * feat(libs): synthesize iec-std-functions.stlib from StdFunctionRegistry The strucpp compiler bakes IEC 61131-3 standard functions (ADD/SUB/ MUX/SHL/CONCAT/SQRT/...) into a runtime registry — they're intrinsics, not compiled .stlib content. Editor tooling that wants to render "Arithmetic" / "BitShift" / "TypeConversion" / etc. as drag-and-drop library entries previously had to ship its own hand-mirrored copy of the registry. This commit makes the registry the canonical source: rebuild-libs walks `StdFunctionRegistry.getAll()` and emits a metadata-only .stlib (no sources, no codegen output) carrying every std function as a `LibraryFunctionEntry`. Tooling reads it through the same path it uses for compiled libraries — agnostic of where the manifest came from. Schema: - LibraryFunctionEntry gains `variadic?: { minArgs: number }` so variable-arg functions like ADD/MUL (≥ 2 operands) and MUX (≥ 2 inputs after a selector) survive the round-trip. - Generic-type names (ANY_NUM, ANY_INT, ANY_REAL, ANY_BIT, ANY_STRING, ANY_ELEMENTARY, ANY) flow through as bare strings; consumers unify by matching identical names across params and return type. The library-manifest docstring spells out the contract. Synthesis (scripts/rebuild-libs.mjs): - `synthesizeStdFunctionsLibrary` runs alongside the disk-backed and codesys-import paths. - Categories from the registry's lowercase identifiers (numeric/trig/arithmetic/...) map to capitalized display names (Numerical/Arithmetic/...) — both numeric and trig fold into "Numerical" since IEC 61131-3 groups them visually; the rest are one-to-one. - applyLibraryConfigDocumentation runs as a post-step, so libs/sources/iec-std-functions/library.json can ship a `functions: { ADD: { documentation: "..." } }` map later without touching this script. Output: libs/iec-std-functions.stlib carries 81 functions across 10 display categories (Numerical: 16, Arithmetic: 5, Selection: 6, Comparison: 6, Bitwise: 4, BitShift: 4, TypeConversion: 20, CharacterString: 9, Time: 6, System: 5). Co-Authored-By: Claude Opus 4.7 (1M context) * feat(libs): add displayName to library manifest Editor library trees and package-manager UIs need a human-readable label for each library — kebab-case identifiers like `iec-standard-fb` or `oscat-basic` work fine for filenames and dependency declarations but read poorly as folder titles in a drag-and-drop block picker. Add an optional `displayName` field that flows from `library.json` straight through to the compiled manifest. `displayName` is purely advisory metadata: when unset, consumers fall back to `name`, so existing .stlib archives that don't ship one serialize identically to the pre-displayName format. Bundled libraries: - iec-standard-fb → "Standard Function Blocks" - additional-function-blocks → "Additional Function Blocks" - oscat-basic → "OSCAT Basic" - iec-std-functions → "Standard Functions" Wired through both build paths: - rebuild-libs.mjs disk-backed and codesys-import paths set `manifest.displayName` from `config.displayName` after compile. - synthesizeStdFunctionsLibrary picks it up the same way. LibraryConfig validator accepts the new field as optional string; malformed values surface at build time alongside the existing schema errors. Co-Authored-By: Claude Opus 4.7 (1M context) * fix(codesys-v3): strip redundant top-level POUs/ prefix from categories CODESYS V3 libraries follow a fixed project-explorer convention: every code object (FUNCTION_BLOCK, FUNCTION, PROGRAM) lives under a top- level "POUs" folder, types under "Data types", globals under "Global Variables". When the archive is compiled into a single .stlib, the library itself becomes the POUs container — re-emitting the "POUs" folder inside it nests every block one level deeper than downstream tooling expects. OSCAT showed the symptom most loudly: the editor's library tree rendered OSCAT Basic POUs ← redundant Buffer Management Engineering/automation … instead of OSCAT Basic Buffer Management Engineering/automation … Strip the prefix in the V3 parser when assigning the per-POU `category`. POUs sitting directly under "POUs" with no subcategory become uncategorized (root-level under their library); deeper paths lose their leading segment. Other top-level folders pass through unchanged — "Data types" and "Global Variables" carry meaningful classification information that downstream tooling uses to render TYPEs / GVLs differently. Tests updated: the OSCAT folder-hierarchy assertion now expects `Time&Date` / `Buffer Management` / `Mathematical` / `Logic/Others` rather than the `POUs/`-prefixed versions, and explicitly rejects any surviving POUs prefix so a regression here surfaces immediately. Co-Authored-By: Claude Opus 4.7 (1M context) * fix(codegen): #undef SP in generated header to dodge AVR macro collision Compiling a project that pulled in additional-function-blocks for an AVR target failed with generated.hpp:169:14: error: expected unqualified-id before 'volatile' IEC_REAL SP; ^ `` defines `SP` as `(*(volatile uint8_t *)(0x3D))` for the AVR Stack Pointer; once the preprocessor sees PID's `IEC_REAL SP;` struct member, the field name expands into garbage and avr-gcc bails. Macros are global by definition and expand before namespace resolution, so neither namespace wrapping nor renaming the IEC variable inside the library would help — the user can't be expected to rename PID's standard `SP` setpoint pin to dodge a target-specific header. Add `#undef SP` next to the existing `#undef OVERFLOW` (math.h collision on macOS / glibc) in the generated header, after the runtime includes and before the namespace open. The undef is a no-op on platforms where the macro isn't defined, so it's safe unconditionally; conditional emission keyed on target keeps showing up as the wrong layer (codegen doesn't know whether the project will ultimately compile under avr-gcc or g++). Trigger: any project pulling in additional-function-blocks via the strucpp library system saw this on AVR builds because PID's struct declaration ends up in the project's generated.hpp regardless of whether PID itself is instantiated. Reported when adding an RTC FB to an Irrigation Controller project; RTC isn't the offender, but it caused the additional-function-blocks bundle to be linked, dragging PID along. Test added in tests/backend/codegen.test.ts pins the list of undef'd macros and their position in the header (after the last `#include`, before the namespace open) so a regression on either dimension surfaces here. Co-Authored-By: Claude Opus 4.7 (1M context) * fix(runtime): make CURRENT_DT() compile on AVR + add platform override avr-gcc's libstdc++ ships `` but omits `system_clock`, so the unconditional `system_clock::now()` in CURRENT_DT() failed to type-check on Arduino targets even when nothing in the user's program called CURRENT_DT(). Inline functions are still parsed, so the body needs to be valid for every target. Resolution priority CURRENT_DT() now follows (highest first): 1. `__CURRENT_DT_NS` when non-zero — the platform integration delivered a real wall-clock value (RTC chip, NTP, OpenPLC v4 runtime syscall wrapper, etc.). Honoured on every target. VPP packages targeting hardware with an RTC override (1) by writing `__CURRENT_DT_NS` from their platform glue; nothing else in the runtime needs to change. 2. std::chrono::system_clock on hosted targets — REPL, test runner, g++ builds without an explicit RTC. Same behaviour as before. 3. `__CURRENT_TIME_NS` (time since program start) on AVR. The scan-cycle clock the runtime already maintains is monotonic and advances per scan, so programs that diff two CURRENT_DT() readings still see meaningful elapsed time — just measured from boot rather than from the Unix epoch. Better than returning `IEC_DT(0)` (a fixed Unix epoch) which would make every diff come out as zero. The chrono path is excluded from compilation on AVR via `#ifdef __AVR__`, so even an `if (false)`-style runtime guard isn't enough — the body needs to be wholly absent on the target where the symbols don't exist. Co-Authored-By: Claude Opus 4.7 (1M context) * feat(types): canonical IEC base-type registry shipped as iec-types.json Hoist every IEC 61131-3 elementary-type fact (byte size, logical bit width, signedness, C++ alias, wire format, PLCopen TC6 XML mapping) into a single hand-authored TS module that's also emitted as libs/iec-types.json on every npm run build. Downstream tooling — the OpenPLC Editor's variables table / debugger / XML emitter, the future xml2st replacement — reads the JSON instead of maintaining its own type tables, eliminating the multi-source drift that surfaced when WSTRING was added on the strucpp side but never flowed through. In-repo, type-registry and type-utils now derive from the same source (removing two stale duplicates of the elementary-type list); the AST ELEMENTARY_TYPES map is built from the canonical registry's `bits` field so BOOL keeps its IEC-spec 1-bit logical width while every other type collapses to byteSize*8. Tests: a 38-case pin suite covers entry shape, byte/bit invariants, PLCopen XML naming convention, lookup helpers, and the on-disk JSON artefact staying in sync with IEC_BASE_TYPES. Co-Authored-By: Claude Opus 4.7 (1M context) * fix(types): strict STRING/WSTRING separation + nanosecond date literals Reported scenario: a WSTRING program variable initialised with a STRING literal (`'foo'`) silently produced broken C++: error: no matching function for call to 'IECWStringVar<254>::IECWStringVar(const char [22])' Per IEC 61131-3 the two literal kinds are NOT interchangeable — single quotes mean STRING, double quotes mean WSTRING. The bug had several layers; this commit closes all of them and adds the strict checking the standard implies. Frontend * AST builder: WSTRING (`"foo"`), DATE (`D#…`), TIME_OF_DAY (`TOD#…`), and DATE_AND_TIME (`DT#…`) literals were lexed but not built — they fell through to the default INT 0 branch and silently corrupted every downstream type check. Each gets its own LiteralExpression case now. Type-checker * New checkVarBlocks pass validates every variable initialiser against its declared type using the same `validateAssignment` used by AssignmentStatement. Without it, a STRING literal in a WSTRING declaration reached codegen unchecked. * type-utils canonicalises elementary names through the iec-types registry so DT ↔ DATE_AND_TIME and TOD ↔ TIME_OF_DAY are treated as the same type for assignability (they are aliases per the IEC standard, not separate types). Codegen * STRING literals → `"…"` (const char*), WSTRING literals → `u"…"` (const char16_t* — what IECWStringVar's string ctor binds to). `L"…"` (wchar_t) was wrong: 32-bit on Linux/AVR. * Default WSTRING declaration (no initialiser) emits `u""`. * DATE/TOD/DT literals were emitted as the raw IEC string verbatim (`TOD#12:00`) — invalid C++ and only "worked" by accident because the AST-builder gap fed 0 instead. Now parsed to int64 nanoseconds via new `parseDate/Tod/Dt LiteralToNs` helpers. Runtime * STRING_TO_WSTRING / WSTRING_TO_STRING (templated, plus aliases for the wrapped *Var types) — codepoint-by-codepoint transcoding in the BMP. Out-of-range codepoints get the documented lossy narrow rather than a hard failure. * iec_std_lib.hpp now `#include`s the string headers it depends on so the conversion templates are visible without callers pulling them in separately. Tests: a 10-case pin suite covers parser tagging, type-checker rejection of mismatches, codegen u/no-prefix emission, struct-field emission, and STRING_TO_WSTRING / WSTRING_TO_STRING resolution. Co-Authored-By: Claude Opus 4.7 (1M context) * feat(diagnostics): annotate CompileError with POU + section context Errors are emitted from many places (parser, AST builder, project model, semantic analyzer, codegen) all carrying just (line, column, file). Programmatic consumers like the OpenPLC Editor need richer location data: which POU, which section (var-block vs body), and a body-relative line number that matches what the user sees in Monaco. A single post-pass walks the AST after parsing/analysis, builds an interval table per POU, and decorates every error in place with the new fields. Standalone CLI use is unaffected — formatDiagnostic still prints the absolute (file, line) — but consumers reading the result get enough structure to route diagnostics into the right POU tab and remap body-line numbers without parsing error strings or doing their own AST walk. Var-block errors keep the file line directly (the editor's vars-text view aligns with the per-POU file's line numbering); body errors gain a bodyLine offset 1-indexed from the first body statement; var-block errors anchored at a specific declaration also gain variableName so editors can highlight the exact row. Tests cover the user-reported WSTRING-init scenario, plain body mismatches, multi-POU programs (one error per POU), and the defensive line=0 fall-through. Co-Authored-By: Claude Opus 4.7 (1M context) * fix(il): apply IL→ST transpilation to every additionalSources entry Phase 0 IL detection ran only on the primary source. The OpenPLC Editor's program.st splitter feeds per-POU files via additionalSources, and any of them can be IL — without this pass an IL POU like FUNCTION_BLOCK State_Display VAR State : INT; END_VAR LD State ST Out END_FUNCTION_BLOCK reaches the ST parser as raw IL and fails with the gigantic chevrotain "expecting one of these 1400 token sequences but found 'LD'" error that's almost impossible for users to read. Each additional source now goes through the same transpileILSource call as the primary, with errors attributed to the source's own fileName. Tests pin the multi-source IL case directly so a future refactor that re-introduces the gap fails loudly here. Co-Authored-By: Claude Opus 4.7 (1M context) * fix(diagnostics): prefer bodyLine over file line in formatDiagnostic The OpenPLC Editor's console renders a `[POU / body line N]` prefix above each error using the new POU-context fields, then prints strucpp's gcc-style snippet underneath. formatDiagnostic kept using the raw file line for both the header column (`Manual_Override.st:21`) and the snippet gutter (`21 |`), so the user saw two different line numbers for the same error: [MANUAL_OVERRIDE / body line 9] Manual_Override.st:21:10: error: ... 21 | asd := "hello world"; When `error.section === 'body'` and `error.bodyLine` is set, the header column and gutter both display `bodyLine` — the same number the user sees in Monaco — while the source content is still read from `error.line` (where the text physically lives in the per-POU file). For non-body errors the behaviour is unchanged: `error.line` flows through as before. Co-Authored-By: Claude Opus 4.7 (1M context) * fix(diagnostics): make body-line preference opt-in in formatDiagnostic The previous commit unconditionally swapped to bodyLine for body diagnostics, which would change line numbers for the strucpp CLI and the vscode-extension consumers — both of which want the absolute file line they've always reported. formatDiagnostic gains an optional third parameter `{ preferBodyLine?: boolean }`. Default `false` ⇒ existing callers (CLI, vscode-extension) see no behaviour change; pin tests added to prove the file-line rendering is unchanged when no option is passed. The OpenPLC Editor passes `{ preferBodyLine: true }` to get the Monaco-aligned numbering it already advertises in its bracketed POU prefix. Var-block errors are deliberately a no-op even with the flag set: their `line` already aligns with the editor's vars-text Monaco view. Co-Authored-By: Claude Opus 4.7 (1M context) * feat(library): introduce LibraryChunk type for per-symbol tree-shaking Phase 1 of function-level tree-shaking. Adds the chunked representation to the library type system so subsequent phases can populate and consume it incrementally without breaking existing emit paths. - `LibraryChunk` — one top-level symbol's contribution to the library's header + cpp output, plus its dep edges to other symbols. - `LibraryChunkDep` — a graph edge naming the owning library and the target symbol. Same-archive edges use the literal `"this"`. - `LibraryCompileResult.chunks` and `StlibArchive.chunks` — optional in Phase 1; populated from Phase 2, becomes authoritative in Phase 4 when the legacy `headerCode`/`cppCode` blob fields are retired. No runtime behaviour change: nothing emits or reads `chunks` yet. The type addition exists so Phase 2's compiler instrumentation and Phase 3's codegen shake can be developed against a real type rather than gradually-typed scaffolding. Verification: tsc clean, full vitest suite green (1724 passed). Co-Authored-By: Claude Opus 4.7 (1M context) * feat(codegen): emit chunk-boundary markers around top-level declarations Phase 2a of function-level tree-shaking. Adds an opt-in compile option that wraps each top-level emitted declaration with comment markers in both header and cpp output: //@chunk:begin:: ... declaration body ... //@chunk:end:: Kinds: `type` (struct/enum/alias), `inlineGlobal`, `functionBlock`, `function`. Programs are marked as `functionBlock` because their emitted shape matches an FB (class + per-TU implementation). Plumbed through: - `CompileOptions.emitChunkMarkers` — public surface flag, off by default - `CodeGenOptions.emitChunkMarkers` — internal flag forwarded to `TypeCodeGenOptions` so type-codegen can wrap each generated type - `emitHeaderChunkMarker` / `emitCppChunkMarker` — no-op when off The library compiler (Phase 2b) will turn this on and slice the emitted header/cpp into per-symbol chunks for the new `LibraryChunk[]` field. Production callers leave the flag off; their output is identical to before. Verification: - `tsc --noEmit` clean - Full vitest suite green (1724 passed) - Smoke test confirms markers appear when flag is on (6 header + 4 cpp markers for a small Type+FB+Program fixture) and stay absent when off. Co-Authored-By: Claude Opus 4.7 (1M context) * feat(library): extract per-symbol chunks + dep graph at library compile Phase 2b of function-level tree-shaking. With Phase 2a's chunk markers in place, the library compiler now slices emitted header/cpp into per-symbol chunks and computes the cross-symbol dep graph by walking the AST. New module `src/library/library-chunks.ts` owns three things: - `extractChunkSlices(code, eol)` parses the codegen markers in a single output stream into per-symbol text slices and returns the marker-stripped text for the legacy headerCode/cppCode blobs. - `buildChunks(header, cpp, eol, ast, libName, deps)` merges header and cpp slices by `:` key, preserves declaration order, and stitches each chunk together with its dep edges. - `computeChunkDeps` walks the chunk's AST subtree collecting `FunctionCallExpression`, `VariableExpression`, `TypeReference`, `FunctionBlockDeclaration.extends/implements`, and `InterfaceDeclaration.extends` references; resolves them through a symbol→library ownership map (built from the archive's own AST plus each declared dep's manifest); drops anything unresolved (built-ins, codegen-injected helpers); sorts deterministically. `compileLibrary` always enables chunk markers now (the option is internal to the codegen — production user compiles don't touch this path). After the compile, it builds the chunks, replaces the result's `headerCode`/`cppCode` with the marker-stripped text, and exposes the chunks on the result. `compileStlib` carries the chunks through into `StlibArchive.chunks`. Phase 4 will switch the consumer codegen to read these and retire the legacy blob fields. Verification: - 11 new vitest tests in `tests/library/library-chunks.test.ts` covering chunk extraction across all four kinds, intra-library type/function-call/global-read dep edges, cross-library dep edges, deterministic dep ordering, self-dep elimination, and marker-stripping of the archive blobs. - All 1735 tests pass (1724 existing + 11 new); no regressions. - Bundled libs auto-rebuilt with chunks via `rebuild-libs.mjs`'s pre-test setup: iec-standard-fb → 23 chunks (FBs) additional-function-blocks → 6 chunks oscat-basic → 564 chunks (172 FB + 373 fn + 14 type + 5 inline-global — MATH/PHYS/LANGUAGE/SETUP/LOCATION) iec-std-functions → 0 chunks (synthetic, no ST source) - Archive `headerCode`/`cppCode` blobs contain zero chunk markers. Co-Authored-By: Claude Opus 4.7 (1M context) * feat(codegen): function-level tree-shake — emit only reachable chunks Phase 3 of function-level tree-shaking. The consumer codegen now emits only the library chunks reachable from the user's AST, following the chunk dep graph baked into each archive at library compile time. Library-level inclusion (today's behaviour: enable oscat-basic = inline its entire ~7000-line C++ blob) is retired. New tree-shake driver in `src/index.ts`: - `collectUsedSymbols(ast, archives, includeEverything)` replaces `collectUsedLibraries`. Walks the user's AST collecting names from every cross-symbol reference kind (FunctionCallExpression, VariableExpression, TypeReference, FB extends/implements, InterfaceDeclaration extends). Resolves each name through a symbol→chunk index, BFS-traverses the chunk dep edges, and returns `Map>`. Test builds bypass the shake. New emission API on `CodeGenerator`: - `addLibraryChunks(archive, reachableNames)` replaces `addLibraryPreamble(name, headerCode, cppCode)`. Header and cpp emission loops iterate per-archive in load order; for each archive only chunks whose name appears in `reachable` are emitted, in `chunks[]` array order (= declaration order). FB chunks get a `class X;` forward decl emitted first so intra-library FB-to-FB references resolve regardless of declaration order. `library-loader.ts` carries the `chunks` field through `loadStlibArchive` (previously dropped during validation). Verification on bundled libs: - Program using only `TON`: headerCode = 1782 bytes TON: included; DRIVER_1, LANGUAGE, MATH, GEN_SIN: stripped - Program using only `DRIVER_1`: headerCode = 2268 bytes DRIVER_1 + TON (its declared dep): included OSCAT inline globals, OSCAT helpers: stripped This resolves the AVR per-variable-size error that previously prevented any project enabling OSCAT (`CONSTANTS_LANGUAGE`, `CONSTANTS_MATH`, etc. — 30–80 KB inline globals) from compiling on Mega targets, even when nothing referenced those globals. All 1735 tests pass; no regressions. Co-Authored-By: Claude Opus 4.7 (1M context) * refactor(library): retire legacy headerCode/cppCode blob fields Phase 4 of function-level tree-shaking — cleanup pass. With Phase 3 moving every consumer to chunk-based emission, the library-wide `headerCode` / `cppCode` blob fields on `StlibArchive` no longer serve any purpose: they're redundant with `chunks` (whose concatenation yields the same text) and offer no API the codegen still uses. Removed: - `StlibArchive.headerCode` and `StlibArchive.cppCode` fields. The archive carries `chunks` (now required, no longer optional) as its single source of compiled C++ output. - `compileStlib`'s `extractNamespaceBody` + `stripDependencyPreambles` post-processing. Chunks own only their own declaration's text by construction — there's no dependency-preamble code to strip because nothing inlines dependencies into a child library's output anymore. - `stripDependencyPreambles` helper from `library-utils.ts` (no callers). - `headerCode` / `cppCode` validators in `loadStlibArchive`. Replaced with a `chunks` array validator so a synthesised `.stlib` that forgets the field fails fast at load time instead of silently producing empty output downstream. Updated `scripts/rebuild-libs.mjs` so the synthetic `iec-std-functions` archive emits `chunks: []` (it has no codegen output — it's a pure manifest, the runtime ships the C++ implementations). Test fixtures and assertions migrated from the old blob shape to chunks (e.g. assert `chunks.length > 0` instead of `headerCode/cppCode` truthiness; assert concatenated chunk text contains expected symbols instead of grepping a blob). Tests that used to validate "rejects missing headerCode" / "rejects missing cppCode" collapsed into one "rejects missing chunks" check. The legacy `extractNamespaceBody` export stays — it's part of the public API and may still be useful for decompile / tooling consumers that work with the user's compile output (not library archives). Verification: 1734 tests pass; no regressions. One test count delta vs. Phase 3 is the headerCode+cppCode validator pair merging into a single chunks validator. Co-Authored-By: Claude Opus 4.7 (1M context) * test(library): chunk-shake correctness fuzz across all bundled libs Phase 5 of function-level tree-shaking — correctness gate. For every FB and every type chunk in every bundled library (oscat-basic, iec-standard-fb, additional-function-blocks), the fuzz synthesises a minimal `PROGRAM Main; VAR ... END_VAR; END_PROGRAM` that references that one symbol in isolation, then compiles with strucpp and asserts the compile succeeds. A failure means the chunk's dep edges (computed at library compile time by `collectReferencedNames`) missed something — most likely an implicit conversion, an IEC intrinsic dispatch path, or a transitive type referenced only inside a struct field. The remediation is in the extractor in `src/library/library-chunks.ts`, not in the fuzz. Coverage: - Every functionBlock chunk: standalone instance declaration - Every type chunk: standalone variable declaration - Function chunks and inline-global chunks intentionally skipped — they're transitively covered by FB / type fuzz (any FB or type that pulls a function / global pulls them through dep edges). Result: 218 fuzz cases pass. - 23 iec-standard-fb FBs - 6 additional-function-blocks FBs - 172 oscat-basic FBs - 14 oscat-basic types - 3 "library has at least one shake-relevant chunk" sanity assertions A `STANDALONE_EXEMPT` set is provided for symbols that legitimately can't be referenced standalone (abstract bases, types needing init args). Currently empty — every bundled symbol in the current library set is directly instantiable. Full suite: 1952 tests pass; no regressions. Co-Authored-By: Claude Opus 4.7 (1M context) * refactor(codegen): drop #undef SP — no longer reachable post-glue split `#undef SP` was guarding against `` redefining `SP` as the AVR stack-pointer register. After the Arduino-side runtime glue split (openplc-editor's arduino_runtime_glue.{cpp,h} + slimmed Baremetal.ino), no translation unit that parses `generated.hpp` also includes ``: - The Arduino .ino has `` (→ ``) but no longer includes `generated.hpp`. - Library-side .cpp files include `generated.hpp` but never pull `` (`openplc.h` is platform-clean; iec_*.hpp don't reach for AVR headers). - Runtime v4 and host test/REPL builds are Linux/Mac — `` isn't even on the include path. `SP` therefore never becomes a macro in any TU we emit into, and the undef is dead code. `#undef OVERFLOW` stays — it's still hit on every platform via `` → ``'s legacy SVID error constant. Test in `tests/backend/codegen.test.ts` updated to pin only the OVERFLOW undef + its placement (after includes, before namespace open). Verification: 1952 tests pass; no regressions. Co-Authored-By: Claude Opus 4.7 (1M context) * fix(codegen): generic std-fn calls with FB outputs + bare literals Two related codegen bugs that produced unbuildable C++ from valid IEC ST in the GARAGEDO_CTL test project: 1. `inferExprType` for `VariableExpression` ignored `fieldAccess`, so `CTU_UDINT2.CV` (UDINT output of a CTU_UDINT FB instance) inferred as `CTU_UDINT` — the FB type, not the field's element type. The downstream literal-cast in `harmonizeStdFuncArgs` then synthesised `static_cast(10)`, an alias that doesn't exist because FBs (unlike types) don't emit `IEC_` aliases. Fix: walk `fieldAccess` through `resolveMemberType`, returning the leaf field's type. 2. `harmonizeStdFuncArgs` skipped casting a bare literal whenever its inferred IEC type matched the dominant variable type (`MUL(int_var, 10)` where both inferred as INT). C++ template deduction still failed: the variable side lowers to `IECVar` while a bare literal lowers to raw `int` — distinct `T`s. Fix: always cast bare literals when paired with at least one IECVar argument, regardless of IEC-type match. Together these produce well-typed C++ for every pattern the GARAGEDO_CTL pou_WELL.cpp surfaced: DIV(CTU_UDINT2.CV, static_cast(10)) ← was IEC_CTU_UDINT DIV(CTU3.CV, static_cast(10)) ← was IEC_CTU MUL(WATER_METER_DR, static_cast(10)) ← was missing entirely Verification: 4 new regression tests in `tests/backend/codegen-functions.test.ts` cover both bugs across INT/UDINT and REAL operand types and both vanilla / library-FB sources. Full suite green (1956 passed, +4 from this change). Co-Authored-By: Claude Opus 4.7 (1M context) * refactor(codesys-import): drop unused headerCol tracking The header column index was captured and immediately discarded via `void headerCol;` — leftover from incremental development. The decl body walk only needs `headerRecIdx`. Co-Authored-By: Claude Opus 4.7 (1M context) --------- Co-authored-by: Claude Opus 4.7 (1M context) --- .gitignore | 19 + libs/iec-standard-fb.stlib | 666 - libs/oscat-basic.stlib | 18114 ---------------- .../additional-function-blocks/derivative.st | 33 + .../additional-function-blocks/hysteresis.st | 26 + .../additional-function-blocks/integral.st | 26 + .../additional-function-blocks/library.json | 28 + .../sources/additional-function-blocks/pid.st | 35 + .../additional-function-blocks/ramp.st | 38 + .../sources/additional-function-blocks/rtc.st | 53 + libs/sources/iec-standard-fb/bistable.st | 13 + libs/sources/iec-standard-fb/counter.st | 396 + .../sources/iec-standard-fb/edge_detection.st | 17 + libs/sources/iec-standard-fb/library.json | 79 + libs/sources/iec-standard-fb/sema.st | 18 + libs/sources/iec-standard-fb/timer.st | 121 + libs/sources/iec-std-functions/library.json | 8 + libs/sources/oscat-basic/library.json | 13 + .../oscat-basic/oscat_basic_335.library | Bin package.json | 7 +- scripts/build-iec-types-json.mjs | 70 + scripts/generate-additional-fb.mjs | 120 + scripts/generate-stdlib.mjs | 128 +- scripts/rebuild-libs.mjs | 477 +- src/backend/codegen.ts | 263 +- src/backend/type-codegen.ts | 44 +- src/cli.ts | 50 +- src/diagnostic-formatter.ts | 39 +- src/diagnostic-pou-context.ts | 228 + src/frontend/ast-builder.ts | 44 + src/index.ts | 239 +- .../codesys-import/codesys-importer.ts | 8 +- src/library/codesys-import/pou-formatter.ts | 33 +- src/library/codesys-import/types.ts | 23 + src/library/codesys-import/v3-parser.ts | 562 +- src/library/library-chunks.ts | 401 + src/library/library-compiler.ts | 307 +- src/library/library-config.ts | 252 + src/library/library-loader.ts | 18 +- src/library/library-manifest.ts | 149 +- src/library/library-utils.ts | 51 - src/project-model.ts | 74 + src/runtime/include/iec_std_lib.hpp | 135 + src/semantic/iec-types-data.ts | 377 + src/semantic/std-function-registry.ts | 15 + src/semantic/type-checker.ts | 125 + src/semantic/type-registry.ts | 36 +- src/semantic/type-utils.ts | 83 +- src/types.ts | 48 + tests/backend/codegen-functions.test.ts | 87 + .../backend/codegen-wstring-literals.test.ts | 175 + tests/backend/codegen.test.ts | 34 + tests/cli/cli-library.test.ts | 156 +- tests/diagnostic-formatter.test.ts | 75 + tests/diagnostic-pou-context.test.ts | 145 + tests/il/il-additional-sources.test.ts | 54 + tests/library/additional-fb-library.test.ts | 302 + tests/library/chunk-shake-fuzz.test.ts | 118 + tests/library/codesys-import.test.ts | 191 +- tests/library/library-chunks.test.ts | 332 + tests/library/library-config.test.ts | 287 + tests/library/library-system.test.ts | 86 +- tests/library/std-fb-library.test.ts | 79 +- tests/library/std-functions-library.test.ts | 146 + tests/semantic/date-time-arithmetic.test.ts | 148 + tests/semantic/iec-types-data.test.ts | 249 + vscode-extension/esbuild.mjs | 39 +- 67 files changed, 7478 insertions(+), 19334 deletions(-) delete mode 100644 libs/iec-standard-fb.stlib delete mode 100644 libs/oscat-basic.stlib create mode 100644 libs/sources/additional-function-blocks/derivative.st create mode 100644 libs/sources/additional-function-blocks/hysteresis.st create mode 100644 libs/sources/additional-function-blocks/integral.st create mode 100644 libs/sources/additional-function-blocks/library.json create mode 100644 libs/sources/additional-function-blocks/pid.st create mode 100644 libs/sources/additional-function-blocks/ramp.st create mode 100644 libs/sources/additional-function-blocks/rtc.st create mode 100644 libs/sources/iec-standard-fb/bistable.st create mode 100644 libs/sources/iec-standard-fb/counter.st create mode 100644 libs/sources/iec-standard-fb/edge_detection.st create mode 100644 libs/sources/iec-standard-fb/library.json create mode 100644 libs/sources/iec-standard-fb/sema.st create mode 100644 libs/sources/iec-standard-fb/timer.st create mode 100644 libs/sources/iec-std-functions/library.json create mode 100644 libs/sources/oscat-basic/library.json rename tests/fixtures/codesys/oscat_basic_335_codesys3.library => libs/sources/oscat-basic/oscat_basic_335.library (100%) create mode 100644 scripts/build-iec-types-json.mjs create mode 100644 scripts/generate-additional-fb.mjs create mode 100644 src/diagnostic-pou-context.ts create mode 100644 src/library/library-chunks.ts create mode 100644 src/library/library-config.ts create mode 100644 src/semantic/iec-types-data.ts create mode 100644 tests/backend/codegen-wstring-literals.test.ts create mode 100644 tests/diagnostic-pou-context.test.ts create mode 100644 tests/il/il-additional-sources.test.ts create mode 100644 tests/library/additional-fb-library.test.ts create mode 100644 tests/library/chunk-shake-fuzz.test.ts create mode 100644 tests/library/library-chunks.test.ts create mode 100644 tests/library/library-config.test.ts create mode 100644 tests/library/std-functions-library.test.ts create mode 100644 tests/semantic/date-time-arithmetic.test.ts create mode 100644 tests/semantic/iec-types-data.test.ts diff --git a/.gitignore b/.gitignore index cc760ec..efa752a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,25 @@ dist/ build/ *.tsbuildinfo +# Compiled library archives — the canonical source of truth lives in +# libs/sources// (.st files + library.json for hand-authored +# libs; .library binary + library.json for codesys-imported libs). The +# .stlib archives are produced by `npm run build` from those sources, +# so tracking them in git would just create stale-blob churn on every +# library or compiler change. Build flow: +# npm install && npm run build → generates libs/*.stlib +# CI rebuilds them before tests via vitest globalSetup; release jobs +# rebuild them as part of `npm run build`. +libs/*.stlib +# iec-types.json is a similar build artefact: derived from +# `src/semantic/iec-types-data.ts` by `scripts/build-iec-types-json.mjs`, +# so tracking it would just produce churn whenever the metadata changes. +libs/iec-types.json +# Extension-side copy is also a build artifact (vscode-extension's +# esbuild.mjs syncs it from libs/ at vsix build time). +vscode-extension/bundled-libs/*.stlib +vscode-extension/bundled-libs/iec-types.json + # IDE and editors .vscode/ .idea/ diff --git a/libs/iec-standard-fb.stlib b/libs/iec-standard-fb.stlib deleted file mode 100644 index 8181ae7..0000000 --- a/libs/iec-standard-fb.stlib +++ /dev/null @@ -1,666 +0,0 @@ -{ - "formatVersion": 1, - "manifest": { - "name": "iec-standard-fb", - "version": "1.0.0", - "namespace": "strucpp", - "functions": [], - "functionBlocks": [ - { - "name": "R_TRIG", - "inputs": [ - { - "name": "CLK", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "F_TRIG", - "inputs": [ - { - "name": "CLK", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "SR", - "inputs": [ - { - "name": "S1", - "type": "BOOL" - }, - { - "name": "R", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q1", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "RS", - "inputs": [ - { - "name": "S", - "type": "BOOL" - }, - { - "name": "R1", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q1", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "CTU", - "inputs": [ - { - "name": "CU", - "type": "BOOL" - }, - { - "name": "R", - "type": "BOOL" - }, - { - "name": "PV", - "type": "INT" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - }, - { - "name": "CV", - "type": "INT" - } - ], - "inouts": [] - }, - { - "name": "CTD", - "inputs": [ - { - "name": "CD", - "type": "BOOL" - }, - { - "name": "LD", - "type": "BOOL" - }, - { - "name": "PV", - "type": "INT" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - }, - { - "name": "CV", - "type": "INT" - } - ], - "inouts": [] - }, - { - "name": "CTUD", - "inputs": [ - { - "name": "CU", - "type": "BOOL" - }, - { - "name": "CD", - "type": "BOOL" - }, - { - "name": "R", - "type": "BOOL" - }, - { - "name": "LD", - "type": "BOOL" - }, - { - "name": "PV", - "type": "INT" - } - ], - "outputs": [ - { - "name": "QU", - "type": "BOOL" - }, - { - "name": "QD", - "type": "BOOL" - }, - { - "name": "CV", - "type": "INT" - } - ], - "inouts": [] - }, - { - "name": "CTU_DINT", - "inputs": [ - { - "name": "CU", - "type": "BOOL" - }, - { - "name": "R", - "type": "BOOL" - }, - { - "name": "PV", - "type": "DINT" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - }, - { - "name": "CV", - "type": "DINT" - } - ], - "inouts": [] - }, - { - "name": "CTU_LINT", - "inputs": [ - { - "name": "CU", - "type": "BOOL" - }, - { - "name": "R", - "type": "BOOL" - }, - { - "name": "PV", - "type": "LINT" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - }, - { - "name": "CV", - "type": "LINT" - } - ], - "inouts": [] - }, - { - "name": "CTU_UDINT", - "inputs": [ - { - "name": "CU", - "type": "BOOL" - }, - { - "name": "R", - "type": "BOOL" - }, - { - "name": "PV", - "type": "UDINT" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - }, - { - "name": "CV", - "type": "UDINT" - } - ], - "inouts": [] - }, - { - "name": "CTU_ULINT", - "inputs": [ - { - "name": "CU", - "type": "BOOL" - }, - { - "name": "R", - "type": "BOOL" - }, - { - "name": "PV", - "type": "ULINT" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - }, - { - "name": "CV", - "type": "ULINT" - } - ], - "inouts": [] - }, - { - "name": "CTD_DINT", - "inputs": [ - { - "name": "CD", - "type": "BOOL" - }, - { - "name": "LD", - "type": "BOOL" - }, - { - "name": "PV", - "type": "DINT" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - }, - { - "name": "CV", - "type": "DINT" - } - ], - "inouts": [] - }, - { - "name": "CTD_LINT", - "inputs": [ - { - "name": "CD", - "type": "BOOL" - }, - { - "name": "LD", - "type": "BOOL" - }, - { - "name": "PV", - "type": "LINT" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - }, - { - "name": "CV", - "type": "LINT" - } - ], - "inouts": [] - }, - { - "name": "CTD_UDINT", - "inputs": [ - { - "name": "CD", - "type": "BOOL" - }, - { - "name": "LD", - "type": "BOOL" - }, - { - "name": "PV", - "type": "UDINT" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - }, - { - "name": "CV", - "type": "UDINT" - } - ], - "inouts": [] - }, - { - "name": "CTD_ULINT", - "inputs": [ - { - "name": "CD", - "type": "BOOL" - }, - { - "name": "LD", - "type": "BOOL" - }, - { - "name": "PV", - "type": "ULINT" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - }, - { - "name": "CV", - "type": "ULINT" - } - ], - "inouts": [] - }, - { - "name": "CTUD_DINT", - "inputs": [ - { - "name": "CU", - "type": "BOOL" - }, - { - "name": "CD", - "type": "BOOL" - }, - { - "name": "R", - "type": "BOOL" - }, - { - "name": "LD", - "type": "BOOL" - }, - { - "name": "PV", - "type": "DINT" - } - ], - "outputs": [ - { - "name": "QU", - "type": "BOOL" - }, - { - "name": "QD", - "type": "BOOL" - }, - { - "name": "CV", - "type": "DINT" - } - ], - "inouts": [] - }, - { - "name": "CTUD_LINT", - "inputs": [ - { - "name": "CU", - "type": "BOOL" - }, - { - "name": "CD", - "type": "BOOL" - }, - { - "name": "R", - "type": "BOOL" - }, - { - "name": "LD", - "type": "BOOL" - }, - { - "name": "PV", - "type": "LINT" - } - ], - "outputs": [ - { - "name": "QU", - "type": "BOOL" - }, - { - "name": "QD", - "type": "BOOL" - }, - { - "name": "CV", - "type": "LINT" - } - ], - "inouts": [] - }, - { - "name": "CTUD_UDINT", - "inputs": [ - { - "name": "CU", - "type": "BOOL" - }, - { - "name": "CD", - "type": "BOOL" - }, - { - "name": "R", - "type": "BOOL" - }, - { - "name": "LD", - "type": "BOOL" - }, - { - "name": "PV", - "type": "UDINT" - } - ], - "outputs": [ - { - "name": "QU", - "type": "BOOL" - }, - { - "name": "QD", - "type": "BOOL" - }, - { - "name": "CV", - "type": "UDINT" - } - ], - "inouts": [] - }, - { - "name": "CTUD_ULINT", - "inputs": [ - { - "name": "CU", - "type": "BOOL" - }, - { - "name": "CD", - "type": "BOOL" - }, - { - "name": "R", - "type": "BOOL" - }, - { - "name": "LD", - "type": "BOOL" - }, - { - "name": "PV", - "type": "ULINT" - } - ], - "outputs": [ - { - "name": "QU", - "type": "BOOL" - }, - { - "name": "QD", - "type": "BOOL" - }, - { - "name": "CV", - "type": "ULINT" - } - ], - "inouts": [] - }, - { - "name": "TON", - "inputs": [ - { - "name": "IN", - "type": "BOOL" - }, - { - "name": "PT", - "type": "TIME" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - }, - { - "name": "ET", - "type": "TIME" - } - ], - "inouts": [] - }, - { - "name": "TOF", - "inputs": [ - { - "name": "IN", - "type": "BOOL" - }, - { - "name": "PT", - "type": "TIME" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - }, - { - "name": "ET", - "type": "TIME" - } - ], - "inouts": [] - }, - { - "name": "TP", - "inputs": [ - { - "name": "IN", - "type": "BOOL" - }, - { - "name": "PT", - "type": "TIME" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - }, - { - "name": "ET", - "type": "TIME" - } - ], - "inouts": [] - } - ], - "types": [], - "headers": [], - "isBuiltin": true, - "sourceFiles": [ - "edge_detection.st", - "bistable.st", - "counter.st", - "timer.st" - ], - "description": "IEC 61131-3 Standard Function Blocks (auto-generated from ST sources)" - }, - "headerCode": "\nclass R_TRIG;\nclass F_TRIG;\nclass SR;\nclass RS;\nclass CTU;\nclass CTD;\nclass CTUD;\nclass CTU_DINT;\nclass CTU_LINT;\nclass CTU_UDINT;\nclass CTU_ULINT;\nclass CTD_DINT;\nclass CTD_LINT;\nclass CTD_UDINT;\nclass CTD_ULINT;\nclass CTUD_DINT;\nclass CTUD_LINT;\nclass CTUD_UDINT;\nclass CTUD_ULINT;\nclass TON;\nclass TOF;\nclass TP;\n\nclass R_TRIG {\npublic:\n // Inputs\n IEC_BOOL CLK;\n // Outputs\n IEC_BOOL Q;\n // Local variables\n IEC_BOOL M;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n R_TRIG();\n\n // Execute function block\n void operator()();\n\n virtual ~R_TRIG() = default;\n};\n\nclass F_TRIG {\npublic:\n // Inputs\n IEC_BOOL CLK;\n // Outputs\n IEC_BOOL Q;\n // Local variables\n IEC_BOOL M;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n F_TRIG();\n\n // Execute function block\n void operator()();\n\n virtual ~F_TRIG() = default;\n};\n\nclass SR {\npublic:\n // Inputs\n IEC_BOOL S1;\n IEC_BOOL R;\n // Outputs\n IEC_BOOL Q1;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n SR();\n\n // Execute function block\n void operator()();\n\n virtual ~SR() = default;\n};\n\nclass RS {\npublic:\n // Inputs\n IEC_BOOL S;\n IEC_BOOL R1;\n // Outputs\n IEC_BOOL Q1;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n RS();\n\n // Execute function block\n void operator()();\n\n virtual ~RS() = default;\n};\n\nclass TON {\npublic:\n // Inputs\n IEC_BOOL IN;\n IEC_TIME PT;\n // Outputs\n IEC_BOOL Q;\n IEC_TIME ET;\n // Local variables\n IEC_SINT STATE;\n IEC_BOOL PREV_IN;\n IEC_TIME CURRENT_TIME;\n IEC_TIME START_TIME;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n TON();\n\n // Execute function block\n void operator()();\n\n virtual ~TON() = default;\n};\n\nclass TOF {\npublic:\n // Inputs\n IEC_BOOL IN;\n IEC_TIME PT;\n // Outputs\n IEC_BOOL Q;\n IEC_TIME ET;\n // Local variables\n IEC_SINT STATE;\n IEC_BOOL PREV_IN;\n IEC_TIME CURRENT_TIME;\n IEC_TIME START_TIME;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n TOF();\n\n // Execute function block\n void operator()();\n\n virtual ~TOF() = default;\n};\n\nclass TP {\npublic:\n // Inputs\n IEC_BOOL IN;\n IEC_TIME PT;\n // Outputs\n IEC_BOOL Q;\n IEC_TIME ET;\n // Local variables\n IEC_SINT STATE;\n IEC_BOOL PREV_IN;\n IEC_TIME CURRENT_TIME;\n IEC_TIME START_TIME;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n TP();\n\n // Execute function block\n void operator()();\n\n virtual ~TP() = default;\n};\n\nclass CTU {\npublic:\n // Inputs\n IEC_BOOL CU;\n IEC_BOOL R;\n IEC_INT PV;\n // Outputs\n IEC_BOOL Q;\n IEC_INT CV;\n // Local variables\n R_TRIG CU_T;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n CTU();\n\n // Execute function block\n void operator()();\n\n virtual ~CTU() = default;\n};\n\nclass CTU_DINT {\npublic:\n // Inputs\n IEC_BOOL CU;\n IEC_BOOL R;\n IEC_DINT PV;\n // Outputs\n IEC_BOOL Q;\n IEC_DINT CV;\n // Local variables\n R_TRIG CU_T;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n CTU_DINT();\n\n // Execute function block\n void operator()();\n\n virtual ~CTU_DINT() = default;\n};\n\nclass CTU_LINT {\npublic:\n // Inputs\n IEC_BOOL CU;\n IEC_BOOL R;\n IEC_LINT PV;\n // Outputs\n IEC_BOOL Q;\n IEC_LINT CV;\n // Local variables\n R_TRIG CU_T;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n CTU_LINT();\n\n // Execute function block\n void operator()();\n\n virtual ~CTU_LINT() = default;\n};\n\nclass CTU_UDINT {\npublic:\n // Inputs\n IEC_BOOL CU;\n IEC_BOOL R;\n IEC_UDINT PV;\n // Outputs\n IEC_BOOL Q;\n IEC_UDINT CV;\n // Local variables\n R_TRIG CU_T;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n CTU_UDINT();\n\n // Execute function block\n void operator()();\n\n virtual ~CTU_UDINT() = default;\n};\n\nclass CTU_ULINT {\npublic:\n // Inputs\n IEC_BOOL CU;\n IEC_BOOL R;\n IEC_ULINT PV;\n // Outputs\n IEC_BOOL Q;\n IEC_ULINT CV;\n // Local variables\n R_TRIG CU_T;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n CTU_ULINT();\n\n // Execute function block\n void operator()();\n\n virtual ~CTU_ULINT() = default;\n};\n\nclass CTD {\npublic:\n // Inputs\n IEC_BOOL CD;\n IEC_BOOL LD;\n IEC_INT PV;\n // Outputs\n IEC_BOOL Q;\n IEC_INT CV;\n // Local variables\n F_TRIG CD_T;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n CTD();\n\n // Execute function block\n void operator()();\n\n virtual ~CTD() = default;\n};\n\nclass CTUD {\npublic:\n // Inputs\n IEC_BOOL CU;\n IEC_BOOL CD;\n IEC_BOOL R;\n IEC_BOOL LD;\n IEC_INT PV;\n // Outputs\n IEC_BOOL QU;\n IEC_BOOL QD;\n IEC_INT CV;\n // Local variables\n R_TRIG CU_T;\n F_TRIG CD_T;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n CTUD();\n\n // Execute function block\n void operator()();\n\n virtual ~CTUD() = default;\n};\n\nclass CTD_DINT {\npublic:\n // Inputs\n IEC_BOOL CD;\n IEC_BOOL LD;\n IEC_DINT PV;\n // Outputs\n IEC_BOOL Q;\n IEC_DINT CV;\n // Local variables\n F_TRIG CD_T;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n CTD_DINT();\n\n // Execute function block\n void operator()();\n\n virtual ~CTD_DINT() = default;\n};\n\nclass CTD_LINT {\npublic:\n // Inputs\n IEC_BOOL CD;\n IEC_BOOL LD;\n IEC_LINT PV;\n // Outputs\n IEC_BOOL Q;\n IEC_LINT CV;\n // Local variables\n F_TRIG CD_T;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n CTD_LINT();\n\n // Execute function block\n void operator()();\n\n virtual ~CTD_LINT() = default;\n};\n\nclass CTD_UDINT {\npublic:\n // Inputs\n IEC_BOOL CD;\n IEC_BOOL LD;\n IEC_UDINT PV;\n // Outputs\n IEC_BOOL Q;\n IEC_UDINT CV;\n // Local variables\n F_TRIG CD_T;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n CTD_UDINT();\n\n // Execute function block\n void operator()();\n\n virtual ~CTD_UDINT() = default;\n};\n\nclass CTD_ULINT {\npublic:\n // Inputs\n IEC_BOOL CD;\n IEC_BOOL LD;\n IEC_ULINT PV;\n // Outputs\n IEC_BOOL Q;\n IEC_ULINT CV;\n // Local variables\n F_TRIG CD_T;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n CTD_ULINT();\n\n // Execute function block\n void operator()();\n\n virtual ~CTD_ULINT() = default;\n};\n\nclass CTUD_DINT {\npublic:\n // Inputs\n IEC_BOOL CU;\n IEC_BOOL CD;\n IEC_BOOL R;\n IEC_BOOL LD;\n IEC_DINT PV;\n // Outputs\n IEC_BOOL QU;\n IEC_BOOL QD;\n IEC_DINT CV;\n // Local variables\n R_TRIG CU_T;\n F_TRIG CD_T;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n CTUD_DINT();\n\n // Execute function block\n void operator()();\n\n virtual ~CTUD_DINT() = default;\n};\n\nclass CTUD_LINT {\npublic:\n // Inputs\n IEC_BOOL CU;\n IEC_BOOL CD;\n IEC_BOOL R;\n IEC_BOOL LD;\n IEC_LINT PV;\n // Outputs\n IEC_BOOL QU;\n IEC_BOOL QD;\n IEC_LINT CV;\n // Local variables\n R_TRIG CU_T;\n F_TRIG CD_T;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n CTUD_LINT();\n\n // Execute function block\n void operator()();\n\n virtual ~CTUD_LINT() = default;\n};\n\nclass CTUD_UDINT {\npublic:\n // Inputs\n IEC_BOOL CU;\n IEC_BOOL CD;\n IEC_BOOL R;\n IEC_BOOL LD;\n IEC_UDINT PV;\n // Outputs\n IEC_BOOL QU;\n IEC_BOOL QD;\n IEC_UDINT CV;\n // Local variables\n R_TRIG CU_T;\n F_TRIG CD_T;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n CTUD_UDINT();\n\n // Execute function block\n void operator()();\n\n virtual ~CTUD_UDINT() = default;\n};\n\nclass CTUD_ULINT {\npublic:\n // Inputs\n IEC_BOOL CU;\n IEC_BOOL CD;\n IEC_BOOL R;\n IEC_BOOL LD;\n IEC_ULINT PV;\n // Outputs\n IEC_BOOL QU;\n IEC_BOOL QD;\n IEC_ULINT CV;\n // Local variables\n R_TRIG CU_T;\n F_TRIG CD_T;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n CTUD_ULINT();\n\n // Execute function block\n void operator()();\n\n virtual ~CTUD_ULINT() = default;\n};\n", - "cppCode": "\n\nR_TRIG::R_TRIG() {\n // Initialize variables\n}\n\nvoid R_TRIG::operator()() {\n Q = (CLK) & (!M);\n M = CLK;\n}\n\n\nF_TRIG::F_TRIG()\n : M(true)\n{\n // Initialize variables\n}\n\nvoid F_TRIG::operator()() {\n Q = (!CLK) & (!M);\n M = !CLK;\n}\n\n\nSR::SR() {\n // Initialize variables\n}\n\nvoid SR::operator()() {\n Q1 = (S1) | ((((!R)) & (Q1)));\n}\n\n\nRS::RS() {\n // Initialize variables\n}\n\nvoid RS::operator()() {\n Q1 = ((!R1)) & (((S) | (Q1)));\n}\n\n\nTON::TON() {\n // Initialize variables\n}\n\nvoid TON::operator()() {\n CURRENT_TIME = TIME();\n if (((((STATE == 0)) & (NOT(PREV_IN))) & (IN))) {\n STATE = 1;\n Q = false;\n START_TIME = CURRENT_TIME;\n } else {\n if ((NOT(IN))) {\n ET = 0LL;\n Q = false;\n STATE = 0;\n } else if ((STATE == 1)) {\n if (((START_TIME + PT) <= CURRENT_TIME)) {\n STATE = 2;\n Q = true;\n ET = PT;\n } else {\n ET = CURRENT_TIME - START_TIME;\n }\n }\n }\n PREV_IN = IN;\n}\n\n\nTOF::TOF() {\n // Initialize variables\n}\n\nvoid TOF::operator()() {\n CURRENT_TIME = TIME();\n if (((((STATE == 0)) & (PREV_IN)) & (NOT(IN)))) {\n STATE = 1;\n START_TIME = CURRENT_TIME;\n } else {\n if ((IN)) {\n ET = 0LL;\n Q = true;\n STATE = 0;\n } else if ((STATE == 1)) {\n if (((START_TIME + PT) <= CURRENT_TIME)) {\n STATE = 2;\n Q = false;\n ET = PT;\n } else {\n Q = true;\n ET = CURRENT_TIME - START_TIME;\n }\n }\n }\n PREV_IN = IN;\n}\n\n\nTP::TP() {\n // Initialize variables\n}\n\nvoid TP::operator()() {\n CURRENT_TIME = TIME();\n if (((((STATE == 0)) & (NOT(PREV_IN))) & (IN))) {\n STATE = 1;\n Q = true;\n START_TIME = CURRENT_TIME;\n } else if ((STATE == 1)) {\n if (((START_TIME + PT) <= CURRENT_TIME)) {\n STATE = 2;\n Q = false;\n ET = PT;\n } else {\n ET = CURRENT_TIME - START_TIME;\n }\n }\n if (((NOT(IN)) & ((STATE == 2)))) {\n STATE = 0;\n ET = 0LL;\n }\n PREV_IN = IN;\n}\n\n\nCTU::CTU() {\n // Initialize variables\n}\n\nvoid CTU::operator()() {\n CU_T.CLK = CU;\n CU_T();\n CU_T.ENO = true;\n if (R) {\n CV = 0;\n } else if ((CU_T.Q) & ((CV < PV))) {\n CV = CV + 1;\n }\n Q = (CV >= PV);\n}\n\n\nCTU_DINT::CTU_DINT() {\n // Initialize variables\n}\n\nvoid CTU_DINT::operator()() {\n CU_T.CLK = CU;\n CU_T();\n CU_T.ENO = true;\n if (R) {\n CV = 0;\n } else if ((CU_T.Q) & ((CV < PV))) {\n CV = CV + 1;\n }\n Q = (CV >= PV);\n}\n\n\nCTU_LINT::CTU_LINT() {\n // Initialize variables\n}\n\nvoid CTU_LINT::operator()() {\n CU_T.CLK = CU;\n CU_T();\n CU_T.ENO = true;\n if (R) {\n CV = 0;\n } else if ((CU_T.Q) & ((CV < PV))) {\n CV = CV + 1;\n }\n Q = (CV >= PV);\n}\n\n\nCTU_UDINT::CTU_UDINT() {\n // Initialize variables\n}\n\nvoid CTU_UDINT::operator()() {\n CU_T.CLK = CU;\n CU_T();\n CU_T.ENO = true;\n if (R) {\n CV = 0;\n } else if ((CU_T.Q) & ((CV < PV))) {\n CV = CV + 1;\n }\n Q = (CV >= PV);\n}\n\n\nCTU_ULINT::CTU_ULINT() {\n // Initialize variables\n}\n\nvoid CTU_ULINT::operator()() {\n CU_T.CLK = CU;\n CU_T();\n CU_T.ENO = true;\n if (R) {\n CV = 0;\n } else if ((CU_T.Q) & ((CV < PV))) {\n CV = CV + 1;\n }\n Q = (CV >= PV);\n}\n\n\nCTD::CTD() {\n // Initialize variables\n}\n\nvoid CTD::operator()() {\n CD_T.CLK = CD;\n CD_T();\n CD_T.ENO = true;\n if (LD) {\n CV = PV;\n } else if ((CD_T.Q) & ((CV > 0))) {\n CV = CV - 1;\n }\n Q = (CV <= 0);\n}\n\n\nCTUD::CTUD() {\n // Initialize variables\n}\n\nvoid CTUD::operator()() {\n CU_T.CLK = CU;\n CU_T();\n CU_T.ENO = true;\n CD_T.CLK = CD;\n CD_T();\n CD_T.ENO = true;\n if (R) {\n CV = 0;\n } else if (LD) {\n CV = PV;\n } else {\n if ((CU_T.Q) & ((CV < PV))) {\n CV = CV + 1;\n }\n if ((CD_T.Q) & ((CV > 0))) {\n CV = CV - 1;\n }\n }\n QU = (CV >= PV);\n QD = (CV <= 0);\n}\n\n\nCTD_DINT::CTD_DINT() {\n // Initialize variables\n}\n\nvoid CTD_DINT::operator()() {\n CD_T.CLK = CD;\n CD_T();\n CD_T.ENO = true;\n if (LD) {\n CV = PV;\n } else if ((CD_T.Q) & ((CV > 0))) {\n CV = CV - 1;\n }\n Q = (CV <= 0);\n}\n\n\nCTD_LINT::CTD_LINT() {\n // Initialize variables\n}\n\nvoid CTD_LINT::operator()() {\n CD_T.CLK = CD;\n CD_T();\n CD_T.ENO = true;\n if (LD) {\n CV = PV;\n } else if ((CD_T.Q) & ((CV > 0))) {\n CV = CV - 1;\n }\n Q = (CV <= 0);\n}\n\n\nCTD_UDINT::CTD_UDINT() {\n // Initialize variables\n}\n\nvoid CTD_UDINT::operator()() {\n CD_T.CLK = CD;\n CD_T();\n CD_T.ENO = true;\n if (LD) {\n CV = PV;\n } else if ((CD_T.Q) & ((CV > 0))) {\n CV = CV - 1;\n }\n Q = (CV <= 0);\n}\n\n\nCTD_ULINT::CTD_ULINT() {\n // Initialize variables\n}\n\nvoid CTD_ULINT::operator()() {\n CD_T.CLK = CD;\n CD_T();\n CD_T.ENO = true;\n if (LD) {\n CV = PV;\n } else if ((CD_T.Q) & ((CV > 0))) {\n CV = CV - 1;\n }\n Q = (CV <= 0);\n}\n\n\nCTUD_DINT::CTUD_DINT() {\n // Initialize variables\n}\n\nvoid CTUD_DINT::operator()() {\n CU_T.CLK = CU;\n CU_T();\n CU_T.ENO = true;\n CD_T.CLK = CD;\n CD_T();\n CD_T.ENO = true;\n if (R) {\n CV = 0;\n } else if (LD) {\n CV = PV;\n } else {\n if ((CU_T.Q) & ((CV < PV))) {\n CV = CV + 1;\n }\n if ((CD_T.Q) & ((CV > 0))) {\n CV = CV - 1;\n }\n }\n QU = (CV >= PV);\n QD = (CV <= 0);\n}\n\n\nCTUD_LINT::CTUD_LINT() {\n // Initialize variables\n}\n\nvoid CTUD_LINT::operator()() {\n CU_T.CLK = CU;\n CU_T();\n CU_T.ENO = true;\n CD_T.CLK = CD;\n CD_T();\n CD_T.ENO = true;\n if (R) {\n CV = 0;\n } else if (LD) {\n CV = PV;\n } else {\n if ((CU_T.Q) & ((CV < PV))) {\n CV = CV + 1;\n }\n if ((CD_T.Q) & ((CV > 0))) {\n CV = CV - 1;\n }\n }\n QU = (CV >= PV);\n QD = (CV <= 0);\n}\n\n\nCTUD_UDINT::CTUD_UDINT() {\n // Initialize variables\n}\n\nvoid CTUD_UDINT::operator()() {\n CU_T.CLK = CU;\n CU_T();\n CU_T.ENO = true;\n CD_T.CLK = CD;\n CD_T();\n CD_T.ENO = true;\n if (R) {\n CV = 0;\n } else if (LD) {\n CV = PV;\n } else {\n if ((CU_T.Q) & ((CV < PV))) {\n CV = CV + 1;\n }\n if ((CD_T.Q) & ((CV > 0))) {\n CV = CV - 1;\n }\n }\n QU = (CV >= PV);\n QD = (CV <= 0);\n}\n\n\nCTUD_ULINT::CTUD_ULINT() {\n // Initialize variables\n}\n\nvoid CTUD_ULINT::operator()() {\n CU_T.CLK = CU;\n CU_T();\n CU_T.ENO = true;\n CD_T.CLK = CD;\n CD_T();\n CD_T.ENO = true;\n if (R) {\n CV = 0;\n } else if (LD) {\n CV = PV;\n } else {\n if ((CU_T.Q) & ((CV < PV))) {\n CV = CV + 1;\n }\n if ((CD_T.Q) & ((CV > 0))) {\n CV = CV - 1;\n }\n }\n QU = (CV >= PV);\n QD = (CV <= 0);\n}\n", - "dependencies": [], - "sources": [ - { - "fileName": "edge_detection.st", - "source": "(* IEC 61131-3 Standard Function Blocks: Edge Detection *)\n\nFUNCTION_BLOCK R_TRIG\n VAR_INPUT CLK : BOOL; END_VAR\n VAR_OUTPUT Q : BOOL; END_VAR\n VAR RETAIN M : BOOL; END_VAR\n Q := CLK AND NOT M;\n M := CLK;\nEND_FUNCTION_BLOCK\n\nFUNCTION_BLOCK F_TRIG\n VAR_INPUT CLK : BOOL; END_VAR\n VAR_OUTPUT Q : BOOL; END_VAR\n VAR RETAIN M : BOOL := TRUE; END_VAR\n Q := NOT CLK AND NOT M;\n M := NOT CLK;\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "bistable.st", - "source": "(* IEC 61131-3 Standard Function Blocks: Bistable Latches *)\n\nFUNCTION_BLOCK SR\n VAR_INPUT S1, R : BOOL; END_VAR\n VAR_OUTPUT Q1 : BOOL; END_VAR\n Q1 := S1 OR ((NOT R) AND Q1);\nEND_FUNCTION_BLOCK\n\nFUNCTION_BLOCK RS\n VAR_INPUT S, R1 : BOOL; END_VAR\n VAR_OUTPUT Q1 : BOOL; END_VAR\n Q1 := (NOT R1) AND (S OR Q1);\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "counter.st", - "source": "(* IEC 61131-3 Standard Function Blocks: Counters *)\n\nFUNCTION_BLOCK CTU\n VAR_INPUT\n CU : BOOL;\n R : BOOL;\n PV : INT;\n END_VAR\n VAR_OUTPUT\n Q : BOOL;\n CV : INT;\n END_VAR\n VAR\n CU_T : R_TRIG;\n END_VAR\n CU_T(CLK := CU);\n IF R THEN\n CV := 0;\n ELSIF CU_T.Q AND (CV < PV) THEN\n CV := CV + 1;\n END_IF;\n Q := (CV >= PV);\nEND_FUNCTION_BLOCK\n\nFUNCTION_BLOCK CTD\n VAR_INPUT\n CD : BOOL;\n LD : BOOL;\n PV : INT;\n END_VAR\n VAR_OUTPUT\n Q : BOOL;\n CV : INT;\n END_VAR\n VAR\n CD_T : F_TRIG;\n END_VAR\n CD_T(CLK := CD);\n IF LD THEN\n CV := PV;\n ELSIF CD_T.Q AND (CV > 0) THEN\n CV := CV - 1;\n END_IF;\n Q := (CV <= 0);\nEND_FUNCTION_BLOCK\n\nFUNCTION_BLOCK CTUD\n VAR_INPUT\n CU : BOOL;\n CD : BOOL;\n R : BOOL;\n LD : BOOL;\n PV : INT;\n END_VAR\n VAR_OUTPUT\n QU : BOOL;\n QD : BOOL;\n CV : INT;\n END_VAR\n VAR\n CU_T : R_TRIG;\n CD_T : F_TRIG;\n END_VAR\n CU_T(CLK := CU);\n CD_T(CLK := CD);\n IF R THEN\n CV := 0;\n ELSIF LD THEN\n CV := PV;\n ELSE\n IF CU_T.Q AND (CV < PV) THEN\n CV := CV + 1;\n END_IF;\n IF CD_T.Q AND (CV > 0) THEN\n CV := CV - 1;\n END_IF;\n END_IF;\n QU := (CV >= PV);\n QD := (CV <= 0);\nEND_FUNCTION_BLOCK\n\nFUNCTION_BLOCK CTU_DINT\n VAR_INPUT\n CU : BOOL;\n R : BOOL;\n PV : DINT;\n END_VAR\n VAR_OUTPUT\n Q : BOOL;\n CV : DINT;\n END_VAR\n VAR\n CU_T : R_TRIG;\n END_VAR\n CU_T(CLK := CU);\n IF R THEN\n CV := 0;\n ELSIF CU_T.Q AND (CV < PV) THEN\n CV := CV + 1;\n END_IF;\n Q := (CV >= PV);\nEND_FUNCTION_BLOCK\n\nFUNCTION_BLOCK CTU_LINT\n VAR_INPUT\n CU : BOOL;\n R : BOOL;\n PV : LINT;\n END_VAR\n VAR_OUTPUT\n Q : BOOL;\n CV : LINT;\n END_VAR\n VAR\n CU_T : R_TRIG;\n END_VAR\n CU_T(CLK := CU);\n IF R THEN\n CV := 0;\n ELSIF CU_T.Q AND (CV < PV) THEN\n CV := CV + 1;\n END_IF;\n Q := (CV >= PV);\nEND_FUNCTION_BLOCK\n\nFUNCTION_BLOCK CTU_UDINT\n VAR_INPUT\n CU : BOOL;\n R : BOOL;\n PV : UDINT;\n END_VAR\n VAR_OUTPUT\n Q : BOOL;\n CV : UDINT;\n END_VAR\n VAR\n CU_T : R_TRIG;\n END_VAR\n CU_T(CLK := CU);\n IF R THEN\n CV := 0;\n ELSIF CU_T.Q AND (CV < PV) THEN\n CV := CV + 1;\n END_IF;\n Q := (CV >= PV);\nEND_FUNCTION_BLOCK\n\nFUNCTION_BLOCK CTU_ULINT\n VAR_INPUT\n CU : BOOL;\n R : BOOL;\n PV : ULINT;\n END_VAR\n VAR_OUTPUT\n Q : BOOL;\n CV : ULINT;\n END_VAR\n VAR\n CU_T : R_TRIG;\n END_VAR\n CU_T(CLK := CU);\n IF R THEN\n CV := 0;\n ELSIF CU_T.Q AND (CV < PV) THEN\n CV := CV + 1;\n END_IF;\n Q := (CV >= PV);\nEND_FUNCTION_BLOCK\n\nFUNCTION_BLOCK CTD_DINT\n VAR_INPUT\n CD : BOOL;\n LD : BOOL;\n PV : DINT;\n END_VAR\n VAR_OUTPUT\n Q : BOOL;\n CV : DINT;\n END_VAR\n VAR\n CD_T : F_TRIG;\n END_VAR\n CD_T(CLK := CD);\n IF LD THEN\n CV := PV;\n ELSIF CD_T.Q AND (CV > 0) THEN\n CV := CV - 1;\n END_IF;\n Q := (CV <= 0);\nEND_FUNCTION_BLOCK\n\nFUNCTION_BLOCK CTD_LINT\n VAR_INPUT\n CD : BOOL;\n LD : BOOL;\n PV : LINT;\n END_VAR\n VAR_OUTPUT\n Q : BOOL;\n CV : LINT;\n END_VAR\n VAR\n CD_T : F_TRIG;\n END_VAR\n CD_T(CLK := CD);\n IF LD THEN\n CV := PV;\n ELSIF CD_T.Q AND (CV > 0) THEN\n CV := CV - 1;\n END_IF;\n Q := (CV <= 0);\nEND_FUNCTION_BLOCK\n\nFUNCTION_BLOCK CTD_UDINT\n VAR_INPUT\n CD : BOOL;\n LD : BOOL;\n PV : UDINT;\n END_VAR\n VAR_OUTPUT\n Q : BOOL;\n CV : UDINT;\n END_VAR\n VAR\n CD_T : F_TRIG;\n END_VAR\n CD_T(CLK := CD);\n IF LD THEN\n CV := PV;\n ELSIF CD_T.Q AND (CV > 0) THEN\n CV := CV - 1;\n END_IF;\n Q := (CV <= 0);\nEND_FUNCTION_BLOCK\n\nFUNCTION_BLOCK CTD_ULINT\n VAR_INPUT\n CD : BOOL;\n LD : BOOL;\n PV : ULINT;\n END_VAR\n VAR_OUTPUT\n Q : BOOL;\n CV : ULINT;\n END_VAR\n VAR\n CD_T : F_TRIG;\n END_VAR\n CD_T(CLK := CD);\n IF LD THEN\n CV := PV;\n ELSIF CD_T.Q AND (CV > 0) THEN\n CV := CV - 1;\n END_IF;\n Q := (CV <= 0);\nEND_FUNCTION_BLOCK\n\nFUNCTION_BLOCK CTUD_DINT\n VAR_INPUT\n CU : BOOL;\n CD : BOOL;\n R : BOOL;\n LD : BOOL;\n PV : DINT;\n END_VAR\n VAR_OUTPUT\n QU : BOOL;\n QD : BOOL;\n CV : DINT;\n END_VAR\n VAR\n CU_T : R_TRIG;\n CD_T : F_TRIG;\n END_VAR\n CU_T(CLK := CU);\n CD_T(CLK := CD);\n IF R THEN\n CV := 0;\n ELSIF LD THEN\n CV := PV;\n ELSE\n IF CU_T.Q AND (CV < PV) THEN\n CV := CV + 1;\n END_IF;\n IF CD_T.Q AND (CV > 0) THEN\n CV := CV - 1;\n END_IF;\n END_IF;\n QU := (CV >= PV);\n QD := (CV <= 0);\nEND_FUNCTION_BLOCK\n\nFUNCTION_BLOCK CTUD_LINT\n VAR_INPUT\n CU : BOOL;\n CD : BOOL;\n R : BOOL;\n LD : BOOL;\n PV : LINT;\n END_VAR\n VAR_OUTPUT\n QU : BOOL;\n QD : BOOL;\n CV : LINT;\n END_VAR\n VAR\n CU_T : R_TRIG;\n CD_T : F_TRIG;\n END_VAR\n CU_T(CLK := CU);\n CD_T(CLK := CD);\n IF R THEN\n CV := 0;\n ELSIF LD THEN\n CV := PV;\n ELSE\n IF CU_T.Q AND (CV < PV) THEN\n CV := CV + 1;\n END_IF;\n IF CD_T.Q AND (CV > 0) THEN\n CV := CV - 1;\n END_IF;\n END_IF;\n QU := (CV >= PV);\n QD := (CV <= 0);\nEND_FUNCTION_BLOCK\n\nFUNCTION_BLOCK CTUD_UDINT\n VAR_INPUT\n CU : BOOL;\n CD : BOOL;\n R : BOOL;\n LD : BOOL;\n PV : UDINT;\n END_VAR\n VAR_OUTPUT\n QU : BOOL;\n QD : BOOL;\n CV : UDINT;\n END_VAR\n VAR\n CU_T : R_TRIG;\n CD_T : F_TRIG;\n END_VAR\n CU_T(CLK := CU);\n CD_T(CLK := CD);\n IF R THEN\n CV := 0;\n ELSIF LD THEN\n CV := PV;\n ELSE\n IF CU_T.Q AND (CV < PV) THEN\n CV := CV + 1;\n END_IF;\n IF CD_T.Q AND (CV > 0) THEN\n CV := CV - 1;\n END_IF;\n END_IF;\n QU := (CV >= PV);\n QD := (CV <= 0);\nEND_FUNCTION_BLOCK\n\nFUNCTION_BLOCK CTUD_ULINT\n VAR_INPUT\n CU : BOOL;\n CD : BOOL;\n R : BOOL;\n LD : BOOL;\n PV : ULINT;\n END_VAR\n VAR_OUTPUT\n QU : BOOL;\n QD : BOOL;\n CV : ULINT;\n END_VAR\n VAR\n CU_T : R_TRIG;\n CD_T : F_TRIG;\n END_VAR\n CU_T(CLK := CU);\n CD_T(CLK := CD);\n IF R THEN\n CV := 0;\n ELSIF LD THEN\n CV := PV;\n ELSE\n IF CU_T.Q AND (CV < PV) THEN\n CV := CV + 1;\n END_IF;\n IF CD_T.Q AND (CV > 0) THEN\n CV := CV - 1;\n END_IF;\n END_IF;\n QU := (CV >= PV);\n QD := (CV <= 0);\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "timer.st", - "source": "(* IEC 61131-3 Standard Function Blocks: Timers *)\n(* Uses TIME() built-in function for current time (CODESYS-compatible) *)\n\nFUNCTION_BLOCK TON\n VAR_INPUT\n IN : BOOL;\n PT : TIME;\n END_VAR\n VAR_OUTPUT\n Q : BOOL;\n ET : TIME;\n END_VAR\n VAR\n STATE : SINT;\n PREV_IN : BOOL;\n CURRENT_TIME, START_TIME : TIME;\n END_VAR\n\n CURRENT_TIME := TIME();\n\n IF ((STATE = 0) AND NOT(PREV_IN) AND IN) THEN\n STATE := 1;\n Q := FALSE;\n START_TIME := CURRENT_TIME;\n ELSE\n IF (NOT(IN)) THEN\n ET := T#0s;\n Q := FALSE;\n STATE := 0;\n ELSIF (STATE = 1) THEN\n IF ((START_TIME + PT) <= CURRENT_TIME) THEN\n STATE := 2;\n Q := TRUE;\n ET := PT;\n ELSE\n ET := CURRENT_TIME - START_TIME;\n END_IF;\n END_IF;\n END_IF;\n\n PREV_IN := IN;\nEND_FUNCTION_BLOCK\n\nFUNCTION_BLOCK TOF\n VAR_INPUT\n IN : BOOL;\n PT : TIME;\n END_VAR\n VAR_OUTPUT\n Q : BOOL;\n ET : TIME;\n END_VAR\n VAR\n STATE : SINT;\n PREV_IN : BOOL;\n CURRENT_TIME, START_TIME : TIME;\n END_VAR\n\n CURRENT_TIME := TIME();\n\n IF ((STATE = 0) AND PREV_IN AND NOT(IN)) THEN\n STATE := 1;\n START_TIME := CURRENT_TIME;\n ELSE\n IF (IN) THEN\n ET := T#0s;\n Q := TRUE;\n STATE := 0;\n ELSIF (STATE = 1) THEN\n IF ((START_TIME + PT) <= CURRENT_TIME) THEN\n STATE := 2;\n Q := FALSE;\n ET := PT;\n ELSE\n Q := TRUE;\n ET := CURRENT_TIME - START_TIME;\n END_IF;\n END_IF;\n END_IF;\n\n PREV_IN := IN;\nEND_FUNCTION_BLOCK\n\nFUNCTION_BLOCK TP\n VAR_INPUT\n IN : BOOL;\n PT : TIME;\n END_VAR\n VAR_OUTPUT\n Q : BOOL;\n ET : TIME;\n END_VAR\n VAR\n STATE : SINT;\n PREV_IN : BOOL;\n CURRENT_TIME, START_TIME : TIME;\n END_VAR\n\n CURRENT_TIME := TIME();\n\n IF ((STATE = 0) AND NOT(PREV_IN) AND IN) THEN\n STATE := 1;\n Q := TRUE;\n START_TIME := CURRENT_TIME;\n ELSIF (STATE = 1) THEN\n IF ((START_TIME + PT) <= CURRENT_TIME) THEN\n STATE := 2;\n Q := FALSE;\n ET := PT;\n ELSE\n ET := CURRENT_TIME - START_TIME;\n END_IF;\n END_IF;\n\n IF (NOT(IN) AND (STATE = 2)) THEN\n STATE := 0;\n ET := T#0s;\n END_IF;\n\n PREV_IN := IN;\nEND_FUNCTION_BLOCK\n" - } - ] -} diff --git a/libs/oscat-basic.stlib b/libs/oscat-basic.stlib deleted file mode 100644 index c1919d9..0000000 --- a/libs/oscat-basic.stlib +++ /dev/null @@ -1,18114 +0,0 @@ -{ - "formatVersion": 1, - "manifest": { - "name": "oscat-basic", - "version": "335.0.0", - "namespace": "oscat_basic", - "functions": [ - { - "name": "ACOSH", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "ACOTH", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "AGDF", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "AIN", - "returnType": "REAL", - "parameters": [ - { - "name": "IN", - "type": "DWORD", - "direction": "input" - }, - { - "name": "BITS", - "type": "BYTE", - "direction": "input" - }, - { - "name": "SIGN", - "type": "BYTE", - "direction": "input" - }, - { - "name": "LOW", - "type": "REAL", - "direction": "input" - }, - { - "name": "HIGH", - "type": "REAL", - "direction": "input" - }, - { - "name": "FF", - "type": "DWORD", - "direction": "input" - }, - { - "name": "TEMP1", - "type": "DWORD", - "direction": "input" - }, - { - "name": "TEMP2", - "type": "DWORD", - "direction": "input" - }, - { - "name": "SX", - "type": "BOOL", - "direction": "input" - } - ] - }, - { - "name": "AOUT", - "returnType": "DWORD", - "parameters": [ - { - "name": "IN", - "type": "REAL", - "direction": "input" - }, - { - "name": "BITS", - "type": "BYTE", - "direction": "input" - }, - { - "name": "SIGN", - "type": "BYTE", - "direction": "input" - }, - { - "name": "LOW", - "type": "REAL", - "direction": "input" - }, - { - "name": "HIGH", - "type": "REAL", - "direction": "input" - }, - { - "name": "FF", - "type": "DWORD", - "direction": "input" - }, - { - "name": "IN2", - "type": "REAL", - "direction": "input" - }, - { - "name": "SX", - "type": "BOOL", - "direction": "input" - } - ] - }, - { - "name": "AOUT1", - "returnType": "DWORD", - "parameters": [ - { - "name": "IN", - "type": "REAL", - "direction": "input" - }, - { - "name": "BIT_0", - "type": "INT", - "direction": "input" - }, - { - "name": "BIT_N", - "type": "INT", - "direction": "input" - }, - { - "name": "SIGN", - "type": "INT", - "direction": "input" - }, - { - "name": "LOW", - "type": "REAL", - "direction": "input" - }, - { - "name": "HIGH", - "type": "REAL", - "direction": "input" - }, - { - "name": "FF", - "type": "DWORD", - "direction": "input" - }, - { - "name": "SX", - "type": "BOOL", - "direction": "input" - }, - { - "name": "IN2", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "ARRAY_AVG", - "returnType": "REAL", - "parameters": [ - { - "name": "PT", - "type": "__INLINE_ARRAY_REAL", - "direction": "input" - }, - { - "name": "SIZE", - "type": "UINT", - "direction": "input" - }, - { - "name": "I", - "type": "UINT", - "direction": "input" - }, - { - "name": "STOP", - "type": "UINT", - "direction": "input" - } - ] - }, - { - "name": "ARRAY_GAV", - "returnType": "REAL", - "parameters": [ - { - "name": "PT", - "type": "__INLINE_ARRAY_REAL", - "direction": "input" - }, - { - "name": "SIZE", - "type": "UINT", - "direction": "input" - }, - { - "name": "I", - "type": "UINT", - "direction": "input" - }, - { - "name": "STOP", - "type": "UINT", - "direction": "input" - } - ] - }, - { - "name": "ARRAY_HAV", - "returnType": "REAL", - "parameters": [ - { - "name": "PT", - "type": "__INLINE_ARRAY_REAL", - "direction": "input" - }, - { - "name": "SIZE", - "type": "UINT", - "direction": "input" - }, - { - "name": "I", - "type": "UINT", - "direction": "input" - }, - { - "name": "STOP", - "type": "UINT", - "direction": "input" - } - ] - }, - { - "name": "ARRAY_MAX", - "returnType": "REAL", - "parameters": [ - { - "name": "PT", - "type": "__INLINE_ARRAY_REAL", - "direction": "input" - }, - { - "name": "SIZE", - "type": "UINT", - "direction": "input" - }, - { - "name": "I", - "type": "UINT", - "direction": "input" - }, - { - "name": "STOP", - "type": "UINT", - "direction": "input" - } - ] - }, - { - "name": "ARRAY_MIN", - "returnType": "REAL", - "parameters": [ - { - "name": "PT", - "type": "__INLINE_ARRAY_REAL", - "direction": "input" - }, - { - "name": "SIZE", - "type": "UINT", - "direction": "input" - }, - { - "name": "I", - "type": "UINT", - "direction": "input" - }, - { - "name": "STOP", - "type": "UINT", - "direction": "input" - } - ] - }, - { - "name": "ARRAY_SDV", - "returnType": "REAL", - "parameters": [ - { - "name": "PT", - "type": "__INLINE_ARRAY_REAL", - "direction": "input" - }, - { - "name": "SIZE", - "type": "UINT", - "direction": "input" - } - ] - }, - { - "name": "ARRAY_SPR", - "returnType": "REAL", - "parameters": [ - { - "name": "PT", - "type": "__INLINE_ARRAY_REAL", - "direction": "input" - }, - { - "name": "SIZE", - "type": "UINT", - "direction": "input" - }, - { - "name": "I", - "type": "UINT", - "direction": "input" - }, - { - "name": "STOP", - "type": "UINT", - "direction": "input" - }, - { - "name": "ARRAY_MAX", - "type": "REAL", - "direction": "input" - }, - { - "name": "ARRAY_MIN", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "ARRAY_SUM", - "returnType": "REAL", - "parameters": [ - { - "name": "PT", - "type": "__INLINE_ARRAY_REAL", - "direction": "input" - }, - { - "name": "SIZE", - "type": "UINT", - "direction": "input" - }, - { - "name": "I", - "type": "UINT", - "direction": "input" - }, - { - "name": "STOP", - "type": "UINT", - "direction": "input" - } - ] - }, - { - "name": "ARRAY_TREND", - "returnType": "REAL", - "parameters": [ - { - "name": "PT", - "type": "__INLINE_ARRAY_REAL", - "direction": "input" - }, - { - "name": "SIZE", - "type": "UINT", - "direction": "input" - }, - { - "name": "I", - "type": "UINT", - "direction": "input" - }, - { - "name": "STOP", - "type": "UINT", - "direction": "input" - }, - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "STOP2", - "type": "UINT", - "direction": "input" - } - ] - }, - { - "name": "ARRAY_VAR", - "returnType": "REAL", - "parameters": [ - { - "name": "PT", - "type": "__INLINE_ARRAY_REAL", - "direction": "input" - }, - { - "name": "SIZE", - "type": "UINT", - "direction": "input" - }, - { - "name": "AVG", - "type": "REAL", - "direction": "input" - }, - { - "name": "I", - "type": "UINT", - "direction": "input" - }, - { - "name": "STOP", - "type": "UINT", - "direction": "input" - } - ] - }, - { - "name": "ASINH", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "ATAN2", - "returnType": "REAL", - "parameters": [ - { - "name": "Y", - "type": "REAL", - "direction": "input" - }, - { - "name": "X", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "ATANH", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "BAND_B", - "returnType": "BYTE", - "parameters": [ - { - "name": "X", - "type": "BYTE", - "direction": "input" - }, - { - "name": "B", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "BCDC_TO_INT", - "returnType": "INT", - "parameters": [ - { - "name": "IN", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "BETA", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "Y", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "BFT_TO_MS", - "returnType": "REAL", - "parameters": [ - { - "name": "BFT", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "BINOM", - "returnType": "DINT", - "parameters": [ - { - "name": "N", - "type": "INT", - "direction": "input" - }, - { - "name": "K", - "type": "INT", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "BIN_TO_BYTE", - "returnType": "BYTE", - "parameters": [ - { - "name": "BIN", - "type": "STRING", - "direction": "input" - }, - { - "name": "PT", - "type": "BYTE", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - }, - { - "name": "X", - "type": "BYTE", - "direction": "input" - }, - { - "name": "STOP", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "BIN_TO_DWORD", - "returnType": "DWORD", - "parameters": [ - { - "name": "BIN", - "type": "STRING", - "direction": "input" - }, - { - "name": "PT", - "type": "BYTE", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - }, - { - "name": "X", - "type": "BYTE", - "direction": "input" - }, - { - "name": "STOP", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "BIT_COUNT", - "returnType": "INT", - "parameters": [ - { - "name": "IN", - "type": "DWORD", - "direction": "input" - } - ] - }, - { - "name": "BIT_LOAD_B", - "returnType": "BYTE", - "parameters": [ - { - "name": "IN", - "type": "BYTE", - "direction": "input" - }, - { - "name": "VAL", - "type": "BOOL", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "DAT", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "BIT_LOAD_B2", - "returnType": "BYTE", - "parameters": [ - { - "name": "I", - "type": "BYTE", - "direction": "input" - }, - { - "name": "D", - "type": "BOOL", - "direction": "input" - }, - { - "name": "P", - "type": "INT", - "direction": "input" - }, - { - "name": "N", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "BIT_LOAD_DW", - "returnType": "DWORD", - "parameters": [ - { - "name": "IN", - "type": "DWORD", - "direction": "input" - }, - { - "name": "VAL", - "type": "BOOL", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "DAT", - "type": "DWORD", - "direction": "input" - } - ] - }, - { - "name": "BIT_LOAD_DW2", - "returnType": "DWORD", - "parameters": [ - { - "name": "I", - "type": "DWORD", - "direction": "input" - }, - { - "name": "D", - "type": "BOOL", - "direction": "input" - }, - { - "name": "P", - "type": "INT", - "direction": "input" - }, - { - "name": "N", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "BIT_LOAD_W", - "returnType": "WORD", - "parameters": [ - { - "name": "IN", - "type": "WORD", - "direction": "input" - }, - { - "name": "VAL", - "type": "BOOL", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "DAT", - "type": "WORD", - "direction": "input" - } - ] - }, - { - "name": "BIT_LOAD_W2", - "returnType": "WORD", - "parameters": [ - { - "name": "I", - "type": "WORD", - "direction": "input" - }, - { - "name": "D", - "type": "BOOL", - "direction": "input" - }, - { - "name": "P", - "type": "INT", - "direction": "input" - }, - { - "name": "N", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "BIT_OF_DWORD", - "returnType": "BOOL", - "parameters": [ - { - "name": "IN", - "type": "DWORD", - "direction": "input" - }, - { - "name": "N", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "BIT_TOGGLE_B", - "returnType": "BYTE", - "parameters": [ - { - "name": "IN", - "type": "BYTE", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "BIT_TOGGLE_DW", - "returnType": "DWORD", - "parameters": [ - { - "name": "IN", - "type": "DWORD", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "BIT_TOGGLE_W", - "returnType": "WORD", - "parameters": [ - { - "name": "IN", - "type": "WORD", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "BUFFER_COMP", - "returnType": "INT", - "parameters": [ - { - "name": "PT1", - "type": "__INLINE_ARRAY_BYTE", - "direction": "input" - }, - { - "name": "SIZE1", - "type": "INT", - "direction": "input" - }, - { - "name": "PT2", - "type": "__INLINE_ARRAY_BYTE", - "direction": "input" - }, - { - "name": "SIZE2", - "type": "INT", - "direction": "input" - }, - { - "name": "START", - "type": "INT", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - }, - { - "name": "J", - "type": "INT", - "direction": "input" - }, - { - "name": "END", - "type": "INT", - "direction": "input" - }, - { - "name": "FIRSTBYTE", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "BUFFER_SEARCH", - "returnType": "INT", - "parameters": [ - { - "name": "PT", - "type": "__INLINE_ARRAY_BYTE", - "direction": "input" - }, - { - "name": "SIZE", - "type": "INT", - "direction": "input" - }, - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "IGN", - "type": "BOOL", - "direction": "input" - }, - { - "name": "PS", - "type": "__INLINE_ARRAY_BYTE", - "direction": "input" - }, - { - "name": "CHX", - "type": "BYTE", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - }, - { - "name": "END", - "type": "INT", - "direction": "input" - }, - { - "name": "K", - "type": "INT", - "direction": "input" - }, - { - "name": "LX", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "BUFFER_TO_STRING", - "returnType": "STRING", - "parameters": [ - { - "name": "PT", - "type": "__INLINE_ARRAY_BYTE", - "direction": "input" - }, - { - "name": "SIZE", - "type": "UINT", - "direction": "input" - }, - { - "name": "START", - "type": "UINT", - "direction": "input" - }, - { - "name": "STOP", - "type": "UINT", - "direction": "input" - }, - { - "name": "PS", - "type": "BYTE", - "direction": "input" - }, - { - "name": "I", - "type": "UINT", - "direction": "input" - }, - { - "name": "STP", - "type": "UINT", - "direction": "input" - }, - { - "name": "STA", - "type": "UINT", - "direction": "input" - } - ] - }, - { - "name": "BYTE_OF_BIT", - "returnType": "BYTE", - "parameters": [ - { - "name": "B0", - "type": "BOOL", - "direction": "input" - }, - { - "name": "B1", - "type": "BOOL", - "direction": "input" - }, - { - "name": "B2", - "type": "BOOL", - "direction": "input" - }, - { - "name": "B3", - "type": "BOOL", - "direction": "input" - }, - { - "name": "B4", - "type": "BOOL", - "direction": "input" - }, - { - "name": "B5", - "type": "BOOL", - "direction": "input" - }, - { - "name": "B6", - "type": "BOOL", - "direction": "input" - }, - { - "name": "B7", - "type": "BOOL", - "direction": "input" - } - ] - }, - { - "name": "BYTE_OF_DWORD", - "returnType": "BYTE", - "parameters": [ - { - "name": "IN", - "type": "DWORD", - "direction": "input" - }, - { - "name": "N", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "BYTE_TO_GRAY", - "returnType": "BYTE", - "parameters": [ - { - "name": "IN", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "BYTE_TO_RANGE", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "BYTE", - "direction": "input" - }, - { - "name": "LOW", - "type": "REAL", - "direction": "input" - }, - { - "name": "HIGH", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "BYTE_TO_STRB", - "returnType": "STRING", - "parameters": [ - { - "name": "IN", - "type": "BYTE", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - }, - { - "name": "PT", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "BYTE_TO_STRH", - "returnType": "STRING", - "parameters": [ - { - "name": "IN", - "type": "BYTE", - "direction": "input" - }, - { - "name": "TEMP", - "type": "BYTE", - "direction": "input" - }, - { - "name": "PT", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "CABS", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "COMPLEX", - "direction": "input" - } - ] - }, - { - "name": "CACOS", - "returnType": "COMPLEX", - "parameters": [ - { - "name": "X", - "type": "COMPLEX", - "direction": "input" - }, - { - "name": "Y", - "type": "COMPLEX", - "direction": "input" - } - ] - }, - { - "name": "CACOSH", - "returnType": "COMPLEX", - "parameters": [ - { - "name": "X", - "type": "COMPLEX", - "direction": "input" - }, - { - "name": "Y", - "type": "COMPLEX", - "direction": "input" - } - ] - }, - { - "name": "CADD", - "returnType": "COMPLEX", - "parameters": [ - { - "name": "X", - "type": "COMPLEX", - "direction": "input" - }, - { - "name": "Y", - "type": "COMPLEX", - "direction": "input" - } - ] - }, - { - "name": "CAPITALIZE", - "returnType": "STRING", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "PT", - "type": "BYTE", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "L", - "type": "INT", - "direction": "input" - }, - { - "name": "FIRST", - "type": "BOOL", - "direction": "input" - } - ] - }, - { - "name": "CARG", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "COMPLEX", - "direction": "input" - } - ] - }, - { - "name": "CASIN", - "returnType": "COMPLEX", - "parameters": [ - { - "name": "X", - "type": "COMPLEX", - "direction": "input" - }, - { - "name": "Y", - "type": "COMPLEX", - "direction": "input" - } - ] - }, - { - "name": "CASINH", - "returnType": "COMPLEX", - "parameters": [ - { - "name": "X", - "type": "COMPLEX", - "direction": "input" - }, - { - "name": "Y", - "type": "COMPLEX", - "direction": "input" - } - ] - }, - { - "name": "CATAN", - "returnType": "COMPLEX", - "parameters": [ - { - "name": "X", - "type": "COMPLEX", - "direction": "input" - }, - { - "name": "R2", - "type": "REAL", - "direction": "input" - }, - { - "name": "NUM", - "type": "REAL", - "direction": "input" - }, - { - "name": "DEN", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "CATANH", - "returnType": "COMPLEX", - "parameters": [ - { - "name": "X", - "type": "COMPLEX", - "direction": "input" - }, - { - "name": "I2", - "type": "REAL", - "direction": "input" - }, - { - "name": "NUM", - "type": "REAL", - "direction": "input" - }, - { - "name": "DEN", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "CAUCHY", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "T", - "type": "REAL", - "direction": "input" - }, - { - "name": "U", - "type": "REAL", - "direction": "input" - }, - { - "name": "TMP", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "CAUCHYCD", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "T", - "type": "REAL", - "direction": "input" - }, - { - "name": "U", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "CCON", - "returnType": "COMPLEX", - "parameters": [ - { - "name": "X", - "type": "COMPLEX", - "direction": "input" - } - ] - }, - { - "name": "CCOS", - "returnType": "COMPLEX", - "parameters": [ - { - "name": "X", - "type": "COMPLEX", - "direction": "input" - } - ] - }, - { - "name": "CCOSH", - "returnType": "COMPLEX", - "parameters": [ - { - "name": "X", - "type": "COMPLEX", - "direction": "input" - } - ] - }, - { - "name": "CDIV", - "returnType": "COMPLEX", - "parameters": [ - { - "name": "X", - "type": "COMPLEX", - "direction": "input" - }, - { - "name": "Y", - "type": "COMPLEX", - "direction": "input" - }, - { - "name": "TEMP", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "CEIL", - "returnType": "INT", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "CEIL2", - "returnType": "DINT", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "CEXP", - "returnType": "COMPLEX", - "parameters": [ - { - "name": "X", - "type": "COMPLEX", - "direction": "input" - }, - { - "name": "TEMP", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "CHARCODE", - "returnType": "BYTE", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "FOUND", - "type": "STRING", - "direction": "input" - }, - { - "name": "SEARCH", - "type": "STRING", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "CHARNAME", - "returnType": "STRING", - "parameters": [ - { - "name": "C", - "type": "BYTE", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "CHECK_PARITY", - "returnType": "BOOL", - "parameters": [ - { - "name": "IN", - "type": "DWORD", - "direction": "input" - }, - { - "name": "P", - "type": "BOOL", - "direction": "input" - } - ] - }, - { - "name": "CHK_REAL", - "returnType": "BYTE", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "PT", - "type": "DWORD", - "direction": "input" - }, - { - "name": "TMP", - "type": "DWORD", - "direction": "input" - } - ] - }, - { - "name": "CHR_TO_STRING", - "returnType": "STRING", - "parameters": [ - { - "name": "C", - "type": "BYTE", - "direction": "input" - }, - { - "name": "PT", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "CINV", - "returnType": "COMPLEX", - "parameters": [ - { - "name": "X", - "type": "COMPLEX", - "direction": "input" - }, - { - "name": "TEMP", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "CIRCLE_A", - "returnType": "REAL", - "parameters": [ - { - "name": "RX", - "type": "REAL", - "direction": "input" - }, - { - "name": "AX", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "CIRCLE_C", - "returnType": "REAL", - "parameters": [ - { - "name": "RX", - "type": "REAL", - "direction": "input" - }, - { - "name": "AX", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "CIRCLE_SEG", - "returnType": "REAL", - "parameters": [ - { - "name": "RX", - "type": "REAL", - "direction": "input" - }, - { - "name": "HX", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "CLEAN", - "returnType": "STRING", - "parameters": [ - { - "name": "IN", - "type": "STRING", - "direction": "input" - }, - { - "name": "CX", - "type": "STRING", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "STOP", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "CLOG", - "returnType": "COMPLEX", - "parameters": [ - { - "name": "X", - "type": "COMPLEX", - "direction": "input" - } - ] - }, - { - "name": "CMP", - "returnType": "BOOL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "Y", - "type": "REAL", - "direction": "input" - }, - { - "name": "N", - "type": "INT", - "direction": "input" - }, - { - "name": "TMP", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "CMUL", - "returnType": "COMPLEX", - "parameters": [ - { - "name": "X", - "type": "COMPLEX", - "direction": "input" - }, - { - "name": "Y", - "type": "COMPLEX", - "direction": "input" - } - ] - }, - { - "name": "CODE", - "returnType": "BYTE", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "PT", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "CONE_V", - "returnType": "REAL", - "parameters": [ - { - "name": "RX", - "type": "REAL", - "direction": "input" - }, - { - "name": "HX", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "COSH", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "T", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "COTH", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "COUNT_CHAR", - "returnType": "INT", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "CHR", - "type": "BYTE", - "direction": "input" - }, - { - "name": "L", - "type": "INT", - "direction": "input" - }, - { - "name": "PT", - "type": "BYTE", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "COUNT_SUBSTRING", - "returnType": "INT", - "parameters": [ - { - "name": "SEARCH", - "type": "STRING", - "direction": "input" - }, - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "SIZE", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "CPOL", - "returnType": "COMPLEX", - "parameters": [ - { - "name": "L", - "type": "REAL", - "direction": "input" - }, - { - "name": "A", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "CPOW", - "returnType": "COMPLEX", - "parameters": [ - { - "name": "X", - "type": "COMPLEX", - "direction": "input" - }, - { - "name": "Y", - "type": "COMPLEX", - "direction": "input" - } - ] - }, - { - "name": "CRC_GEN", - "returnType": "DWORD", - "parameters": [ - { - "name": "PT", - "type": "__INLINE_ARRAY_BYTE", - "direction": "input" - }, - { - "name": "SIZE", - "type": "INT", - "direction": "input" - }, - { - "name": "PL", - "type": "INT", - "direction": "input" - }, - { - "name": "PN", - "type": "DWORD", - "direction": "input" - }, - { - "name": "INIT", - "type": "DWORD", - "direction": "input" - }, - { - "name": "REV_IN", - "type": "BOOL", - "direction": "input" - }, - { - "name": "REV_OUT", - "type": "BOOL", - "direction": "input" - }, - { - "name": "XOR_OUT", - "type": "DWORD", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "SHIFT", - "type": "INT", - "direction": "input" - }, - { - "name": "DX", - "type": "BYTE", - "direction": "input" - }, - { - "name": "BITS", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "CSET", - "returnType": "COMPLEX", - "parameters": [ - { - "name": "RE", - "type": "REAL", - "direction": "input" - }, - { - "name": "IM", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "CSIN", - "returnType": "COMPLEX", - "parameters": [ - { - "name": "X", - "type": "COMPLEX", - "direction": "input" - } - ] - }, - { - "name": "CSINH", - "returnType": "COMPLEX", - "parameters": [ - { - "name": "X", - "type": "COMPLEX", - "direction": "input" - } - ] - }, - { - "name": "CSQRT", - "returnType": "COMPLEX", - "parameters": [ - { - "name": "X", - "type": "COMPLEX", - "direction": "input" - }, - { - "name": "TEMP", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "CSUB", - "returnType": "COMPLEX", - "parameters": [ - { - "name": "X", - "type": "COMPLEX", - "direction": "input" - }, - { - "name": "Y", - "type": "COMPLEX", - "direction": "input" - } - ] - }, - { - "name": "CTAN", - "returnType": "COMPLEX", - "parameters": [ - { - "name": "X", - "type": "COMPLEX", - "direction": "input" - }, - { - "name": "TEMP", - "type": "REAL", - "direction": "input" - }, - { - "name": "XI2", - "type": "REAL", - "direction": "input" - }, - { - "name": "XR2", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "CTANH", - "returnType": "COMPLEX", - "parameters": [ - { - "name": "X", - "type": "COMPLEX", - "direction": "input" - }, - { - "name": "TEMP", - "type": "REAL", - "direction": "input" - }, - { - "name": "XI2", - "type": "REAL", - "direction": "input" - }, - { - "name": "XR2", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "CTRL_IN", - "returnType": "REAL", - "parameters": [ - { - "name": "SET_POINT", - "type": "REAL", - "direction": "input" - }, - { - "name": "ACTUAL", - "type": "REAL", - "direction": "input" - }, - { - "name": "NOISE", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "C_TO_F", - "returnType": "REAL", - "parameters": [ - { - "name": "CELSIUS", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "C_TO_K", - "returnType": "REAL", - "parameters": [ - { - "name": "CELSIUS", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "DATE_ADD", - "returnType": "DATE", - "parameters": [ - { - "name": "IDATE", - "type": "DATE", - "direction": "input" - }, - { - "name": "D", - "type": "INT", - "direction": "input" - }, - { - "name": "W", - "type": "INT", - "direction": "input" - }, - { - "name": "M", - "type": "INT", - "direction": "input" - }, - { - "name": "Y", - "type": "INT", - "direction": "input" - }, - { - "name": "MO", - "type": "INT", - "direction": "input" - }, - { - "name": "YR", - "type": "INT", - "direction": "input" - }, - { - "name": "DM", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "DAYS_DELTA", - "returnType": "DINT", - "parameters": [ - { - "name": "DATE_1", - "type": "DATE", - "direction": "input" - }, - { - "name": "DATE_2", - "type": "DATE", - "direction": "input" - } - ] - }, - { - "name": "DAYS_IN_MONTH", - "returnType": "INT", - "parameters": [ - { - "name": "IDATE", - "type": "DATE", - "direction": "input" - } - ] - }, - { - "name": "DAYS_IN_YEAR", - "returnType": "INT", - "parameters": [ - { - "name": "IDATE", - "type": "DATE", - "direction": "input" - } - ] - }, - { - "name": "DAY_OF_DATE", - "returnType": "DINT", - "parameters": [ - { - "name": "IDATE", - "type": "DATE", - "direction": "input" - } - ] - }, - { - "name": "DAY_OF_MONTH", - "returnType": "INT", - "parameters": [ - { - "name": "IDATE", - "type": "DATE", - "direction": "input" - }, - { - "name": "LEAP", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "DAY_OF_WEEK", - "returnType": "INT", - "parameters": [ - { - "name": "IDATE", - "type": "DATE", - "direction": "input" - } - ] - }, - { - "name": "DAY_OF_YEAR", - "returnType": "INT", - "parameters": [ - { - "name": "IDATE", - "type": "DATE", - "direction": "input" - } - ] - }, - { - "name": "DAY_TO_TIME", - "returnType": "TIME", - "parameters": [ - { - "name": "IN", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "DEAD_BAND", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "L", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "DEAD_ZONE", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "L", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "DEC1", - "returnType": "INT", - "parameters": [ - { - "name": "X", - "type": "INT", - "direction": "input" - }, - { - "name": "N", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "DEC_TO_BYTE", - "returnType": "BYTE", - "parameters": [ - { - "name": "DEC", - "type": "STRING", - "direction": "input" - }, - { - "name": "PT", - "type": "BYTE", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - }, - { - "name": "X", - "type": "BYTE", - "direction": "input" - }, - { - "name": "STOP", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "DEC_TO_DWORD", - "returnType": "DWORD", - "parameters": [ - { - "name": "DEC", - "type": "STRING", - "direction": "input" - }, - { - "name": "PT", - "type": "BYTE", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - }, - { - "name": "X", - "type": "BYTE", - "direction": "input" - }, - { - "name": "STOP", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "DEC_TO_INT", - "returnType": "INT", - "parameters": [ - { - "name": "DEC", - "type": "STRING", - "direction": "input" - }, - { - "name": "PT", - "type": "BYTE", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - }, - { - "name": "X", - "type": "BYTE", - "direction": "input" - }, - { - "name": "SIGN", - "type": "BOOL", - "direction": "input" - }, - { - "name": "STOP", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "DEG", - "returnType": "REAL", - "parameters": [ - { - "name": "RAD", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "DEG_TO_DIR", - "returnType": "STRING", - "parameters": [ - { - "name": "DEG", - "type": "INT", - "direction": "input" - }, - { - "name": "N", - "type": "INT", - "direction": "input" - }, - { - "name": "L", - "type": "INT", - "direction": "input" - }, - { - "name": "LY", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "DEL_CHARS", - "returnType": "STRING", - "parameters": [ - { - "name": "IN", - "type": "STRING", - "direction": "input" - }, - { - "name": "CX", - "type": "STRING", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "STOP", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "DIFFER", - "returnType": "BOOL", - "parameters": [ - { - "name": "IN1", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN2", - "type": "REAL", - "direction": "input" - }, - { - "name": "X", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "DIR_TO_DEG", - "returnType": "INT", - "parameters": [ - { - "name": "DIR", - "type": "STRING", - "direction": "input" - }, - { - "name": "L", - "type": "INT", - "direction": "input" - }, - { - "name": "LY", - "type": "INT", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "DST", - "returnType": "BOOL", - "parameters": [ - { - "name": "UTC", - "type": "DT", - "direction": "input" - }, - { - "name": "YR", - "type": "INT", - "direction": "input" - }, - { - "name": "YR4", - "type": "DWORD", - "direction": "input" - }, - { - "name": "LTC", - "type": "DWORD", - "direction": "input" - }, - { - "name": "IDATE", - "type": "DWORD", - "direction": "input" - } - ] - }, - { - "name": "DT2_TO_SDT", - "returnType": "SDT", - "parameters": [ - { - "name": "DI", - "type": "DATE", - "direction": "input" - }, - { - "name": "TI", - "type": "TOD", - "direction": "input" - } - ] - }, - { - "name": "DT_TO_SDT", - "returnType": "SDT", - "parameters": [ - { - "name": "DTI", - "type": "DT", - "direction": "input" - }, - { - "name": "TMP", - "type": "DATE", - "direction": "input" - }, - { - "name": "TDT", - "type": "DWORD", - "direction": "input" - } - ] - }, - { - "name": "DT_TO_STRF", - "returnType": "STRING", - "parameters": [ - { - "name": "DTI", - "type": "DT", - "direction": "input" - }, - { - "name": "MS", - "type": "INT", - "direction": "input" - }, - { - "name": "FMT", - "type": "STRING", - "direction": "input" - }, - { - "name": "LANG", - "type": "INT", - "direction": "input" - }, - { - "name": "FILL", - "type": "STRING", - "direction": "input" - }, - { - "name": "BLANK", - "type": "STRING", - "direction": "input" - }, - { - "name": "LY", - "type": "INT", - "direction": "input" - }, - { - "name": "DX", - "type": "DATE", - "direction": "input" - }, - { - "name": "FS", - "type": "STRING", - "direction": "input" - }, - { - "name": "TD", - "type": "TOD", - "direction": "input" - }, - { - "name": "TMP", - "type": "INT", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "F", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "DWORD_OF_BYTE", - "returnType": "DWORD", - "parameters": [ - { - "name": "B3", - "type": "BYTE", - "direction": "input" - }, - { - "name": "B2", - "type": "BYTE", - "direction": "input" - }, - { - "name": "B1", - "type": "BYTE", - "direction": "input" - }, - { - "name": "B0", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "DWORD_OF_WORD", - "returnType": "DWORD", - "parameters": [ - { - "name": "W1", - "type": "WORD", - "direction": "input" - }, - { - "name": "W0", - "type": "WORD", - "direction": "input" - } - ] - }, - { - "name": "DWORD_TO_STRB", - "returnType": "STRING", - "parameters": [ - { - "name": "IN", - "type": "DWORD", - "direction": "input" - }, - { - "name": "PT", - "type": "BYTE", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "DWORD_TO_STRF", - "returnType": "STRING", - "parameters": [ - { - "name": "IN", - "type": "DWORD", - "direction": "input" - }, - { - "name": "N", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "DWORD_TO_STRH", - "returnType": "STRING", - "parameters": [ - { - "name": "IN", - "type": "DWORD", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - }, - { - "name": "TEMP", - "type": "BYTE", - "direction": "input" - }, - { - "name": "PT", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "DW_TO_REAL", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "DWORD", - "direction": "input" - }, - { - "name": "PT", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "D_TRUNC", - "returnType": "DINT", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "EASTER", - "returnType": "DATE", - "parameters": [ - { - "name": "YEAR", - "type": "INT", - "direction": "input" - }, - { - "name": "B", - "type": "INT", - "direction": "input" - }, - { - "name": "C", - "type": "INT", - "direction": "input" - }, - { - "name": "ODAY", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "ELLIPSE_A", - "returnType": "REAL", - "parameters": [ - { - "name": "R1", - "type": "REAL", - "direction": "input" - }, - { - "name": "R2", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "ELLIPSE_C", - "returnType": "REAL", - "parameters": [ - { - "name": "R1", - "type": "REAL", - "direction": "input" - }, - { - "name": "R2", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "ERF", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "X2", - "type": "REAL", - "direction": "input" - }, - { - "name": "AX2", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "ERFC", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "EVEN", - "returnType": "BOOL", - "parameters": [ - { - "name": "IN", - "type": "DINT", - "direction": "input" - } - ] - }, - { - "name": "EXEC", - "returnType": "STRING", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "R1", - "type": "REAL", - "direction": "input" - }, - { - "name": "R2", - "type": "REAL", - "direction": "input" - }, - { - "name": "OPERATOR", - "type": "STRING", - "direction": "input" - } - ] - }, - { - "name": "EXP10", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "EXPN", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "N", - "type": "INT", - "direction": "input" - }, - { - "name": "SIGN", - "type": "BOOL", - "direction": "input" - } - ] - }, - { - "name": "FACT", - "returnType": "DINT", - "parameters": [ - { - "name": "X", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "FIB", - "returnType": "DINT", - "parameters": [ - { - "name": "X", - "type": "INT", - "direction": "input" - }, - { - "name": "T1", - "type": "DINT", - "direction": "input" - }, - { - "name": "T2", - "type": "DINT", - "direction": "input" - } - ] - }, - { - "name": "FILL", - "returnType": "STRING", - "parameters": [ - { - "name": "C", - "type": "BYTE", - "direction": "input" - }, - { - "name": "L", - "type": "INT", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - }, - { - "name": "SX", - "type": "STRING", - "direction": "input" - } - ] - }, - { - "name": "FINDB", - "returnType": "INT", - "parameters": [ - { - "name": "STR1", - "type": "STRING", - "direction": "input" - }, - { - "name": "STR2", - "type": "STRING", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "LENGTH", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "FINDB_NONUM", - "returnType": "INT", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "PT", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "FINDB_NUM", - "returnType": "INT", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "PT", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "FINDP", - "returnType": "INT", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "SRC", - "type": "STRING", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - }, - { - "name": "LS", - "type": "INT", - "direction": "input" - }, - { - "name": "LX", - "type": "INT", - "direction": "input" - }, - { - "name": "STP", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "FIND_CHAR", - "returnType": "INT", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - }, - { - "name": "PT", - "type": "__INLINE_ARRAY_BYTE", - "direction": "input" - }, - { - "name": "STOP", - "type": "INT", - "direction": "input" - }, - { - "name": "X", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "FIND_CTRL", - "returnType": "INT", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - }, - { - "name": "PT", - "type": "__INLINE_ARRAY_BYTE", - "direction": "input" - }, - { - "name": "STOP", - "type": "INT", - "direction": "input" - }, - { - "name": "X", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "FIND_NONUM", - "returnType": "INT", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - }, - { - "name": "PT", - "type": "__INLINE_ARRAY_BYTE", - "direction": "input" - }, - { - "name": "END", - "type": "INT", - "direction": "input" - }, - { - "name": "X", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "FIND_NUM", - "returnType": "INT", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - }, - { - "name": "PT", - "type": "__INLINE_ARRAY_BYTE", - "direction": "input" - }, - { - "name": "STOP", - "type": "INT", - "direction": "input" - }, - { - "name": "X", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "FIX", - "returnType": "STRING", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "L", - "type": "INT", - "direction": "input" - }, - { - "name": "C", - "type": "BYTE", - "direction": "input" - }, - { - "name": "M", - "type": "INT", - "direction": "input" - }, - { - "name": "N", - "type": "INT", - "direction": "input" - }, - { - "name": "SX", - "type": "STRING", - "direction": "input" - } - ] - }, - { - "name": "FLOAT_TO_REAL", - "returnType": "REAL", - "parameters": [ - { - "name": "FLT", - "type": "STRING", - "direction": "input" - }, - { - "name": "PT", - "type": "__INLINE_ARRAY_BYTE", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - }, - { - "name": "X", - "type": "BYTE", - "direction": "input" - }, - { - "name": "SIGN", - "type": "INT", - "direction": "input" - }, - { - "name": "STOP", - "type": "INT", - "direction": "input" - }, - { - "name": "TMP", - "type": "DINT", - "direction": "input" - }, - { - "name": "D", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "FLOOR", - "returnType": "INT", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "FLOOR2", - "returnType": "DINT", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "FRACT", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "FRMP_B", - "returnType": "BYTE", - "parameters": [ - { - "name": "START", - "type": "BYTE", - "direction": "input" - }, - { - "name": "DIR", - "type": "BOOL", - "direction": "input" - }, - { - "name": "TD", - "type": "TIME", - "direction": "input" - }, - { - "name": "TR", - "type": "TIME", - "direction": "input" - } - ] - }, - { - "name": "FSTRING_TO_BYTE", - "returnType": "BYTE", - "parameters": [ - { - "name": "IN", - "type": "STRING", - "direction": "input" - } - ] - }, - { - "name": "FSTRING_TO_DT", - "returnType": "DT", - "parameters": [ - { - "name": "SDT", - "type": "STRING", - "direction": "input" - }, - { - "name": "FMT", - "type": "STRING", - "direction": "input" - }, - { - "name": "IGNORE", - "type": "STRING", - "direction": "input" - }, - { - "name": "FCHAR", - "type": "STRING", - "direction": "input" - }, - { - "name": "C", - "type": "STRING", - "direction": "input" - }, - { - "name": "TMP", - "type": "STRING", - "direction": "input" - }, - { - "name": "END", - "type": "INT", - "direction": "input" - }, - { - "name": "DY", - "type": "INT", - "direction": "input" - }, - { - "name": "DM", - "type": "INT", - "direction": "input" - }, - { - "name": "DD", - "type": "INT", - "direction": "input" - }, - { - "name": "TH", - "type": "INT", - "direction": "input" - }, - { - "name": "TM", - "type": "INT", - "direction": "input" - }, - { - "name": "TS", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "FSTRING_TO_DWORD", - "returnType": "DWORD", - "parameters": [ - { - "name": "IN", - "type": "STRING", - "direction": "input" - } - ] - }, - { - "name": "FSTRING_TO_MONTH", - "returnType": "INT", - "parameters": [ - { - "name": "MTH", - "type": "STRING", - "direction": "input" - }, - { - "name": "LANG", - "type": "INT", - "direction": "input" - }, - { - "name": "LX", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "FSTRING_TO_WEEK", - "returnType": "BYTE", - "parameters": [ - { - "name": "WEEK", - "type": "STRING", - "direction": "input" - }, - { - "name": "LANG", - "type": "INT", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "FSTRING_TO_WEEKDAY", - "returnType": "INT", - "parameters": [ - { - "name": "WDAY", - "type": "STRING", - "direction": "input" - }, - { - "name": "LANG", - "type": "INT", - "direction": "input" - }, - { - "name": "TMP", - "type": "STRING", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - }, - { - "name": "LY", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "F_LIN", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "A", - "type": "REAL", - "direction": "input" - }, - { - "name": "B", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "F_LIN2", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "X1", - "type": "REAL", - "direction": "input" - }, - { - "name": "Y1", - "type": "REAL", - "direction": "input" - }, - { - "name": "X2", - "type": "REAL", - "direction": "input" - }, - { - "name": "Y2", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "F_POLY", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "C", - "type": "__INLINE_ARRAY_REAL", - "direction": "input" - } - ] - }, - { - "name": "F_POWER", - "returnType": "REAL", - "parameters": [ - { - "name": "A", - "type": "REAL", - "direction": "input" - }, - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "N", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "F_QUAD", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "A", - "type": "REAL", - "direction": "input" - }, - { - "name": "B", - "type": "REAL", - "direction": "input" - }, - { - "name": "C", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "F_TO_C", - "returnType": "REAL", - "parameters": [ - { - "name": "FAHRENHEIT", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "F_TO_OM", - "returnType": "REAL", - "parameters": [ - { - "name": "F", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "F_TO_PT", - "returnType": "TIME", - "parameters": [ - { - "name": "F", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "GAMMA", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "GAUSS", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "U", - "type": "REAL", - "direction": "input" - }, - { - "name": "SI", - "type": "REAL", - "direction": "input" - }, - { - "name": "TEMP", - "type": "REAL", - "direction": "input" - }, - { - "name": "SI_INV", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "GAUSSCD", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "U", - "type": "REAL", - "direction": "input" - }, - { - "name": "SI", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "GCD", - "returnType": "INT", - "parameters": [ - { - "name": "A", - "type": "DINT", - "direction": "input" - }, - { - "name": "B", - "type": "DINT", - "direction": "input" - }, - { - "name": "T", - "type": "DINT", - "direction": "input" - } - ] - }, - { - "name": "GDF", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "GEO_TO_DEG", - "returnType": "REAL", - "parameters": [ - { - "name": "D", - "type": "INT", - "direction": "input" - }, - { - "name": "M", - "type": "INT", - "direction": "input" - }, - { - "name": "SEC", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "GOLD", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "GRAY_TO_BYTE", - "returnType": "BYTE", - "parameters": [ - { - "name": "IN", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "HEX_TO_BYTE", - "returnType": "BYTE", - "parameters": [ - { - "name": "HEX", - "type": "STRING", - "direction": "input" - }, - { - "name": "PT", - "type": "BYTE", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - }, - { - "name": "X", - "type": "BYTE", - "direction": "input" - }, - { - "name": "STOP", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "HEX_TO_DWORD", - "returnType": "DWORD", - "parameters": [ - { - "name": "HEX", - "type": "STRING", - "direction": "input" - }, - { - "name": "PT", - "type": "BYTE", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - }, - { - "name": "X", - "type": "BYTE", - "direction": "input" - }, - { - "name": "STOP", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "HOUR", - "returnType": "INT", - "parameters": [ - { - "name": "ITOD", - "type": "TOD", - "direction": "input" - } - ] - }, - { - "name": "HOUR_OF_DT", - "returnType": "INT", - "parameters": [ - { - "name": "XDT", - "type": "DT", - "direction": "input" - } - ] - }, - { - "name": "HOUR_TO_TIME", - "returnType": "TIME", - "parameters": [ - { - "name": "IN", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "HOUR_TO_TOD", - "returnType": "TOD", - "parameters": [ - { - "name": "IN", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "HYPOT", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "Y", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "INC", - "returnType": "INT", - "parameters": [ - { - "name": "X", - "type": "INT", - "direction": "input" - }, - { - "name": "D", - "type": "INT", - "direction": "input" - }, - { - "name": "M", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "INC1", - "returnType": "INT", - "parameters": [ - { - "name": "X", - "type": "INT", - "direction": "input" - }, - { - "name": "N", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "INC2", - "returnType": "INT", - "parameters": [ - { - "name": "X", - "type": "INT", - "direction": "input" - }, - { - "name": "D", - "type": "INT", - "direction": "input" - }, - { - "name": "L", - "type": "INT", - "direction": "input" - }, - { - "name": "U", - "type": "INT", - "direction": "input" - }, - { - "name": "TMP", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "INT_TO_BCDC", - "returnType": "BYTE", - "parameters": [ - { - "name": "IN", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "INV", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "ISC_ALPHA", - "returnType": "BOOL", - "parameters": [ - { - "name": "IN", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "ISC_CTRL", - "returnType": "BOOL", - "parameters": [ - { - "name": "IN", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "ISC_HEX", - "returnType": "BOOL", - "parameters": [ - { - "name": "IN", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "ISC_LOWER", - "returnType": "BOOL", - "parameters": [ - { - "name": "IN", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "ISC_NUM", - "returnType": "BOOL", - "parameters": [ - { - "name": "IN", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "ISC_UPPER", - "returnType": "BOOL", - "parameters": [ - { - "name": "IN", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "IS_ALNUM", - "returnType": "BOOL", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "L", - "type": "INT", - "direction": "input" - }, - { - "name": "PT", - "type": "BYTE", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "IS_ALPHA", - "returnType": "BOOL", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "L", - "type": "INT", - "direction": "input" - }, - { - "name": "PT", - "type": "BYTE", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "IS_CC", - "returnType": "BOOL", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "CMP", - "type": "STRING", - "direction": "input" - }, - { - "name": "L", - "type": "INT", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "IS_CTRL", - "returnType": "BOOL", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "L", - "type": "INT", - "direction": "input" - }, - { - "name": "PT", - "type": "BYTE", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "IS_HEX", - "returnType": "BOOL", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "L", - "type": "INT", - "direction": "input" - }, - { - "name": "PT", - "type": "BYTE", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "IS_LOWER", - "returnType": "BOOL", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "L", - "type": "INT", - "direction": "input" - }, - { - "name": "PT", - "type": "BYTE", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "IS_NCC", - "returnType": "BOOL", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "CMP", - "type": "STRING", - "direction": "input" - }, - { - "name": "L", - "type": "INT", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "IS_NUM", - "returnType": "BOOL", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "L", - "type": "INT", - "direction": "input" - }, - { - "name": "PT", - "type": "BYTE", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "IS_SORTED", - "returnType": "BOOL", - "parameters": [ - { - "name": "PT", - "type": "__INLINE_ARRAY_REAL", - "direction": "input" - }, - { - "name": "SIZE", - "type": "UINT", - "direction": "input" - }, - { - "name": "STOP", - "type": "INT", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "IS_UPPER", - "returnType": "BOOL", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "L", - "type": "INT", - "direction": "input" - }, - { - "name": "PT", - "type": "BYTE", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "JD2000", - "returnType": "REAL", - "parameters": [ - { - "name": "DTI", - "type": "DT", - "direction": "input" - } - ] - }, - { - "name": "KMH_TO_MS", - "returnType": "REAL", - "parameters": [ - { - "name": "KMH", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "K_TO_C", - "returnType": "REAL", - "parameters": [ - { - "name": "KELVIN", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "LAMBERT_W", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "W", - "type": "REAL", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - }, - { - "name": "WE", - "type": "REAL", - "direction": "input" - }, - { - "name": "W1E", - "type": "REAL", - "direction": "input" - }, - { - "name": "LAST", - "type": "DWORD", - "direction": "input" - }, - { - "name": "EWX", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "LANGEVIN", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "LEAP_DAY", - "returnType": "BOOL", - "parameters": [ - { - "name": "IDATE", - "type": "DATE", - "direction": "input" - } - ] - }, - { - "name": "LEAP_OF_DATE", - "returnType": "BOOL", - "parameters": [ - { - "name": "IDATE", - "type": "DATE", - "direction": "input" - } - ] - }, - { - "name": "LEAP_YEAR", - "returnType": "BOOL", - "parameters": [ - { - "name": "YR", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "LINEAR_INT", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "XY", - "type": "__INLINE_ARRAY_REAL", - "direction": "input" - }, - { - "name": "PTS", - "type": "INT", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "LIST_ADD", - "returnType": "BOOL", - "parameters": [ - { - "name": "SEP", - "type": "BYTE", - "direction": "input" - }, - { - "name": "INS", - "type": "STRING", - "direction": "input" - }, - { - "name": "LIST", - "type": "STRING", - "direction": "inout" - }, - { - "name": "SX", - "type": "STRING", - "direction": "input" - } - ] - }, - { - "name": "LIST_CLEAN", - "returnType": "BOOL", - "parameters": [ - { - "name": "SEP", - "type": "BYTE", - "direction": "input" - }, - { - "name": "LIST", - "type": "STRING", - "direction": "inout" - }, - { - "name": "PT", - "type": "__INLINE_ARRAY_BYTE", - "direction": "input" - }, - { - "name": "READ", - "type": "INT", - "direction": "input" - }, - { - "name": "WRITE", - "type": "INT", - "direction": "input" - }, - { - "name": "LAST", - "type": "BYTE", - "direction": "input" - }, - { - "name": "C", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "LIST_GET", - "returnType": "STRING", - "parameters": [ - { - "name": "SEP", - "type": "BYTE", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "LIST", - "type": "STRING", - "direction": "inout" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - }, - { - "name": "O", - "type": "INT", - "direction": "input" - }, - { - "name": "PT", - "type": "__INLINE_ARRAY_BYTE", - "direction": "input" - }, - { - "name": "PO", - "type": "__INLINE_ARRAY_BYTE", - "direction": "input" - }, - { - "name": "CNT", - "type": "INT", - "direction": "input" - }, - { - "name": "C", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "LIST_INSERT", - "returnType": "BOOL", - "parameters": [ - { - "name": "SEP", - "type": "BYTE", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "INS", - "type": "STRING", - "direction": "input" - }, - { - "name": "LIST", - "type": "STRING", - "direction": "inout" - }, - { - "name": "PT", - "type": "__INLINE_ARRAY_BYTE", - "direction": "input" - }, - { - "name": "READ", - "type": "INT", - "direction": "input" - }, - { - "name": "CNT", - "type": "INT", - "direction": "input" - }, - { - "name": "SX", - "type": "STRING", - "direction": "input" - } - ] - }, - { - "name": "LIST_LEN", - "returnType": "INT", - "parameters": [ - { - "name": "SEP", - "type": "BYTE", - "direction": "input" - }, - { - "name": "LIST", - "type": "STRING", - "direction": "inout" - }, - { - "name": "PT", - "type": "__INLINE_ARRAY_BYTE", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "C", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "LIST_RETRIEVE", - "returnType": "STRING", - "parameters": [ - { - "name": "SEP", - "type": "BYTE", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "LIST", - "type": "STRING", - "direction": "inout" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - }, - { - "name": "O", - "type": "INT", - "direction": "input" - }, - { - "name": "W", - "type": "INT", - "direction": "input" - }, - { - "name": "PT", - "type": "__INLINE_ARRAY_BYTE", - "direction": "input" - }, - { - "name": "PO", - "type": "__INLINE_ARRAY_BYTE", - "direction": "input" - }, - { - "name": "CNT", - "type": "INT", - "direction": "input" - }, - { - "name": "C", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "LIST_RETRIEVE_LAST", - "returnType": "STRING", - "parameters": [ - { - "name": "SEP", - "type": "BYTE", - "direction": "input" - }, - { - "name": "LIST", - "type": "STRING", - "direction": "inout" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - }, - { - "name": "LAST", - "type": "INT", - "direction": "input" - }, - { - "name": "PT", - "type": "__INLINE_ARRAY_BYTE", - "direction": "input" - }, - { - "name": "C", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "LOWERCASE", - "returnType": "STRING", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "PT", - "type": "BYTE", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "L", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "LTIME_TO_UTC", - "returnType": "DT", - "parameters": [ - { - "name": "LTIME", - "type": "DT", - "direction": "input" - }, - { - "name": "DST", - "type": "BOOL", - "direction": "input" - }, - { - "name": "TIME_ZONE_OFFSET", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "MANUAL", - "returnType": "BOOL", - "parameters": [ - { - "name": "IN", - "type": "BOOL", - "direction": "input" - }, - { - "name": "ON", - "type": "BOOL", - "direction": "input" - }, - { - "name": "OFF", - "type": "BOOL", - "direction": "input" - } - ] - }, - { - "name": "MAX3", - "returnType": "REAL", - "parameters": [ - { - "name": "IN1", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN2", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN3", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "MID3", - "returnType": "REAL", - "parameters": [ - { - "name": "IN1", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN2", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN3", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "MIN3", - "returnType": "REAL", - "parameters": [ - { - "name": "IN1", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN2", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN3", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "MINUTE", - "returnType": "INT", - "parameters": [ - { - "name": "ITOD", - "type": "TOD", - "direction": "input" - } - ] - }, - { - "name": "MINUTE_OF_DT", - "returnType": "INT", - "parameters": [ - { - "name": "XDT", - "type": "DT", - "direction": "input" - } - ] - }, - { - "name": "MINUTE_TO_TIME", - "returnType": "TIME", - "parameters": [ - { - "name": "IN", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "MIRROR", - "returnType": "STRING", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "PI", - "type": "__INLINE_ARRAY_BYTE", - "direction": "input" - }, - { - "name": "PO", - "type": "BYTE", - "direction": "input" - }, - { - "name": "LX", - "type": "INT", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "MIX", - "returnType": "REAL", - "parameters": [ - { - "name": "A", - "type": "REAL", - "direction": "input" - }, - { - "name": "B", - "type": "REAL", - "direction": "input" - }, - { - "name": "M", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "MODR", - "returnType": "REAL", - "parameters": [ - { - "name": "IN", - "type": "REAL", - "direction": "input" - }, - { - "name": "DIVI", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "MONTH_BEGIN", - "returnType": "DATE", - "parameters": [ - { - "name": "IDATE", - "type": "DATE", - "direction": "input" - } - ] - }, - { - "name": "MONTH_END", - "returnType": "DATE", - "parameters": [ - { - "name": "IDATE", - "type": "DATE", - "direction": "input" - } - ] - }, - { - "name": "MONTH_OF_DATE", - "returnType": "INT", - "parameters": [ - { - "name": "IDATE", - "type": "DATE", - "direction": "input" - } - ] - }, - { - "name": "MONTH_TO_STRING", - "returnType": "STRING", - "parameters": [ - { - "name": "MTH", - "type": "INT", - "direction": "input" - }, - { - "name": "LANG", - "type": "INT", - "direction": "input" - }, - { - "name": "LX", - "type": "INT", - "direction": "input" - }, - { - "name": "LY", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "MS_TO_BFT", - "returnType": "INT", - "parameters": [ - { - "name": "MS", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "MS_TO_KMH", - "returnType": "REAL", - "parameters": [ - { - "name": "MS", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "MULTIME", - "returnType": "TIME", - "parameters": [ - { - "name": "T", - "type": "TIME", - "direction": "input" - }, - { - "name": "M", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "MULTI_IN", - "returnType": "REAL", - "parameters": [ - { - "name": "IN_1", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN_2", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN_3", - "type": "REAL", - "direction": "input" - }, - { - "name": "DEFAULT", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN_MIN", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN_MAX", - "type": "REAL", - "direction": "input" - }, - { - "name": "MODE", - "type": "BYTE", - "direction": "input" - }, - { - "name": "COUNT", - "type": "INT", - "direction": "input" - }, - { - "name": "F1", - "type": "BOOL", - "direction": "input" - }, - { - "name": "F2", - "type": "BOOL", - "direction": "input" - }, - { - "name": "F3", - "type": "BOOL", - "direction": "input" - } - ] - }, - { - "name": "MUL_ADD", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "K", - "type": "REAL", - "direction": "input" - }, - { - "name": "O", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "MUX_2", - "returnType": "BOOL", - "parameters": [ - { - "name": "D0", - "type": "BOOL", - "direction": "input" - }, - { - "name": "D1", - "type": "BOOL", - "direction": "input" - }, - { - "name": "A0", - "type": "BOOL", - "direction": "input" - } - ] - }, - { - "name": "MUX_4", - "returnType": "BOOL", - "parameters": [ - { - "name": "D0", - "type": "BOOL", - "direction": "input" - }, - { - "name": "D1", - "type": "BOOL", - "direction": "input" - }, - { - "name": "D2", - "type": "BOOL", - "direction": "input" - }, - { - "name": "D3", - "type": "BOOL", - "direction": "input" - }, - { - "name": "A0", - "type": "BOOL", - "direction": "input" - }, - { - "name": "A1", - "type": "BOOL", - "direction": "input" - } - ] - }, - { - "name": "MUX_R2", - "returnType": "REAL", - "parameters": [ - { - "name": "IN0", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN1", - "type": "REAL", - "direction": "input" - }, - { - "name": "A", - "type": "BOOL", - "direction": "input" - } - ] - }, - { - "name": "MUX_R4", - "returnType": "REAL", - "parameters": [ - { - "name": "IN0", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN1", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN2", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN3", - "type": "REAL", - "direction": "input" - }, - { - "name": "A0", - "type": "BOOL", - "direction": "input" - }, - { - "name": "A1", - "type": "BOOL", - "direction": "input" - } - ] - }, - { - "name": "NEGX", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "OCT_TO_BYTE", - "returnType": "BYTE", - "parameters": [ - { - "name": "OCT", - "type": "STRING", - "direction": "input" - }, - { - "name": "PT", - "type": "BYTE", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - }, - { - "name": "X", - "type": "BYTE", - "direction": "input" - }, - { - "name": "STOP", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "OCT_TO_DWORD", - "returnType": "DWORD", - "parameters": [ - { - "name": "OCT", - "type": "STRING", - "direction": "input" - }, - { - "name": "PT", - "type": "BYTE", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - }, - { - "name": "X", - "type": "BYTE", - "direction": "input" - }, - { - "name": "STOP", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "OFFSET", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "O1", - "type": "BOOL", - "direction": "input" - }, - { - "name": "O2", - "type": "BOOL", - "direction": "input" - }, - { - "name": "O3", - "type": "BOOL", - "direction": "input" - }, - { - "name": "O4", - "type": "BOOL", - "direction": "input" - }, - { - "name": "D", - "type": "BOOL", - "direction": "input" - }, - { - "name": "OFFSET_1", - "type": "REAL", - "direction": "input" - }, - { - "name": "OFFSET_2", - "type": "REAL", - "direction": "input" - }, - { - "name": "OFFSET_3", - "type": "REAL", - "direction": "input" - }, - { - "name": "OFFSET_4", - "type": "REAL", - "direction": "input" - }, - { - "name": "DEFAULT", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "OFFSET2", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "O1", - "type": "BOOL", - "direction": "input" - }, - { - "name": "O2", - "type": "BOOL", - "direction": "input" - }, - { - "name": "O3", - "type": "BOOL", - "direction": "input" - }, - { - "name": "O4", - "type": "BOOL", - "direction": "input" - }, - { - "name": "D", - "type": "BOOL", - "direction": "input" - }, - { - "name": "OFFSET_1", - "type": "REAL", - "direction": "input" - }, - { - "name": "OFFSET_2", - "type": "REAL", - "direction": "input" - }, - { - "name": "OFFSET_3", - "type": "REAL", - "direction": "input" - }, - { - "name": "OFFSET_4", - "type": "REAL", - "direction": "input" - }, - { - "name": "DEFAULT", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "OM_TO_F", - "returnType": "REAL", - "parameters": [ - { - "name": "OM", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "OSCAT_VERSION", - "returnType": "DWORD", - "parameters": [ - { - "name": "IN", - "type": "BOOL", - "direction": "input" - } - ] - }, - { - "name": "OVERRIDE", - "returnType": "REAL", - "parameters": [ - { - "name": "X1", - "type": "REAL", - "direction": "input" - }, - { - "name": "X2", - "type": "REAL", - "direction": "input" - }, - { - "name": "X3", - "type": "REAL", - "direction": "input" - }, - { - "name": "E1", - "type": "BOOL", - "direction": "input" - }, - { - "name": "E2", - "type": "BOOL", - "direction": "input" - }, - { - "name": "E3", - "type": "BOOL", - "direction": "input" - } - ] - }, - { - "name": "PARITY", - "returnType": "BOOL", - "parameters": [ - { - "name": "IN", - "type": "DWORD", - "direction": "input" - } - ] - }, - { - "name": "PERIOD", - "returnType": "BOOL", - "parameters": [ - { - "name": "D1", - "type": "DATE", - "direction": "input" - }, - { - "name": "DX", - "type": "DATE", - "direction": "input" - }, - { - "name": "D2", - "type": "DATE", - "direction": "input" - }, - { - "name": "DAY1", - "type": "INT", - "direction": "input" - }, - { - "name": "DAY2", - "type": "INT", - "direction": "input" - }, - { - "name": "DAYX", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "PERIOD2", - "returnType": "BOOL", - "parameters": [ - { - "name": "DP", - "type": "__INLINE_ARRAY_DATE", - "direction": "input" - }, - { - "name": "DX", - "type": "DATE", - "direction": "input" - } - ] - }, - { - "name": "POLYNOM_INT", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "XY", - "type": "__INLINE_ARRAY_REAL", - "direction": "input" - }, - { - "name": "PTS", - "type": "INT", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - }, - { - "name": "J", - "type": "INT", - "direction": "input" - }, - { - "name": "STOP", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "PT_TO_F", - "returnType": "REAL", - "parameters": [ - { - "name": "PT", - "type": "TIME", - "direction": "input" - } - ] - }, - { - "name": "R2_ABS", - "returnType": "REAL2", - "parameters": [ - { - "name": "X", - "type": "REAL2", - "direction": "input" - } - ] - }, - { - "name": "R2_ADD", - "returnType": "REAL2", - "parameters": [ - { - "name": "X", - "type": "REAL2", - "direction": "input" - }, - { - "name": "Y", - "type": "REAL", - "direction": "input" - }, - { - "name": "TEMP", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "R2_ADD2", - "returnType": "REAL2", - "parameters": [ - { - "name": "X", - "type": "REAL2", - "direction": "input" - }, - { - "name": "Y", - "type": "REAL2", - "direction": "input" - } - ] - }, - { - "name": "R2_MUL", - "returnType": "REAL2", - "parameters": [ - { - "name": "X", - "type": "REAL2", - "direction": "input" - }, - { - "name": "Y", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "R2_SET", - "returnType": "REAL2", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "RAD", - "returnType": "REAL", - "parameters": [ - { - "name": "DEG", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "RANGE_TO_BYTE", - "returnType": "BYTE", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "LOW", - "type": "REAL", - "direction": "input" - }, - { - "name": "HIGH", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "RANGE_TO_WORD", - "returnType": "WORD", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "LOW", - "type": "REAL", - "direction": "input" - }, - { - "name": "HIGH", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "RDM", - "returnType": "REAL", - "parameters": [ - { - "name": "LAST", - "type": "REAL", - "direction": "input" - }, - { - "name": "TN", - "type": "DWORD", - "direction": "input" - }, - { - "name": "TC", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "RDM2", - "returnType": "INT", - "parameters": [ - { - "name": "LAST", - "type": "INT", - "direction": "input" - }, - { - "name": "LOW", - "type": "INT", - "direction": "input" - }, - { - "name": "HIGH", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "RDMDW", - "returnType": "DWORD", - "parameters": [ - { - "name": "LAST", - "type": "DWORD", - "direction": "input" - }, - { - "name": "RX", - "type": "REAL", - "direction": "input" - }, - { - "name": "M", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "REAL_TO_DW", - "returnType": "DWORD", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "PT", - "type": "DWORD", - "direction": "input" - } - ] - }, - { - "name": "REAL_TO_FRAC", - "returnType": "FRACTION", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "N", - "type": "INT", - "direction": "input" - }, - { - "name": "TEMP", - "type": "DINT", - "direction": "input" - }, - { - "name": "SIGN", - "type": "BOOL", - "direction": "input" - }, - { - "name": "X_GERUNDET", - "type": "DINT", - "direction": "input" - }, - { - "name": "X_OHNE_NACHKOMMA", - "type": "REAL", - "direction": "input" - }, - { - "name": "NUMERATOR", - "type": "DINT", - "direction": "input" - }, - { - "name": "DENOMINATOR", - "type": "DINT", - "direction": "input" - }, - { - "name": "NUMERATOR_OLD", - "type": "DINT", - "direction": "input" - }, - { - "name": "DENOMINATOR_OLD", - "type": "DINT", - "direction": "input" - } - ] - }, - { - "name": "REAL_TO_STRF", - "returnType": "STRING", - "parameters": [ - { - "name": "IN", - "type": "REAL", - "direction": "input" - }, - { - "name": "N", - "type": "INT", - "direction": "input" - }, - { - "name": "D", - "type": "STRING", - "direction": "input" - }, - { - "name": "O", - "type": "REAL", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "REFLECT", - "returnType": "DWORD", - "parameters": [ - { - "name": "D", - "type": "DWORD", - "direction": "input" - }, - { - "name": "L", - "type": "INT", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "REFRACTION", - "returnType": "REAL", - "parameters": [ - { - "name": "ELEV", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "REPLACE_ALL", - "returnType": "STRING", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "SRC", - "type": "STRING", - "direction": "input" - }, - { - "name": "REP", - "type": "STRING", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "LP", - "type": "INT", - "direction": "input" - }, - { - "name": "LX", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "REPLACE_CHARS", - "returnType": "STRING", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "SRC", - "type": "STRING", - "direction": "input" - }, - { - "name": "REP", - "type": "STRING", - "direction": "input" - }, - { - "name": "A", - "type": "INT", - "direction": "input" - }, - { - "name": "B", - "type": "INT", - "direction": "input" - }, - { - "name": "C", - "type": "STRING", - "direction": "input" - }, - { - "name": "STP", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "REPLACE_UML", - "returnType": "STRING", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "L", - "type": "INT", - "direction": "input" - }, - { - "name": "PT", - "type": "BYTE", - "direction": "input" - }, - { - "name": "PTO", - "type": "BYTE", - "direction": "input" - }, - { - "name": "PTM", - "type": "BYTE", - "direction": "input" - }, - { - "name": "PT1", - "type": "BYTE", - "direction": "input" - }, - { - "name": "PT2", - "type": "BYTE", - "direction": "input" - }, - { - "name": "SU", - "type": "STRING", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "RES_NI", - "returnType": "REAL", - "parameters": [ - { - "name": "T", - "type": "REAL", - "direction": "input" - }, - { - "name": "R0", - "type": "REAL", - "direction": "input" - }, - { - "name": "A", - "type": "REAL", - "direction": "input" - }, - { - "name": "B", - "type": "REAL", - "direction": "input" - }, - { - "name": "C", - "type": "REAL", - "direction": "input" - }, - { - "name": "T2", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "RES_NTC", - "returnType": "REAL", - "parameters": [ - { - "name": "T", - "type": "REAL", - "direction": "input" - }, - { - "name": "RN", - "type": "REAL", - "direction": "input" - }, - { - "name": "B", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "RES_PT", - "returnType": "REAL", - "parameters": [ - { - "name": "T", - "type": "REAL", - "direction": "input" - }, - { - "name": "R0", - "type": "REAL", - "direction": "input" - }, - { - "name": "A", - "type": "REAL", - "direction": "input" - }, - { - "name": "B", - "type": "REAL", - "direction": "input" - }, - { - "name": "C", - "type": "REAL", - "direction": "input" - }, - { - "name": "T2", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "RES_SI", - "returnType": "REAL", - "parameters": [ - { - "name": "T", - "type": "REAL", - "direction": "input" - }, - { - "name": "RS", - "type": "REAL", - "direction": "input" - }, - { - "name": "TS", - "type": "REAL", - "direction": "input" - }, - { - "name": "A", - "type": "REAL", - "direction": "input" - }, - { - "name": "B", - "type": "REAL", - "direction": "input" - }, - { - "name": "TX", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "REVERSE", - "returnType": "BYTE", - "parameters": [ - { - "name": "IN", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "RND", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "N", - "type": "INT", - "direction": "input" - }, - { - "name": "M", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "ROUND", - "returnType": "REAL", - "parameters": [ - { - "name": "IN", - "type": "REAL", - "direction": "input" - }, - { - "name": "N", - "type": "INT", - "direction": "input" - }, - { - "name": "X", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "SCALE", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "K", - "type": "REAL", - "direction": "input" - }, - { - "name": "O", - "type": "REAL", - "direction": "input" - }, - { - "name": "MX", - "type": "REAL", - "direction": "input" - }, - { - "name": "MN", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "SCALE_B", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "BYTE", - "direction": "input" - }, - { - "name": "I_LO", - "type": "BYTE", - "direction": "input" - }, - { - "name": "I_HI", - "type": "BYTE", - "direction": "input" - }, - { - "name": "O_LO", - "type": "REAL", - "direction": "input" - }, - { - "name": "O_HI", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "SCALE_B2", - "returnType": "REAL", - "parameters": [ - { - "name": "IN1", - "type": "BYTE", - "direction": "input" - }, - { - "name": "IN2", - "type": "BYTE", - "direction": "input" - }, - { - "name": "K", - "type": "REAL", - "direction": "input" - }, - { - "name": "O", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN1_MIN", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN1_MAX", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN2_MIN", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN2_MAX", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "SCALE_B4", - "returnType": "REAL", - "parameters": [ - { - "name": "IN1", - "type": "BYTE", - "direction": "input" - }, - { - "name": "IN2", - "type": "BYTE", - "direction": "input" - }, - { - "name": "IN3", - "type": "BYTE", - "direction": "input" - }, - { - "name": "IN4", - "type": "BYTE", - "direction": "input" - }, - { - "name": "K", - "type": "REAL", - "direction": "input" - }, - { - "name": "O", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN1_MIN", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN1_MAX", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN2_MIN", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN2_MAX", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN3_MIN", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN3_MAX", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN4_MIN", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN4_MAX", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "SCALE_B8", - "returnType": "REAL", - "parameters": [ - { - "name": "IN1", - "type": "BYTE", - "direction": "input" - }, - { - "name": "IN2", - "type": "BYTE", - "direction": "input" - }, - { - "name": "IN3", - "type": "BYTE", - "direction": "input" - }, - { - "name": "IN4", - "type": "BYTE", - "direction": "input" - }, - { - "name": "IN5", - "type": "BYTE", - "direction": "input" - }, - { - "name": "IN6", - "type": "BYTE", - "direction": "input" - }, - { - "name": "IN7", - "type": "BYTE", - "direction": "input" - }, - { - "name": "IN8", - "type": "BYTE", - "direction": "input" - }, - { - "name": "K", - "type": "REAL", - "direction": "input" - }, - { - "name": "O", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN1_MIN", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN1_MAX", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN2_MIN", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN2_MAX", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN3_MIN", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN3_MAX", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN4_MIN", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN4_MAX", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN5_MIN", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN5_MAX", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN6_MIN", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN6_MAX", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN7_MIN", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN7_MAX", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN8_MIN", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN8_MAX", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "SCALE_D", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "DWORD", - "direction": "input" - }, - { - "name": "I_LO", - "type": "DWORD", - "direction": "input" - }, - { - "name": "I_HI", - "type": "DWORD", - "direction": "input" - }, - { - "name": "O_LO", - "type": "REAL", - "direction": "input" - }, - { - "name": "O_HI", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "SCALE_R", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "I_LO", - "type": "REAL", - "direction": "input" - }, - { - "name": "I_HI", - "type": "REAL", - "direction": "input" - }, - { - "name": "O_LO", - "type": "REAL", - "direction": "input" - }, - { - "name": "O_HI", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "SCALE_X2", - "returnType": "REAL", - "parameters": [ - { - "name": "IN1", - "type": "BOOL", - "direction": "input" - }, - { - "name": "IN2", - "type": "BOOL", - "direction": "input" - }, - { - "name": "K", - "type": "REAL", - "direction": "input" - }, - { - "name": "O", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN1_MIN", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN1_MAX", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN2_MIN", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN2_MAX", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "SCALE_X4", - "returnType": "REAL", - "parameters": [ - { - "name": "IN1", - "type": "BOOL", - "direction": "input" - }, - { - "name": "IN2", - "type": "BOOL", - "direction": "input" - }, - { - "name": "IN3", - "type": "BOOL", - "direction": "input" - }, - { - "name": "IN4", - "type": "BOOL", - "direction": "input" - }, - { - "name": "K", - "type": "REAL", - "direction": "input" - }, - { - "name": "O", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN1_MIN", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN1_MAX", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN2_MIN", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN2_MAX", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN3_MIN", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN3_MAX", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN4_MIN", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN4_MAX", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "SCALE_X8", - "returnType": "REAL", - "parameters": [ - { - "name": "IN1", - "type": "BOOL", - "direction": "input" - }, - { - "name": "IN2", - "type": "BOOL", - "direction": "input" - }, - { - "name": "IN3", - "type": "BOOL", - "direction": "input" - }, - { - "name": "IN4", - "type": "BOOL", - "direction": "input" - }, - { - "name": "IN5", - "type": "BOOL", - "direction": "input" - }, - { - "name": "IN6", - "type": "BOOL", - "direction": "input" - }, - { - "name": "IN7", - "type": "BOOL", - "direction": "input" - }, - { - "name": "IN8", - "type": "BOOL", - "direction": "input" - }, - { - "name": "K", - "type": "REAL", - "direction": "input" - }, - { - "name": "O", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN1_MIN", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN1_MAX", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN2_MIN", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN2_MAX", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN3_MIN", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN3_MAX", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN4_MIN", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN4_MAX", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN5_MIN", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN5_MAX", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN6_MIN", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN6_MAX", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN7_MIN", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN7_MAX", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN8_MIN", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN8_MAX", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "SDT_TO_DATE", - "returnType": "DATE", - "parameters": [ - { - "name": "DTI", - "type": "SDT", - "direction": "input" - } - ] - }, - { - "name": "SDT_TO_DT", - "returnType": "DT", - "parameters": [ - { - "name": "DTI", - "type": "SDT", - "direction": "input" - } - ] - }, - { - "name": "SDT_TO_TOD", - "returnType": "TOD", - "parameters": [ - { - "name": "DTI", - "type": "SDT", - "direction": "input" - } - ] - }, - { - "name": "SECOND", - "returnType": "REAL", - "parameters": [ - { - "name": "ITOD", - "type": "TOD", - "direction": "input" - } - ] - }, - { - "name": "SECOND_OF_DT", - "returnType": "INT", - "parameters": [ - { - "name": "XDT", - "type": "DT", - "direction": "input" - } - ] - }, - { - "name": "SECOND_TO_TIME", - "returnType": "TIME", - "parameters": [ - { - "name": "IN", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "SENSOR_INT", - "returnType": "REAL", - "parameters": [ - { - "name": "VOLTAGE", - "type": "REAL", - "direction": "input" - }, - { - "name": "CURRENT", - "type": "REAL", - "direction": "input" - }, - { - "name": "RP", - "type": "REAL", - "direction": "input" - }, - { - "name": "RS", - "type": "REAL", - "direction": "input" - }, - { - "name": "RG", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "SET_DATE", - "returnType": "DATE", - "parameters": [ - { - "name": "YEAR", - "type": "INT", - "direction": "input" - }, - { - "name": "MONTH", - "type": "INT", - "direction": "input" - }, - { - "name": "DAY", - "type": "INT", - "direction": "input" - }, - { - "name": "COUNT", - "type": "INT", - "direction": "input" - }, - { - "name": "OFS", - "type": "__INLINE_ARRAY_INT", - "direction": "input" - }, - { - "name": "ENDIF", - "type": "BOOL", - "direction": "input" - } - ] - }, - { - "name": "SET_DT", - "returnType": "DT", - "parameters": [ - { - "name": "YEAR", - "type": "INT", - "direction": "input" - }, - { - "name": "MONTH", - "type": "INT", - "direction": "input" - }, - { - "name": "DAY", - "type": "INT", - "direction": "input" - }, - { - "name": "HOUR", - "type": "INT", - "direction": "input" - }, - { - "name": "MINUTE", - "type": "INT", - "direction": "input" - }, - { - "name": "SECOND", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "SET_TOD", - "returnType": "TOD", - "parameters": [ - { - "name": "HOUR", - "type": "INT", - "direction": "input" - }, - { - "name": "MINUTE", - "type": "INT", - "direction": "input" - }, - { - "name": "SECOND", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "SGN", - "returnType": "INT", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "SHL1", - "returnType": "DWORD", - "parameters": [ - { - "name": "IN", - "type": "DWORD", - "direction": "input" - }, - { - "name": "N", - "type": "INT", - "direction": "input" - }, - { - "name": "TEMP", - "type": "DWORD", - "direction": "input" - } - ] - }, - { - "name": "SHR1", - "returnType": "DWORD", - "parameters": [ - { - "name": "IN", - "type": "DWORD", - "direction": "input" - }, - { - "name": "N", - "type": "INT", - "direction": "input" - }, - { - "name": "TEMP", - "type": "DWORD", - "direction": "input" - } - ] - }, - { - "name": "SIGMOID", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "SIGN_I", - "returnType": "BOOL", - "parameters": [ - { - "name": "IN", - "type": "DINT", - "direction": "input" - } - ] - }, - { - "name": "SIGN_R", - "returnType": "BOOL", - "parameters": [ - { - "name": "IN", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "SINC", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "SINH", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "SPHERE_V", - "returnType": "REAL", - "parameters": [ - { - "name": "RX", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "SQRTN", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "N", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "STAIR", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "D", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "STATUS_TO_ESR", - "returnType": "ESR_DATA", - "parameters": [ - { - "name": "STATUS", - "type": "BYTE", - "direction": "input" - }, - { - "name": "ADRESS", - "type": "STRING", - "direction": "input" - }, - { - "name": "DT_IN", - "type": "DT", - "direction": "input" - }, - { - "name": "TS", - "type": "TIME", - "direction": "input" - } - ] - }, - { - "name": "SUN_MIDDAY", - "returnType": "TOD", - "parameters": [ - { - "name": "LON", - "type": "REAL", - "direction": "input" - }, - { - "name": "UTC", - "type": "DATE", - "direction": "input" - }, - { - "name": "T", - "type": "REAL", - "direction": "input" - }, - { - "name": "OFFSET", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "SWAP_BYTE", - "returnType": "WORD", - "parameters": [ - { - "name": "IN", - "type": "WORD", - "direction": "input" - } - ] - }, - { - "name": "SWAP_BYTE2", - "returnType": "DWORD", - "parameters": [ - { - "name": "IN", - "type": "DWORD", - "direction": "input" - } - ] - }, - { - "name": "TANC", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "TANH", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "TEMP_NI", - "returnType": "REAL", - "parameters": [ - { - "name": "RES", - "type": "REAL", - "direction": "input" - }, - { - "name": "R0", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "TEMP_NTC", - "returnType": "REAL", - "parameters": [ - { - "name": "RES", - "type": "REAL", - "direction": "input" - }, - { - "name": "RN", - "type": "REAL", - "direction": "input" - }, - { - "name": "B", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "TEMP_PT", - "returnType": "REAL", - "parameters": [ - { - "name": "RES", - "type": "REAL", - "direction": "input" - }, - { - "name": "R0", - "type": "REAL", - "direction": "input" - }, - { - "name": "A", - "type": "REAL", - "direction": "input" - }, - { - "name": "B", - "type": "REAL", - "direction": "input" - }, - { - "name": "ACCURACY", - "type": "REAL", - "direction": "input" - }, - { - "name": "STEP", - "type": "REAL", - "direction": "input" - }, - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "Y", - "type": "REAL", - "direction": "input" - }, - { - "name": "T1", - "type": "REAL", - "direction": "input" - }, - { - "name": "PT", - "type": "DWORD", - "direction": "input" - } - ] - }, - { - "name": "TEMP_SI", - "returnType": "REAL", - "parameters": [ - { - "name": "RES", - "type": "REAL", - "direction": "input" - }, - { - "name": "RS", - "type": "REAL", - "direction": "input" - }, - { - "name": "TS", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "TIMECHECK", - "returnType": "BOOL", - "parameters": [ - { - "name": "TD", - "type": "TOD", - "direction": "input" - }, - { - "name": "START", - "type": "TOD", - "direction": "input" - }, - { - "name": "STOP", - "type": "TOD", - "direction": "input" - } - ] - }, - { - "name": "TO_LOWER", - "returnType": "BYTE", - "parameters": [ - { - "name": "IN", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "TO_UML", - "returnType": "STRING", - "parameters": [ - { - "name": "IN", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "TO_UPPER", - "returnType": "BYTE", - "parameters": [ - { - "name": "IN", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "TRIANGLE_A", - "returnType": "REAL", - "parameters": [ - { - "name": "S1", - "type": "REAL", - "direction": "input" - }, - { - "name": "A", - "type": "REAL", - "direction": "input" - }, - { - "name": "S2", - "type": "REAL", - "direction": "input" - }, - { - "name": "S3", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "TRIM", - "returnType": "STRING", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "TRIM1", - "returnType": "STRING", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "TRIME", - "returnType": "STRING", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - } - ] - }, - { - "name": "T_PLC_MS", - "returnType": "DWORD", - "parameters": [ - { - "name": "DEBUG", - "type": "BOOL", - "direction": "input" - }, - { - "name": "N", - "type": "INT", - "direction": "input" - }, - { - "name": "OFFSET", - "type": "DWORD", - "direction": "input" - }, - { - "name": "TX", - "type": "TIME", - "direction": "input" - } - ] - }, - { - "name": "T_PLC_US", - "returnType": "DWORD", - "parameters": [ - { - "name": "DEBUG", - "type": "BOOL", - "direction": "input" - }, - { - "name": "N", - "type": "INT", - "direction": "input" - }, - { - "name": "OFFSET", - "type": "DWORD", - "direction": "input" - }, - { - "name": "TX", - "type": "TIME", - "direction": "input" - } - ] - }, - { - "name": "UPPERCASE", - "returnType": "STRING", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "PT", - "type": "BYTE", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "L", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "UTC_TO_LTIME", - "returnType": "DT", - "parameters": [ - { - "name": "UTC", - "type": "DT", - "direction": "input" - }, - { - "name": "DST_ENABLE", - "type": "BOOL", - "direction": "input" - }, - { - "name": "TIME_ZONE_OFFSET", - "type": "INT", - "direction": "input" - }, - { - "name": "TMP", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "V3_ABS", - "returnType": "REAL", - "parameters": [ - { - "name": "A", - "type": "VECTOR_3", - "direction": "input" - } - ] - }, - { - "name": "V3_ADD", - "returnType": "VECTOR_3", - "parameters": [ - { - "name": "A", - "type": "VECTOR_3", - "direction": "input" - }, - { - "name": "B", - "type": "VECTOR_3", - "direction": "input" - } - ] - }, - { - "name": "V3_ANG", - "returnType": "REAL", - "parameters": [ - { - "name": "A", - "type": "VECTOR_3", - "direction": "input" - }, - { - "name": "B", - "type": "VECTOR_3", - "direction": "input" - }, - { - "name": "D", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "V3_DPRO", - "returnType": "REAL", - "parameters": [ - { - "name": "A", - "type": "VECTOR_3", - "direction": "input" - }, - { - "name": "B", - "type": "VECTOR_3", - "direction": "input" - } - ] - }, - { - "name": "V3_NORM", - "returnType": "VECTOR_3", - "parameters": [ - { - "name": "A", - "type": "VECTOR_3", - "direction": "input" - }, - { - "name": "LA", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "V3_NUL", - "returnType": "BOOL", - "parameters": [ - { - "name": "A", - "type": "VECTOR_3", - "direction": "input" - } - ] - }, - { - "name": "V3_PAR", - "returnType": "BOOL", - "parameters": [ - { - "name": "A", - "type": "VECTOR_3", - "direction": "input" - }, - { - "name": "B", - "type": "VECTOR_3", - "direction": "input" - } - ] - }, - { - "name": "V3_REV", - "returnType": "VECTOR_3", - "parameters": [ - { - "name": "A", - "type": "VECTOR_3", - "direction": "input" - } - ] - }, - { - "name": "V3_SMUL", - "returnType": "VECTOR_3", - "parameters": [ - { - "name": "A", - "type": "VECTOR_3", - "direction": "input" - }, - { - "name": "M", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "V3_SUB", - "returnType": "VECTOR_3", - "parameters": [ - { - "name": "A", - "type": "VECTOR_3", - "direction": "input" - }, - { - "name": "B", - "type": "VECTOR_3", - "direction": "input" - } - ] - }, - { - "name": "V3_XANG", - "returnType": "REAL", - "parameters": [ - { - "name": "A", - "type": "VECTOR_3", - "direction": "input" - }, - { - "name": "LA", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "V3_XPRO", - "returnType": "VECTOR_3", - "parameters": [ - { - "name": "A", - "type": "VECTOR_3", - "direction": "input" - }, - { - "name": "B", - "type": "VECTOR_3", - "direction": "input" - } - ] - }, - { - "name": "V3_YANG", - "returnType": "REAL", - "parameters": [ - { - "name": "A", - "type": "VECTOR_3", - "direction": "input" - }, - { - "name": "LA", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "V3_ZANG", - "returnType": "REAL", - "parameters": [ - { - "name": "A", - "type": "VECTOR_3", - "direction": "input" - }, - { - "name": "LA", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "WEEKDAY_TO_STRING", - "returnType": "STRING", - "parameters": [ - { - "name": "WDAY", - "type": "INT", - "direction": "input" - }, - { - "name": "LANG", - "type": "INT", - "direction": "input" - }, - { - "name": "LX", - "type": "INT", - "direction": "input" - }, - { - "name": "LY", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "WINDOW", - "returnType": "BOOL", - "parameters": [ - { - "name": "LOW", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN", - "type": "REAL", - "direction": "input" - }, - { - "name": "HIGH", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "WINDOW2", - "returnType": "BOOL", - "parameters": [ - { - "name": "LOW", - "type": "REAL", - "direction": "input" - }, - { - "name": "IN", - "type": "REAL", - "direction": "input" - }, - { - "name": "HIGH", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "WORD_OF_BYTE", - "returnType": "WORD", - "parameters": [ - { - "name": "B1", - "type": "BYTE", - "direction": "input" - }, - { - "name": "B0", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "WORD_OF_DWORD", - "returnType": "WORD", - "parameters": [ - { - "name": "IN", - "type": "DWORD", - "direction": "input" - }, - { - "name": "N", - "type": "BYTE", - "direction": "input" - } - ] - }, - { - "name": "WORD_TO_RANGE", - "returnType": "REAL", - "parameters": [ - { - "name": "X", - "type": "WORD", - "direction": "input" - }, - { - "name": "LOW", - "type": "REAL", - "direction": "input" - }, - { - "name": "HIGH", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "WORK_WEEK", - "returnType": "INT", - "parameters": [ - { - "name": "IDATE", - "type": "DATE", - "direction": "input" - }, - { - "name": "D1", - "type": "DATE", - "direction": "input" - }, - { - "name": "W1", - "type": "INT", - "direction": "input" - }, - { - "name": "DS", - "type": "DWORD", - "direction": "input" - }, - { - "name": "YR", - "type": "INT", - "direction": "input" - }, - { - "name": "W31", - "type": "INT", - "direction": "input" - }, - { - "name": "W01", - "type": "INT", - "direction": "input" - }, - { - "name": "WM", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "YEAR_BEGIN", - "returnType": "DATE", - "parameters": [ - { - "name": "Y", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "YEAR_END", - "returnType": "DATE", - "parameters": [ - { - "name": "Y", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "YEAR_OF_DATE", - "returnType": "INT", - "parameters": [ - { - "name": "IDATE", - "type": "DATE", - "direction": "input" - } - ] - }, - { - "name": "_ARRAY_ABS", - "returnType": "BOOL", - "parameters": [ - { - "name": "PT", - "type": "__INLINE_ARRAY_REAL", - "direction": "input" - }, - { - "name": "SIZE", - "type": "UINT", - "direction": "input" - }, - { - "name": "I", - "type": "UINT", - "direction": "input" - }, - { - "name": "STOP", - "type": "UINT", - "direction": "input" - } - ] - }, - { - "name": "_ARRAY_ADD", - "returnType": "BOOL", - "parameters": [ - { - "name": "PT", - "type": "__INLINE_ARRAY_REAL", - "direction": "input" - }, - { - "name": "SIZE", - "type": "UINT", - "direction": "input" - }, - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "I", - "type": "UINT", - "direction": "input" - }, - { - "name": "STOP", - "type": "UINT", - "direction": "input" - } - ] - }, - { - "name": "_ARRAY_INIT", - "returnType": "BOOL", - "parameters": [ - { - "name": "PT", - "type": "__INLINE_ARRAY_REAL", - "direction": "input" - }, - { - "name": "SIZE", - "type": "UINT", - "direction": "input" - }, - { - "name": "INIT", - "type": "REAL", - "direction": "input" - }, - { - "name": "I", - "type": "UINT", - "direction": "input" - }, - { - "name": "STOP", - "type": "UINT", - "direction": "input" - } - ] - }, - { - "name": "_ARRAY_MEDIAN", - "returnType": "REAL", - "parameters": [ - { - "name": "PT", - "type": "__INLINE_ARRAY_REAL", - "direction": "input" - }, - { - "name": "SIZE", - "type": "UINT", - "direction": "input" - }, - { - "name": "I", - "type": "UINT", - "direction": "input" - }, - { - "name": "STOP", - "type": "UINT", - "direction": "input" - } - ] - }, - { - "name": "_ARRAY_MUL", - "returnType": "BOOL", - "parameters": [ - { - "name": "PT", - "type": "__INLINE_ARRAY_REAL", - "direction": "input" - }, - { - "name": "SIZE", - "type": "UINT", - "direction": "input" - }, - { - "name": "X", - "type": "REAL", - "direction": "input" - }, - { - "name": "I", - "type": "UINT", - "direction": "input" - }, - { - "name": "STOP", - "type": "UINT", - "direction": "input" - } - ] - }, - { - "name": "_ARRAY_SHUFFLE", - "returnType": "BOOL", - "parameters": [ - { - "name": "PT", - "type": "__INLINE_ARRAY_REAL", - "direction": "input" - }, - { - "name": "SIZE", - "type": "UINT", - "direction": "input" - }, - { - "name": "TEMP", - "type": "REAL", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - }, - { - "name": "STOP", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "_ARRAY_SORT", - "returnType": "BOOL", - "parameters": [ - { - "name": "PT", - "type": "__INLINE_ARRAY_REAL", - "direction": "input" - }, - { - "name": "SIZE", - "type": "UINT", - "direction": "input" - }, - { - "name": "STACK_COUNT", - "type": "UINT", - "direction": "input" - }, - { - "name": "STACK", - "type": "__INLINE_ARRAY_UINT", - "direction": "input" - }, - { - "name": "LINKS", - "type": "UINT", - "direction": "input" - }, - { - "name": "RECHTS", - "type": "UINT", - "direction": "input" - }, - { - "name": "PIVOT", - "type": "REAL", - "direction": "input" - }, - { - "name": "I", - "type": "UINT", - "direction": "input" - }, - { - "name": "J", - "type": "UINT", - "direction": "input" - }, - { - "name": "ENDE_INNEN", - "type": "BOOL", - "direction": "input" - }, - { - "name": "ENDE_AUSSEN", - "type": "BOOL", - "direction": "input" - }, - { - "name": "TMP", - "type": "REAL", - "direction": "input" - } - ] - }, - { - "name": "_BUFFER_CLEAR", - "returnType": "BOOL", - "parameters": [ - { - "name": "PT", - "type": "BYTE", - "direction": "input" - }, - { - "name": "SIZE", - "type": "UINT", - "direction": "input" - }, - { - "name": "PTW", - "type": "DWORD", - "direction": "input" - }, - { - "name": "TEMP", - "type": "DWORD", - "direction": "input" - }, - { - "name": "END", - "type": "DWORD", - "direction": "input" - }, - { - "name": "END32", - "type": "DWORD", - "direction": "input" - } - ] - }, - { - "name": "_BUFFER_INIT", - "returnType": "BOOL", - "parameters": [ - { - "name": "PT", - "type": "BYTE", - "direction": "input" - }, - { - "name": "SIZE", - "type": "UINT", - "direction": "input" - }, - { - "name": "INIT", - "type": "BYTE", - "direction": "input" - }, - { - "name": "PTW", - "type": "DWORD", - "direction": "input" - }, - { - "name": "TEMP", - "type": "DWORD", - "direction": "input" - }, - { - "name": "END", - "type": "DWORD", - "direction": "input" - }, - { - "name": "END32", - "type": "DWORD", - "direction": "input" - } - ] - }, - { - "name": "_BUFFER_INSERT", - "returnType": "INT", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "PT", - "type": "__INLINE_ARRAY_BYTE", - "direction": "input" - }, - { - "name": "SIZE", - "type": "UINT", - "direction": "input" - }, - { - "name": "END", - "type": "INT", - "direction": "input" - }, - { - "name": "LX", - "type": "INT", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "_BUFFER_UPPERCASE", - "returnType": "BOOL", - "parameters": [ - { - "name": "PT", - "type": "__INLINE_ARRAY_BYTE", - "direction": "input" - }, - { - "name": "SIZE", - "type": "INT", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - } - ] - }, - { - "name": "_STRING_TO_BUFFER", - "returnType": "INT", - "parameters": [ - { - "name": "STR", - "type": "STRING", - "direction": "input" - }, - { - "name": "POS", - "type": "INT", - "direction": "input" - }, - { - "name": "PT", - "type": "__INLINE_ARRAY_BYTE", - "direction": "input" - }, - { - "name": "SIZE", - "type": "UINT", - "direction": "input" - }, - { - "name": "PS", - "type": "BYTE", - "direction": "input" - }, - { - "name": "I", - "type": "INT", - "direction": "input" - }, - { - "name": "END", - "type": "INT", - "direction": "input" - } - ] - } - ], - "functionBlocks": [ - { - "name": "AIN1", - "inputs": [ - { - "name": "IN", - "type": "DWORD" - }, - { - "name": "SIGN_BIT", - "type": "INT" - }, - { - "name": "ERROR_BIT", - "type": "INT" - }, - { - "name": "ERROR_CODE_EN", - "type": "BOOL" - }, - { - "name": "ERROR_CODE", - "type": "DWORD" - }, - { - "name": "OVERFLOW_BIT", - "type": "INT" - }, - { - "name": "OVERFLOW_CODE_EN", - "type": "BOOL" - }, - { - "name": "OVERFLOW_CODE", - "type": "DWORD" - }, - { - "name": "BIT_0", - "type": "INT" - }, - { - "name": "BIT_N", - "type": "INT" - }, - { - "name": "OUT_MIN", - "type": "REAL" - }, - { - "name": "OUT_MAX", - "type": "REAL" - }, - { - "name": "CODE_MIN", - "type": "DWORD" - }, - { - "name": "CODE_MAX", - "type": "DWORD" - }, - { - "name": "ERROR_OUTPUT", - "type": "REAL" - }, - { - "name": "OVERFLOW_OUTPUT", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "OUT", - "type": "REAL" - }, - { - "name": "SIGN", - "type": "BOOL" - }, - { - "name": "ERROR", - "type": "BOOL" - }, - { - "name": "OVERFLOW", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "ALARM_2", - "inputs": [ - { - "name": "X", - "type": "REAL" - }, - { - "name": "LO_1", - "type": "REAL" - }, - { - "name": "HI_1", - "type": "REAL" - }, - { - "name": "LO_2", - "type": "REAL" - }, - { - "name": "HI_2", - "type": "REAL" - }, - { - "name": "HYS", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "Q1_LO", - "type": "BOOL" - }, - { - "name": "Q1_HI", - "type": "BOOL" - }, - { - "name": "Q2_LO", - "type": "BOOL" - }, - { - "name": "Q2_HI", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "ASTRO", - "inputs": [ - { - "name": "M", - "type": "REAL" - }, - { - "name": "AE", - "type": "REAL" - }, - { - "name": "PC", - "type": "REAL" - }, - { - "name": "LJ", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "YM", - "type": "REAL" - }, - { - "name": "YAE", - "type": "REAL" - }, - { - "name": "YPC", - "type": "REAL" - }, - { - "name": "YLJ", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "A_TRIG", - "inputs": [ - { - "name": "IN", - "type": "REAL" - }, - { - "name": "RES", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - }, - { - "name": "D", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "BAR_GRAPH", - "inputs": [ - { - "name": "X", - "type": "REAL" - }, - { - "name": "RST", - "type": "BOOL" - }, - { - "name": "TRIGGER_LOW", - "type": "REAL" - }, - { - "name": "TRIGGER_HIGH", - "type": "REAL" - }, - { - "name": "ALARM_LOW", - "type": "BOOL" - }, - { - "name": "ALARM_HIGH", - "type": "BOOL" - }, - { - "name": "LOG_SCALE", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "LOW", - "type": "BOOL" - }, - { - "name": "Q1", - "type": "BOOL" - }, - { - "name": "Q2", - "type": "BOOL" - }, - { - "name": "Q3", - "type": "BOOL" - }, - { - "name": "Q4", - "type": "BOOL" - }, - { - "name": "Q5", - "type": "BOOL" - }, - { - "name": "Q6", - "type": "BOOL" - }, - { - "name": "HIGH", - "type": "BOOL" - }, - { - "name": "ALARM", - "type": "BOOL" - }, - { - "name": "STATUS", - "type": "BYTE" - } - ], - "inouts": [] - }, - { - "name": "BYTE_TO_BITS", - "inputs": [ - { - "name": "IN", - "type": "BYTE" - } - ], - "outputs": [ - { - "name": "B0", - "type": "BOOL" - }, - { - "name": "B1", - "type": "BOOL" - }, - { - "name": "B2", - "type": "BOOL" - }, - { - "name": "B3", - "type": "BOOL" - }, - { - "name": "B4", - "type": "BOOL" - }, - { - "name": "B5", - "type": "BOOL" - }, - { - "name": "B6", - "type": "BOOL" - }, - { - "name": "B7", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "B_TRIG", - "inputs": [ - { - "name": "CLK", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "CALENDAR_CALC", - "inputs": [ - { - "name": "SPE", - "type": "BOOL" - }, - { - "name": "H", - "type": "REAL" - } - ], - "outputs": [], - "inouts": [ - { - "name": "XCAL", - "type": "CALENDAR" - }, - { - "name": "HOLIDAYS", - "type": "__INLINE_ARRAY_HOLIDAY_DATA", - "arrayDimensions": [ - { - "start": 0, - "end": 29 - } - ], - "elementTypeName": "HOLIDAY_DATA" - } - ] - }, - { - "name": "CALIBRATE", - "inputs": [ - { - "name": "X", - "type": "REAL" - }, - { - "name": "CO", - "type": "BOOL" - }, - { - "name": "CS", - "type": "BOOL" - }, - { - "name": "Y_OFFSET", - "type": "REAL" - }, - { - "name": "Y_SCALE", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "Y", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "CLICK_CNT", - "inputs": [ - { - "name": "IN", - "type": "BOOL" - }, - { - "name": "N", - "type": "INT" - }, - { - "name": "TC", - "type": "TIME" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "CLICK_DEC", - "inputs": [ - { - "name": "IN", - "type": "BOOL" - }, - { - "name": "TC", - "type": "TIME" - } - ], - "outputs": [ - { - "name": "Q0", - "type": "BOOL" - }, - { - "name": "Q1", - "type": "BOOL" - }, - { - "name": "Q2", - "type": "BOOL" - }, - { - "name": "Q3", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "CLK_DIV", - "inputs": [ - { - "name": "CLK", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q0", - "type": "BOOL" - }, - { - "name": "Q1", - "type": "BOOL" - }, - { - "name": "Q2", - "type": "BOOL" - }, - { - "name": "Q3", - "type": "BOOL" - }, - { - "name": "Q4", - "type": "BOOL" - }, - { - "name": "Q5", - "type": "BOOL" - }, - { - "name": "Q6", - "type": "BOOL" - }, - { - "name": "Q7", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "CLK_N", - "inputs": [ - { - "name": "N", - "type": "INT" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "CLK_PRG", - "inputs": [ - { - "name": "PT", - "type": "TIME" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "CLK_PULSE", - "inputs": [ - { - "name": "PT", - "type": "TIME" - }, - { - "name": "N", - "type": "INT" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - }, - { - "name": "CNT", - "type": "INT" - }, - { - "name": "RUN", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "CONTROL_SET1", - "inputs": [ - { - "name": "KT", - "type": "REAL" - }, - { - "name": "TT", - "type": "REAL" - }, - { - "name": "PI", - "type": "BOOL" - }, - { - "name": "PID", - "type": "BOOL" - }, - { - "name": "P_K", - "type": "REAL" - }, - { - "name": "PI_K", - "type": "REAL" - }, - { - "name": "PI_TN", - "type": "REAL" - }, - { - "name": "PID_K", - "type": "REAL" - }, - { - "name": "PID_TN", - "type": "REAL" - }, - { - "name": "PID_TV", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "KP", - "type": "REAL" - }, - { - "name": "TN", - "type": "REAL" - }, - { - "name": "TV", - "type": "REAL" - }, - { - "name": "KI", - "type": "REAL" - }, - { - "name": "KD", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "CONTROL_SET2", - "inputs": [ - { - "name": "KS", - "type": "REAL" - }, - { - "name": "TU", - "type": "REAL" - }, - { - "name": "TG", - "type": "REAL" - }, - { - "name": "PI", - "type": "BOOL" - }, - { - "name": "PID", - "type": "BOOL" - }, - { - "name": "P_K", - "type": "REAL" - }, - { - "name": "PI_K", - "type": "REAL" - }, - { - "name": "PI_TN", - "type": "REAL" - }, - { - "name": "PID_K", - "type": "REAL" - }, - { - "name": "PID_TN", - "type": "REAL" - }, - { - "name": "PID_TV", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "KP", - "type": "REAL" - }, - { - "name": "TN", - "type": "REAL" - }, - { - "name": "TV", - "type": "REAL" - }, - { - "name": "KI", - "type": "REAL" - }, - { - "name": "KD", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "COUNT_BR", - "inputs": [ - { - "name": "SET", - "type": "BOOL" - }, - { - "name": "IN", - "type": "BYTE" - }, - { - "name": "UP", - "type": "BOOL" - }, - { - "name": "DN", - "type": "BOOL" - }, - { - "name": "STEP", - "type": "BYTE" - }, - { - "name": "MX", - "type": "BYTE" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "CNT", - "type": "BYTE" - } - ], - "inouts": [] - }, - { - "name": "COUNT_DR", - "inputs": [ - { - "name": "SET", - "type": "BOOL" - }, - { - "name": "IN", - "type": "DWORD" - }, - { - "name": "UP", - "type": "BOOL" - }, - { - "name": "DN", - "type": "BOOL" - }, - { - "name": "STEP", - "type": "DWORD" - }, - { - "name": "MX", - "type": "DWORD" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "CNT", - "type": "DWORD" - } - ], - "inouts": [] - }, - { - "name": "CTRL_OUT", - "inputs": [ - { - "name": "CI", - "type": "REAL" - }, - { - "name": "OFFSET", - "type": "REAL" - }, - { - "name": "MAN_IN", - "type": "REAL" - }, - { - "name": "LIM_L", - "type": "REAL" - }, - { - "name": "LIM_H", - "type": "REAL" - }, - { - "name": "MANUAL", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Y", - "type": "REAL" - }, - { - "name": "LIM", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "CTRL_PI", - "inputs": [ - { - "name": "ACT", - "type": "REAL" - }, - { - "name": "SET", - "type": "REAL" - }, - { - "name": "SUP", - "type": "REAL" - }, - { - "name": "OFS", - "type": "REAL" - }, - { - "name": "M_I", - "type": "REAL" - }, - { - "name": "MAN", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - }, - { - "name": "KP", - "type": "REAL" - }, - { - "name": "KI", - "type": "REAL" - }, - { - "name": "LL", - "type": "REAL" - }, - { - "name": "LH", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "Y", - "type": "REAL" - }, - { - "name": "DIFF", - "type": "REAL" - }, - { - "name": "LIM", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "CTRL_PID", - "inputs": [ - { - "name": "ACT", - "type": "REAL" - }, - { - "name": "SET", - "type": "REAL" - }, - { - "name": "SUP", - "type": "REAL" - }, - { - "name": "OFS", - "type": "REAL" - }, - { - "name": "M_I", - "type": "REAL" - }, - { - "name": "MAN", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - }, - { - "name": "KP", - "type": "REAL" - }, - { - "name": "TN", - "type": "REAL" - }, - { - "name": "TV", - "type": "REAL" - }, - { - "name": "LL", - "type": "REAL" - }, - { - "name": "LH", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "Y", - "type": "REAL" - }, - { - "name": "DIFF", - "type": "REAL" - }, - { - "name": "LIM", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "CTRL_PWM", - "inputs": [ - { - "name": "CI", - "type": "REAL" - }, - { - "name": "MAN_IN", - "type": "REAL" - }, - { - "name": "MANUAL", - "type": "BOOL" - }, - { - "name": "F", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "CYCLE_4", - "inputs": [ - { - "name": "E", - "type": "BOOL" - }, - { - "name": "T0", - "type": "TIME" - }, - { - "name": "T1", - "type": "TIME" - }, - { - "name": "T2", - "type": "TIME" - }, - { - "name": "T3", - "type": "TIME" - }, - { - "name": "S0", - "type": "BOOL" - }, - { - "name": "SX", - "type": "INT" - }, - { - "name": "SL", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "STATE", - "type": "INT" - } - ], - "inouts": [] - }, - { - "name": "CYCLE_TIME", - "inputs": [ - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "CT_MIN", - "type": "TIME" - }, - { - "name": "CT_MAX", - "type": "TIME" - }, - { - "name": "CT_LAST", - "type": "TIME" - }, - { - "name": "SYSTIME", - "type": "TIME" - }, - { - "name": "SYSDAYS", - "type": "INT" - }, - { - "name": "CYCLES", - "type": "DWORD" - } - ], - "inouts": [] - }, - { - "name": "DCF77", - "inputs": [ - { - "name": "REC", - "type": "BOOL" - }, - { - "name": "SET", - "type": "BOOL" - }, - { - "name": "SDT", - "type": "DT" - }, - { - "name": "DSI", - "type": "BOOL" - }, - { - "name": "SYNC_TIMEOUT", - "type": "TIME" - }, - { - "name": "TIME_OFFSET", - "type": "INT" - }, - { - "name": "DST_EN", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "TP", - "type": "BOOL" - }, - { - "name": "DS", - "type": "BOOL" - }, - { - "name": "WDAY", - "type": "INT" - }, - { - "name": "ERROR", - "type": "BOOL" - }, - { - "name": "RTC", - "type": "DT" - }, - { - "name": "RTC1", - "type": "DT" - }, - { - "name": "MSEC", - "type": "INT" - }, - { - "name": "SYNC", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "DEAD_BAND_A", - "inputs": [ - { - "name": "X", - "type": "REAL" - }, - { - "name": "T", - "type": "TIME" - }, - { - "name": "KL", - "type": "REAL" - }, - { - "name": "LM", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "Y", - "type": "REAL" - }, - { - "name": "L", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "DEAD_ZONE2", - "inputs": [ - { - "name": "X", - "type": "REAL" - }, - { - "name": "L", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "Y", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "DEC_2", - "inputs": [ - { - "name": "D", - "type": "BOOL" - }, - { - "name": "A", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q0", - "type": "BOOL" - }, - { - "name": "Q1", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "DEC_4", - "inputs": [ - { - "name": "D", - "type": "BOOL" - }, - { - "name": "A0", - "type": "BOOL" - }, - { - "name": "A1", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q0", - "type": "BOOL" - }, - { - "name": "Q1", - "type": "BOOL" - }, - { - "name": "Q2", - "type": "BOOL" - }, - { - "name": "Q3", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "DEC_8", - "inputs": [ - { - "name": "D", - "type": "BOOL" - }, - { - "name": "A0", - "type": "BOOL" - }, - { - "name": "A1", - "type": "BOOL" - }, - { - "name": "A2", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q0", - "type": "BOOL" - }, - { - "name": "Q1", - "type": "BOOL" - }, - { - "name": "Q2", - "type": "BOOL" - }, - { - "name": "Q3", - "type": "BOOL" - }, - { - "name": "Q4", - "type": "BOOL" - }, - { - "name": "Q5", - "type": "BOOL" - }, - { - "name": "Q6", - "type": "BOOL" - }, - { - "name": "Q7", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "DELAY", - "inputs": [ - { - "name": "IN", - "type": "REAL" - }, - { - "name": "N", - "type": "INT" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "OUT", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "DELAY_4", - "inputs": [ - { - "name": "IN", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "OUT1", - "type": "REAL" - }, - { - "name": "OUT2", - "type": "REAL" - }, - { - "name": "OUT3", - "type": "REAL" - }, - { - "name": "OUT4", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "DRIVER_1", - "inputs": [ - { - "name": "TOGGLE_MODE", - "type": "BOOL" - }, - { - "name": "TIMEOUT", - "type": "TIME" - }, - { - "name": "SET", - "type": "BOOL" - }, - { - "name": "IN", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "DRIVER_4", - "inputs": [ - { - "name": "TOGGLE_MODE", - "type": "BOOL" - }, - { - "name": "TIMEOUT", - "type": "TIME" - }, - { - "name": "SET", - "type": "BOOL" - }, - { - "name": "IN0", - "type": "BOOL" - }, - { - "name": "IN1", - "type": "BOOL" - }, - { - "name": "IN2", - "type": "BOOL" - }, - { - "name": "IN3", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q0", - "type": "BOOL" - }, - { - "name": "Q1", - "type": "BOOL" - }, - { - "name": "Q2", - "type": "BOOL" - }, - { - "name": "Q3", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "DRIVER_4C", - "inputs": [ - { - "name": "IN", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - }, - { - "name": "TIMEOUT", - "type": "TIME" - }, - { - "name": "SX", - "type": "__INLINE_ARRAY_BYTE", - "arrayDimensions": [ - { - "start": 1, - "end": 7 - } - ], - "elementTypeName": "BYTE" - } - ], - "outputs": [ - { - "name": "SN", - "type": "INT" - }, - { - "name": "Q0", - "type": "BOOL" - }, - { - "name": "Q1", - "type": "BOOL" - }, - { - "name": "Q2", - "type": "BOOL" - }, - { - "name": "Q3", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "DT_SIMU", - "inputs": [ - { - "name": "START", - "type": "DT" - }, - { - "name": "SPEED", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "DTS", - "type": "DT" - } - ], - "inouts": [] - }, - { - "name": "D_TRIG", - "inputs": [ - { - "name": "IN", - "type": "DWORD" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - }, - { - "name": "X", - "type": "DWORD" - } - ], - "inouts": [] - }, - { - "name": "ENERGY", - "inputs": [ - { - "name": "J", - "type": "REAL" - }, - { - "name": "C", - "type": "REAL" - }, - { - "name": "WH", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "YJ", - "type": "REAL" - }, - { - "name": "YC", - "type": "REAL" - }, - { - "name": "YWH", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "ESR_COLLECT", - "inputs": [ - { - "name": "ESR_0", - "type": "__INLINE_ARRAY_ESR_DATA", - "arrayDimensions": [ - { - "start": 0, - "end": 3 - } - ], - "elementTypeName": "ESR_DATA" - }, - { - "name": "ESR_1", - "type": "__INLINE_ARRAY_ESR_DATA", - "arrayDimensions": [ - { - "start": 0, - "end": 3 - } - ], - "elementTypeName": "ESR_DATA" - }, - { - "name": "ESR_2", - "type": "__INLINE_ARRAY_ESR_DATA", - "arrayDimensions": [ - { - "start": 0, - "end": 3 - } - ], - "elementTypeName": "ESR_DATA" - }, - { - "name": "ESR_3", - "type": "__INLINE_ARRAY_ESR_DATA", - "arrayDimensions": [ - { - "start": 0, - "end": 3 - } - ], - "elementTypeName": "ESR_DATA" - }, - { - "name": "ESR_4", - "type": "__INLINE_ARRAY_ESR_DATA", - "arrayDimensions": [ - { - "start": 0, - "end": 3 - } - ], - "elementTypeName": "ESR_DATA" - }, - { - "name": "ESR_5", - "type": "__INLINE_ARRAY_ESR_DATA", - "arrayDimensions": [ - { - "start": 0, - "end": 3 - } - ], - "elementTypeName": "ESR_DATA" - }, - { - "name": "ESR_6", - "type": "__INLINE_ARRAY_ESR_DATA", - "arrayDimensions": [ - { - "start": 0, - "end": 3 - } - ], - "elementTypeName": "ESR_DATA" - }, - { - "name": "ESR_7", - "type": "__INLINE_ARRAY_ESR_DATA", - "arrayDimensions": [ - { - "start": 0, - "end": 3 - } - ], - "elementTypeName": "ESR_DATA" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "ESR_OUT", - "type": "__INLINE_ARRAY_ESR_DATA", - "arrayDimensions": [ - { - "start": 0, - "end": 31 - } - ], - "elementTypeName": "ESR_DATA" - } - ], - "inouts": [ - { - "name": "POS", - "type": "INT" - } - ] - }, - { - "name": "ESR_MON_B8", - "inputs": [ - { - "name": "S0", - "type": "BOOL" - }, - { - "name": "S1", - "type": "BOOL" - }, - { - "name": "S2", - "type": "BOOL" - }, - { - "name": "S3", - "type": "BOOL" - }, - { - "name": "S4", - "type": "BOOL" - }, - { - "name": "S5", - "type": "BOOL" - }, - { - "name": "S6", - "type": "BOOL" - }, - { - "name": "S7", - "type": "BOOL" - }, - { - "name": "DT_IN", - "type": "DT" - }, - { - "name": "A0", - "type": "STRING" - }, - { - "name": "A1", - "type": "STRING" - }, - { - "name": "A2", - "type": "STRING" - }, - { - "name": "A3", - "type": "STRING" - }, - { - "name": "A4", - "type": "STRING" - }, - { - "name": "A5", - "type": "STRING" - }, - { - "name": "A6", - "type": "STRING" - }, - { - "name": "A7", - "type": "STRING" - } - ], - "outputs": [ - { - "name": "ESR_FLAG", - "type": "BOOL" - } - ], - "inouts": [ - { - "name": "ESR_OUT", - "type": "__INLINE_ARRAY_ESR_DATA", - "arrayDimensions": [ - { - "start": 0, - "end": 3 - } - ], - "elementTypeName": "ESR_DATA" - } - ] - }, - { - "name": "ESR_MON_R4", - "inputs": [ - { - "name": "R0", - "type": "REAL" - }, - { - "name": "R1", - "type": "REAL" - }, - { - "name": "R2", - "type": "REAL" - }, - { - "name": "R3", - "type": "REAL" - }, - { - "name": "DT_IN", - "type": "DT" - }, - { - "name": "A0", - "type": "STRING" - }, - { - "name": "A1", - "type": "STRING" - }, - { - "name": "A2", - "type": "STRING" - }, - { - "name": "A3", - "type": "STRING" - }, - { - "name": "S0", - "type": "REAL" - }, - { - "name": "S1", - "type": "REAL" - }, - { - "name": "S2", - "type": "REAL" - }, - { - "name": "S3", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "ESR_FLAG", - "type": "BOOL" - } - ], - "inouts": [ - { - "name": "ESR_OUT", - "type": "__INLINE_ARRAY_ESR_DATA", - "arrayDimensions": [ - { - "start": 0, - "end": 3 - } - ], - "elementTypeName": "ESR_DATA" - } - ] - }, - { - "name": "ESR_MON_X8", - "inputs": [ - { - "name": "S0", - "type": "BYTE" - }, - { - "name": "S1", - "type": "BYTE" - }, - { - "name": "S2", - "type": "BYTE" - }, - { - "name": "S3", - "type": "BYTE" - }, - { - "name": "S4", - "type": "BYTE" - }, - { - "name": "S5", - "type": "BYTE" - }, - { - "name": "S6", - "type": "BYTE" - }, - { - "name": "S7", - "type": "BYTE" - }, - { - "name": "DT_IN", - "type": "DT" - }, - { - "name": "MODE", - "type": "BYTE" - }, - { - "name": "A0", - "type": "STRING" - }, - { - "name": "A1", - "type": "STRING" - }, - { - "name": "A2", - "type": "STRING" - }, - { - "name": "A3", - "type": "STRING" - }, - { - "name": "A4", - "type": "STRING" - }, - { - "name": "A5", - "type": "STRING" - }, - { - "name": "A6", - "type": "STRING" - }, - { - "name": "A7", - "type": "STRING" - } - ], - "outputs": [ - { - "name": "ESR_FLAG", - "type": "BOOL" - } - ], - "inouts": [ - { - "name": "ESR_OUT", - "type": "__INLINE_ARRAY_ESR_DATA", - "arrayDimensions": [ - { - "start": 0, - "end": 3 - } - ], - "elementTypeName": "ESR_DATA" - } - ] - }, - { - "name": "EVENTS", - "inputs": [ - { - "name": "DATE_IN", - "type": "DATE" - }, - { - "name": "ENA", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Y", - "type": "BOOL" - }, - { - "name": "NAME", - "type": "STRING" - } - ], - "inouts": [ - { - "name": "ELIST", - "type": "__INLINE_ARRAY_HOLIDAY_DATA", - "arrayDimensions": [ - { - "start": 0, - "end": 49 - } - ], - "elementTypeName": "HOLIDAY_DATA" - } - ] - }, - { - "name": "FADE", - "inputs": [ - { - "name": "IN1", - "type": "REAL" - }, - { - "name": "IN2", - "type": "REAL" - }, - { - "name": "F", - "type": "BOOL" - }, - { - "name": "TF", - "type": "TIME" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Y", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "FF_D2E", - "inputs": [ - { - "name": "D0", - "type": "BOOL" - }, - { - "name": "D1", - "type": "BOOL" - }, - { - "name": "CLK", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q0", - "type": "BOOL" - }, - { - "name": "Q1", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "FF_D4E", - "inputs": [ - { - "name": "D0", - "type": "BOOL" - }, - { - "name": "D1", - "type": "BOOL" - }, - { - "name": "D2", - "type": "BOOL" - }, - { - "name": "D3", - "type": "BOOL" - }, - { - "name": "CLK", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q0", - "type": "BOOL" - }, - { - "name": "Q1", - "type": "BOOL" - }, - { - "name": "Q2", - "type": "BOOL" - }, - { - "name": "Q3", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "FF_DRE", - "inputs": [ - { - "name": "SET", - "type": "BOOL" - }, - { - "name": "D", - "type": "BOOL" - }, - { - "name": "CLK", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "FF_JKE", - "inputs": [ - { - "name": "SET", - "type": "BOOL" - }, - { - "name": "J", - "type": "BOOL" - }, - { - "name": "CLK", - "type": "BOOL" - }, - { - "name": "K", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "FF_RSE", - "inputs": [ - { - "name": "CS", - "type": "BOOL" - }, - { - "name": "CR", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "FIFO_16", - "inputs": [ - { - "name": "DIN", - "type": "DWORD" - }, - { - "name": "E", - "type": "BOOL" - }, - { - "name": "RD", - "type": "BOOL" - }, - { - "name": "WD", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "DOUT", - "type": "DWORD" - }, - { - "name": "EMPTY", - "type": "BOOL" - }, - { - "name": "FULL", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "FIFO_32", - "inputs": [ - { - "name": "DIN", - "type": "DWORD" - }, - { - "name": "E", - "type": "BOOL" - }, - { - "name": "RD", - "type": "BOOL" - }, - { - "name": "WD", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "DOUT", - "type": "DWORD" - }, - { - "name": "EMPTY", - "type": "BOOL" - }, - { - "name": "FULL", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "FILTER_DW", - "inputs": [ - { - "name": "X", - "type": "DWORD" - }, - { - "name": "T", - "type": "TIME" - } - ], - "outputs": [ - { - "name": "Y", - "type": "DWORD" - } - ], - "inouts": [] - }, - { - "name": "FILTER_I", - "inputs": [ - { - "name": "X", - "type": "INT" - }, - { - "name": "T", - "type": "TIME" - } - ], - "outputs": [ - { - "name": "Y", - "type": "INT" - } - ], - "inouts": [] - }, - { - "name": "FILTER_MAV_DW", - "inputs": [ - { - "name": "X", - "type": "DWORD" - }, - { - "name": "N", - "type": "UINT" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Y", - "type": "DWORD" - } - ], - "inouts": [] - }, - { - "name": "FILTER_MAV_W", - "inputs": [ - { - "name": "X", - "type": "WORD" - }, - { - "name": "N", - "type": "UINT" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Y", - "type": "WORD" - } - ], - "inouts": [] - }, - { - "name": "FILTER_W", - "inputs": [ - { - "name": "X", - "type": "WORD" - }, - { - "name": "T", - "type": "TIME" - } - ], - "outputs": [ - { - "name": "Y", - "type": "WORD" - } - ], - "inouts": [] - }, - { - "name": "FILTER_WAV", - "inputs": [ - { - "name": "X", - "type": "REAL" - }, - { - "name": "W", - "type": "__INLINE_ARRAY_REAL", - "arrayDimensions": [ - { - "start": 0, - "end": 15 - } - ], - "elementTypeName": "REAL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Y", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "FLOW_METER", - "inputs": [ - { - "name": "VX", - "type": "REAL" - }, - { - "name": "E", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - }, - { - "name": "PULSE_MODE", - "type": "BOOL" - }, - { - "name": "UPDATE_TIME", - "type": "TIME" - } - ], - "outputs": [ - { - "name": "F", - "type": "REAL" - } - ], - "inouts": [ - { - "name": "X", - "type": "REAL" - }, - { - "name": "Y", - "type": "UDINT" - } - ] - }, - { - "name": "FT_AVG", - "inputs": [ - { - "name": "IN", - "type": "REAL" - }, - { - "name": "E", - "type": "BOOL" - }, - { - "name": "N", - "type": "INT" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "AVG", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "FT_DERIV", - "inputs": [ - { - "name": "IN", - "type": "REAL" - }, - { - "name": "K", - "type": "REAL" - }, - { - "name": "RUN", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "OUT", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "FT_IMP", - "inputs": [ - { - "name": "IN", - "type": "REAL" - }, - { - "name": "T", - "type": "TIME" - }, - { - "name": "K", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "OUT", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "FT_INT", - "inputs": [ - { - "name": "IN", - "type": "REAL" - }, - { - "name": "K", - "type": "REAL" - }, - { - "name": "RUN", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - }, - { - "name": "OUT_MIN", - "type": "REAL" - }, - { - "name": "OUT_MAX", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "OUT", - "type": "REAL" - }, - { - "name": "LIM", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "FT_INT2", - "inputs": [ - { - "name": "IN", - "type": "REAL" - }, - { - "name": "K", - "type": "REAL" - }, - { - "name": "RUN", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - }, - { - "name": "OUT_MIN", - "type": "REAL" - }, - { - "name": "OUT_MAX", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "OUT", - "type": "REAL" - }, - { - "name": "LIM", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "FT_MIN_MAX", - "inputs": [ - { - "name": "IN", - "type": "REAL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "MX", - "type": "REAL" - }, - { - "name": "MN", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "FT_PD", - "inputs": [ - { - "name": "IN", - "type": "REAL" - }, - { - "name": "KP", - "type": "REAL" - }, - { - "name": "TV", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "Y", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "FT_PDT1", - "inputs": [ - { - "name": "IN", - "type": "REAL" - }, - { - "name": "KP", - "type": "REAL" - }, - { - "name": "TV", - "type": "REAL" - }, - { - "name": "T1", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "Y", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "FT_PI", - "inputs": [ - { - "name": "IN", - "type": "REAL" - }, - { - "name": "KP", - "type": "REAL" - }, - { - "name": "KI", - "type": "REAL" - }, - { - "name": "ILIM_L", - "type": "REAL" - }, - { - "name": "ILIM_H", - "type": "REAL" - }, - { - "name": "IEN", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Y", - "type": "REAL" - }, - { - "name": "LIM", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "FT_PID", - "inputs": [ - { - "name": "IN", - "type": "REAL" - }, - { - "name": "KP", - "type": "REAL" - }, - { - "name": "TN", - "type": "REAL" - }, - { - "name": "TV", - "type": "REAL" - }, - { - "name": "ILIM_L", - "type": "REAL" - }, - { - "name": "ILIM_H", - "type": "REAL" - }, - { - "name": "IEN", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Y", - "type": "REAL" - }, - { - "name": "LIM", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "FT_PIDW", - "inputs": [ - { - "name": "IN", - "type": "REAL" - }, - { - "name": "KP", - "type": "REAL" - }, - { - "name": "TN", - "type": "REAL" - }, - { - "name": "TV", - "type": "REAL" - }, - { - "name": "LIM_L", - "type": "REAL" - }, - { - "name": "LIM_H", - "type": "REAL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Y", - "type": "REAL" - }, - { - "name": "LIM", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "FT_PIDWL", - "inputs": [ - { - "name": "IN", - "type": "REAL" - }, - { - "name": "KP", - "type": "REAL" - }, - { - "name": "TN", - "type": "REAL" - }, - { - "name": "TV", - "type": "REAL" - }, - { - "name": "LIM_L", - "type": "REAL" - }, - { - "name": "LIM_H", - "type": "REAL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Y", - "type": "REAL" - }, - { - "name": "LIM", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "FT_PIW", - "inputs": [ - { - "name": "IN", - "type": "REAL" - }, - { - "name": "KP", - "type": "REAL" - }, - { - "name": "KI", - "type": "REAL" - }, - { - "name": "LIM_L", - "type": "REAL" - }, - { - "name": "LIM_H", - "type": "REAL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Y", - "type": "REAL" - }, - { - "name": "LIM", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "FT_PIWL", - "inputs": [ - { - "name": "IN", - "type": "REAL" - }, - { - "name": "KP", - "type": "REAL" - }, - { - "name": "KI", - "type": "REAL" - }, - { - "name": "LIM_L", - "type": "REAL" - }, - { - "name": "LIM_H", - "type": "REAL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Y", - "type": "REAL" - }, - { - "name": "LIM", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "FT_PT1", - "inputs": [ - { - "name": "IN", - "type": "REAL" - }, - { - "name": "T", - "type": "TIME" - }, - { - "name": "K", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "OUT", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "FT_PT2", - "inputs": [ - { - "name": "IN", - "type": "REAL" - }, - { - "name": "T", - "type": "TIME" - }, - { - "name": "D", - "type": "REAL" - }, - { - "name": "K", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "OUT", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "FT_PROFILE", - "inputs": [ - { - "name": "K", - "type": "REAL" - }, - { - "name": "O", - "type": "REAL" - }, - { - "name": "M", - "type": "REAL" - }, - { - "name": "E", - "type": "BOOL" - }, - { - "name": "VALUE_0", - "type": "REAL" - }, - { - "name": "TIME_1", - "type": "TIME" - }, - { - "name": "VALUE_1", - "type": "REAL" - }, - { - "name": "TIME_2", - "type": "TIME" - }, - { - "name": "VALUE_2", - "type": "REAL" - }, - { - "name": "TIME_3", - "type": "TIME" - }, - { - "name": "VALUE_3", - "type": "REAL" - }, - { - "name": "TIME_10", - "type": "TIME" - }, - { - "name": "VALUE_10", - "type": "REAL" - }, - { - "name": "TIME_11", - "type": "TIME" - }, - { - "name": "VALUE_11", - "type": "REAL" - }, - { - "name": "TIME_12", - "type": "TIME" - }, - { - "name": "VALUE_12", - "type": "REAL" - }, - { - "name": "TIME_13", - "type": "TIME" - }, - { - "name": "VALUE_13", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "Y", - "type": "REAL" - }, - { - "name": "RUN", - "type": "BOOL" - }, - { - "name": "ET", - "type": "TIME" - } - ], - "inouts": [] - }, - { - "name": "FT_RMP", - "inputs": [ - { - "name": "RMP", - "type": "BOOL" - }, - { - "name": "IN", - "type": "REAL" - }, - { - "name": "KR", - "type": "REAL" - }, - { - "name": "KF", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "OUT", - "type": "REAL" - }, - { - "name": "BUSY", - "type": "BOOL" - }, - { - "name": "UD", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "FT_TN16", - "inputs": [ - { - "name": "IN", - "type": "REAL" - }, - { - "name": "T", - "type": "TIME" - } - ], - "outputs": [ - { - "name": "OUT", - "type": "REAL" - }, - { - "name": "TRIG", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "FT_TN64", - "inputs": [ - { - "name": "IN", - "type": "REAL" - }, - { - "name": "T", - "type": "TIME" - } - ], - "outputs": [ - { - "name": "OUT", - "type": "REAL" - }, - { - "name": "TRIG", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "FT_TN8", - "inputs": [ - { - "name": "IN", - "type": "REAL" - }, - { - "name": "T", - "type": "TIME" - } - ], - "outputs": [ - { - "name": "OUT", - "type": "REAL" - }, - { - "name": "TRIG", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "GEN_BIT", - "inputs": [ - { - "name": "IN0", - "type": "DWORD" - }, - { - "name": "IN1", - "type": "DWORD" - }, - { - "name": "IN2", - "type": "DWORD" - }, - { - "name": "IN3", - "type": "DWORD" - }, - { - "name": "CLK", - "type": "BOOL" - }, - { - "name": "STEPS", - "type": "INT" - }, - { - "name": "REP", - "type": "INT" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q0", - "type": "BOOL" - }, - { - "name": "Q1", - "type": "BOOL" - }, - { - "name": "Q2", - "type": "BOOL" - }, - { - "name": "Q3", - "type": "BOOL" - }, - { - "name": "CNT", - "type": "INT" - }, - { - "name": "RUN", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "GEN_PULSE", - "inputs": [ - { - "name": "ENQ", - "type": "BOOL" - }, - { - "name": "PTH", - "type": "TIME" - }, - { - "name": "PTL", - "type": "TIME" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "GEN_PW2", - "inputs": [ - { - "name": "ENQ", - "type": "BOOL" - }, - { - "name": "TH1", - "type": "TIME" - }, - { - "name": "TL1", - "type": "TIME" - }, - { - "name": "TH2", - "type": "TIME" - }, - { - "name": "TL2", - "type": "TIME" - }, - { - "name": "TS", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - }, - { - "name": "TH", - "type": "TIME" - }, - { - "name": "TL", - "type": "TIME" - } - ], - "inouts": [] - }, - { - "name": "GEN_RDM", - "inputs": [ - { - "name": "PT", - "type": "TIME" - }, - { - "name": "AM", - "type": "REAL" - }, - { - "name": "OS", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - }, - { - "name": "OUT", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "GEN_RDT", - "inputs": [ - { - "name": "ENABLE", - "type": "BOOL" - }, - { - "name": "MIN_TIME_MS", - "type": "TIME" - }, - { - "name": "MAX_TIME_MS", - "type": "TIME" - }, - { - "name": "TP_Q", - "type": "TIME" - } - ], - "outputs": [ - { - "name": "XQ", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "GEN_RMP", - "inputs": [ - { - "name": "PT", - "type": "TIME" - }, - { - "name": "AM", - "type": "REAL" - }, - { - "name": "OS", - "type": "REAL" - }, - { - "name": "DL", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - }, - { - "name": "OUT", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "GEN_SIN", - "inputs": [ - { - "name": "PT", - "type": "TIME" - }, - { - "name": "AM", - "type": "REAL" - }, - { - "name": "OS", - "type": "REAL" - }, - { - "name": "DL", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - }, - { - "name": "OUT", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "GEN_SQ", - "inputs": [ - { - "name": "PT", - "type": "TIME" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "GEN_SQR", - "inputs": [ - { - "name": "PT", - "type": "TIME" - }, - { - "name": "AM", - "type": "REAL" - }, - { - "name": "OS", - "type": "REAL" - }, - { - "name": "DC", - "type": "REAL" - }, - { - "name": "DL", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - }, - { - "name": "OUT", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "HOLIDAY", - "inputs": [ - { - "name": "DATE_IN", - "type": "DATE" - }, - { - "name": "LANGU", - "type": "INT" - }, - { - "name": "FRIDAY", - "type": "BOOL" - }, - { - "name": "SATURDAY", - "type": "BOOL" - }, - { - "name": "SUNDAY", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Y", - "type": "BOOL" - }, - { - "name": "NAME", - "type": "STRING" - } - ], - "inouts": [ - { - "name": "HOLIDAYS", - "type": "__INLINE_ARRAY_HOLIDAY_DATA", - "arrayDimensions": [ - { - "start": 0, - "end": 29 - } - ], - "elementTypeName": "HOLIDAY_DATA" - } - ] - }, - { - "name": "HYST", - "inputs": [ - { - "name": "IN", - "type": "REAL" - }, - { - "name": "ON", - "type": "REAL" - }, - { - "name": "OFF", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - }, - { - "name": "WIN", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "HYST_1", - "inputs": [ - { - "name": "IN", - "type": "REAL" - }, - { - "name": "HIGH", - "type": "REAL" - }, - { - "name": "LOW", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - }, - { - "name": "WIN", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "HYST_2", - "inputs": [ - { - "name": "IN", - "type": "REAL" - }, - { - "name": "VAL", - "type": "REAL" - }, - { - "name": "HYS", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - }, - { - "name": "WIN", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "HYST_3", - "inputs": [ - { - "name": "IN", - "type": "REAL" - }, - { - "name": "HYST", - "type": "REAL" - }, - { - "name": "VAL1", - "type": "REAL" - }, - { - "name": "VAL2", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "Q1", - "type": "BOOL" - }, - { - "name": "Q2", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "INC_DEC", - "inputs": [ - { - "name": "CHA", - "type": "BOOL" - }, - { - "name": "CHB", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "DIR", - "type": "BOOL" - }, - { - "name": "CNT", - "type": "INT" - } - ], - "inouts": [] - }, - { - "name": "INTEGRATE", - "inputs": [ - { - "name": "E", - "type": "BOOL" - }, - { - "name": "X", - "type": "REAL" - }, - { - "name": "K", - "type": "REAL" - } - ], - "outputs": [], - "inouts": [ - { - "name": "Y", - "type": "REAL" - } - ] - }, - { - "name": "INTERLOCK", - "inputs": [ - { - "name": "I1", - "type": "BOOL" - }, - { - "name": "I2", - "type": "BOOL" - }, - { - "name": "TL", - "type": "TIME" - } - ], - "outputs": [ - { - "name": "Q1", - "type": "BOOL" - }, - { - "name": "Q2", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "INTERLOCK_4", - "inputs": [ - { - "name": "I0", - "type": "BOOL" - }, - { - "name": "I1", - "type": "BOOL" - }, - { - "name": "I2", - "type": "BOOL" - }, - { - "name": "I3", - "type": "BOOL" - }, - { - "name": "E", - "type": "BOOL" - }, - { - "name": "MODE", - "type": "INT" - } - ], - "outputs": [ - { - "name": "OUT", - "type": "BYTE" - }, - { - "name": "TP", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "LENGTH", - "inputs": [ - { - "name": "M", - "type": "REAL" - }, - { - "name": "P", - "type": "REAL" - }, - { - "name": "IN", - "type": "REAL" - }, - { - "name": "FT", - "type": "REAL" - }, - { - "name": "YD", - "type": "REAL" - }, - { - "name": "MILE", - "type": "REAL" - }, - { - "name": "SM", - "type": "REAL" - }, - { - "name": "FM", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "YM", - "type": "REAL" - }, - { - "name": "YP", - "type": "REAL" - }, - { - "name": "YIN", - "type": "REAL" - }, - { - "name": "YFT", - "type": "REAL" - }, - { - "name": "YYD", - "type": "REAL" - }, - { - "name": "YMILE", - "type": "REAL" - }, - { - "name": "YSM", - "type": "REAL" - }, - { - "name": "YFM", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "LIST_NEXT", - "inputs": [ - { - "name": "SEP", - "type": "BYTE" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "LEL", - "type": "STRING" - }, - { - "name": "NUL", - "type": "BOOL" - } - ], - "inouts": [ - { - "name": "LIST", - "type": "STRING" - } - ] - }, - { - "name": "LTCH", - "inputs": [ - { - "name": "D", - "type": "BOOL" - }, - { - "name": "L", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "LTCH_4", - "inputs": [ - { - "name": "D0", - "type": "BOOL" - }, - { - "name": "D1", - "type": "BOOL" - }, - { - "name": "D2", - "type": "BOOL" - }, - { - "name": "D3", - "type": "BOOL" - }, - { - "name": "L", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q0", - "type": "BOOL" - }, - { - "name": "Q1", - "type": "BOOL" - }, - { - "name": "Q2", - "type": "BOOL" - }, - { - "name": "Q3", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "MANUAL_1", - "inputs": [ - { - "name": "IN", - "type": "BOOL" - }, - { - "name": "MAN", - "type": "BOOL" - }, - { - "name": "M_I", - "type": "BOOL" - }, - { - "name": "SET", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - }, - { - "name": "STATUS", - "type": "BYTE" - } - ], - "inouts": [] - }, - { - "name": "MANUAL_2", - "inputs": [ - { - "name": "IN", - "type": "BOOL" - }, - { - "name": "ENA", - "type": "BOOL" - }, - { - "name": "ON", - "type": "BOOL" - }, - { - "name": "OFF", - "type": "BOOL" - }, - { - "name": "MAN", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - }, - { - "name": "STATUS", - "type": "BYTE" - } - ], - "inouts": [] - }, - { - "name": "MANUAL_4", - "inputs": [ - { - "name": "I0", - "type": "BOOL" - }, - { - "name": "I1", - "type": "BOOL" - }, - { - "name": "I2", - "type": "BOOL" - }, - { - "name": "I3", - "type": "BOOL" - }, - { - "name": "MAN", - "type": "BOOL" - }, - { - "name": "STP", - "type": "BOOL" - }, - { - "name": "M0", - "type": "BOOL" - }, - { - "name": "M1", - "type": "BOOL" - }, - { - "name": "M2", - "type": "BOOL" - }, - { - "name": "M3", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q0", - "type": "BOOL" - }, - { - "name": "Q1", - "type": "BOOL" - }, - { - "name": "Q2", - "type": "BOOL" - }, - { - "name": "Q3", - "type": "BOOL" - }, - { - "name": "STATUS", - "type": "BYTE" - } - ], - "inouts": [] - }, - { - "name": "MATRIX", - "inputs": [ - { - "name": "X1", - "type": "BOOL" - }, - { - "name": "X2", - "type": "BOOL" - }, - { - "name": "X3", - "type": "BOOL" - }, - { - "name": "X4", - "type": "BOOL" - }, - { - "name": "X5", - "type": "BOOL" - }, - { - "name": "RELEASE", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "CODE", - "type": "BYTE" - }, - { - "name": "TP", - "type": "BOOL" - }, - { - "name": "Y1", - "type": "BOOL" - }, - { - "name": "Y2", - "type": "BOOL" - }, - { - "name": "Y3", - "type": "BOOL" - }, - { - "name": "Y4", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "MESSAGE_4R", - "inputs": [ - { - "name": "M0", - "type": "STRING" - }, - { - "name": "M1", - "type": "STRING" - }, - { - "name": "M2", - "type": "STRING" - }, - { - "name": "M3", - "type": "STRING" - }, - { - "name": "MM", - "type": "INT" - }, - { - "name": "ENQ", - "type": "BOOL" - }, - { - "name": "CLK", - "type": "BOOL" - }, - { - "name": "T1", - "type": "TIME" - } - ], - "outputs": [ - { - "name": "MX", - "type": "STRING" - }, - { - "name": "MN", - "type": "INT" - }, - { - "name": "TR", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "MESSAGE_8", - "inputs": [ - { - "name": "IN1", - "type": "BOOL" - }, - { - "name": "IN2", - "type": "BOOL" - }, - { - "name": "IN3", - "type": "BOOL" - }, - { - "name": "IN4", - "type": "BOOL" - }, - { - "name": "IN5", - "type": "BOOL" - }, - { - "name": "IN6", - "type": "BOOL" - }, - { - "name": "IN7", - "type": "BOOL" - }, - { - "name": "IN8", - "type": "BOOL" - }, - { - "name": "S1", - "type": "STRING" - }, - { - "name": "S2", - "type": "STRING" - }, - { - "name": "S3", - "type": "STRING" - }, - { - "name": "S4", - "type": "STRING" - }, - { - "name": "S5", - "type": "STRING" - }, - { - "name": "S6", - "type": "STRING" - }, - { - "name": "S7", - "type": "STRING" - }, - { - "name": "S8", - "type": "STRING" - } - ], - "outputs": [ - { - "name": "M", - "type": "STRING" - } - ], - "inouts": [] - }, - { - "name": "METER", - "inputs": [ - { - "name": "M1", - "type": "REAL" - }, - { - "name": "M2", - "type": "REAL" - }, - { - "name": "I1", - "type": "BOOL" - }, - { - "name": "I2", - "type": "BOOL" - }, - { - "name": "D", - "type": "REAL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [], - "inouts": [ - { - "name": "MX", - "type": "REAL" - } - ] - }, - { - "name": "METER_STAT", - "inputs": [ - { - "name": "IN", - "type": "REAL" - }, - { - "name": "DI", - "type": "DATE" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [], - "inouts": [ - { - "name": "LAST_DAY", - "type": "REAL" - }, - { - "name": "CURRENT_DAY", - "type": "REAL" - }, - { - "name": "LAST_WEEK", - "type": "REAL" - }, - { - "name": "CURRENT_WEEK", - "type": "REAL" - }, - { - "name": "LAST_MONTH", - "type": "REAL" - }, - { - "name": "CURRENT_MONTH", - "type": "REAL" - }, - { - "name": "LAST_YEAR", - "type": "REAL" - }, - { - "name": "CURRENT_YEAR", - "type": "REAL" - } - ] - }, - { - "name": "M_D", - "inputs": [ - { - "name": "START", - "type": "BOOL" - }, - { - "name": "STOP", - "type": "BOOL" - }, - { - "name": "TMAX", - "type": "TIME" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "PT", - "type": "TIME" - }, - { - "name": "ET", - "type": "TIME" - }, - { - "name": "RUN", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "M_T", - "inputs": [ - { - "name": "IN", - "type": "BOOL" - }, - { - "name": "TMAX", - "type": "TIME" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "PT", - "type": "TIME" - }, - { - "name": "ET", - "type": "TIME" - } - ], - "inouts": [] - }, - { - "name": "M_TX", - "inputs": [ - { - "name": "IN", - "type": "BOOL" - }, - { - "name": "TMAX", - "type": "TIME" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "TH", - "type": "TIME" - }, - { - "name": "TL", - "type": "TIME" - }, - { - "name": "DC", - "type": "REAL" - }, - { - "name": "F", - "type": "REAL" - }, - { - "name": "ET", - "type": "TIME" - } - ], - "inouts": [] - }, - { - "name": "ONTIME", - "inputs": [ - { - "name": "IN", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [], - "inouts": [ - { - "name": "SECONDS", - "type": "UDINT" - }, - { - "name": "CYCLES", - "type": "UDINT" - } - ] - }, - { - "name": "PARSET", - "inputs": [ - { - "name": "A0", - "type": "BOOL" - }, - { - "name": "A1", - "type": "BOOL" - }, - { - "name": "X01", - "type": "REAL" - }, - { - "name": "X02", - "type": "REAL" - }, - { - "name": "X03", - "type": "REAL" - }, - { - "name": "X04", - "type": "REAL" - }, - { - "name": "X11", - "type": "REAL" - }, - { - "name": "X12", - "type": "REAL" - }, - { - "name": "X13", - "type": "REAL" - }, - { - "name": "X14", - "type": "REAL" - }, - { - "name": "X21", - "type": "REAL" - }, - { - "name": "X22", - "type": "REAL" - }, - { - "name": "X23", - "type": "REAL" - }, - { - "name": "X24", - "type": "REAL" - }, - { - "name": "X31", - "type": "REAL" - }, - { - "name": "X32", - "type": "REAL" - }, - { - "name": "X33", - "type": "REAL" - }, - { - "name": "X34", - "type": "REAL" - }, - { - "name": "TC", - "type": "TIME" - } - ], - "outputs": [ - { - "name": "P1", - "type": "REAL" - }, - { - "name": "P2", - "type": "REAL" - }, - { - "name": "P3", - "type": "REAL" - }, - { - "name": "P4", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "PARSET2", - "inputs": [ - { - "name": "X", - "type": "REAL" - }, - { - "name": "X01", - "type": "REAL" - }, - { - "name": "X02", - "type": "REAL" - }, - { - "name": "X03", - "type": "REAL" - }, - { - "name": "X04", - "type": "REAL" - }, - { - "name": "X11", - "type": "REAL" - }, - { - "name": "X12", - "type": "REAL" - }, - { - "name": "X13", - "type": "REAL" - }, - { - "name": "X14", - "type": "REAL" - }, - { - "name": "X21", - "type": "REAL" - }, - { - "name": "X22", - "type": "REAL" - }, - { - "name": "X23", - "type": "REAL" - }, - { - "name": "X24", - "type": "REAL" - }, - { - "name": "X31", - "type": "REAL" - }, - { - "name": "X32", - "type": "REAL" - }, - { - "name": "X33", - "type": "REAL" - }, - { - "name": "X34", - "type": "REAL" - }, - { - "name": "L1", - "type": "REAL" - }, - { - "name": "L2", - "type": "REAL" - }, - { - "name": "L3", - "type": "REAL" - }, - { - "name": "TC", - "type": "TIME" - } - ], - "outputs": [ - { - "name": "P1", - "type": "REAL" - }, - { - "name": "P2", - "type": "REAL" - }, - { - "name": "P3", - "type": "REAL" - }, - { - "name": "P4", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "PIN_CODE", - "inputs": [ - { - "name": "CB", - "type": "BYTE" - }, - { - "name": "E", - "type": "BOOL" - }, - { - "name": "PIN", - "type": "STRING" - } - ], - "outputs": [ - { - "name": "TP", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "PRESSURE", - "inputs": [ - { - "name": "MWS", - "type": "REAL" - }, - { - "name": "TORR", - "type": "REAL" - }, - { - "name": "ATT", - "type": "REAL" - }, - { - "name": "ATM", - "type": "REAL" - }, - { - "name": "PA", - "type": "REAL" - }, - { - "name": "BAR", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "YMWS", - "type": "REAL" - }, - { - "name": "YTORR", - "type": "REAL" - }, - { - "name": "YATT", - "type": "REAL" - }, - { - "name": "YATM", - "type": "REAL" - }, - { - "name": "YPA", - "type": "REAL" - }, - { - "name": "YBAR", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "PWM_DC", - "inputs": [ - { - "name": "F", - "type": "REAL" - }, - { - "name": "DC", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "PWM_PW", - "inputs": [ - { - "name": "F", - "type": "REAL" - }, - { - "name": "PW", - "type": "TIME" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "RMP_B", - "inputs": [ - { - "name": "SET", - "type": "BOOL" - }, - { - "name": "PT", - "type": "TIME" - }, - { - "name": "E", - "type": "BOOL" - }, - { - "name": "UP", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "OUT", - "type": "BYTE" - }, - { - "name": "BUSY", - "type": "BOOL" - }, - { - "name": "HIGH", - "type": "BOOL" - }, - { - "name": "LOW", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "RMP_SOFT", - "inputs": [ - { - "name": "IN", - "type": "BOOL" - }, - { - "name": "VAL", - "type": "BYTE" - }, - { - "name": "PT_ON", - "type": "TIME" - }, - { - "name": "PT_OFF", - "type": "TIME" - } - ], - "outputs": [ - { - "name": "OUT", - "type": "BYTE" - } - ], - "inouts": [] - }, - { - "name": "RMP_W", - "inputs": [ - { - "name": "SET", - "type": "BOOL" - }, - { - "name": "PT", - "type": "TIME" - }, - { - "name": "E", - "type": "BOOL" - }, - { - "name": "UP", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "OUT", - "type": "WORD" - }, - { - "name": "BUSY", - "type": "BOOL" - }, - { - "name": "HIGH", - "type": "BOOL" - }, - { - "name": "LOW", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "RTC_2", - "inputs": [ - { - "name": "SET", - "type": "BOOL" - }, - { - "name": "SDT", - "type": "DT" - }, - { - "name": "SMS", - "type": "INT" - }, - { - "name": "DEN", - "type": "BOOL" - }, - { - "name": "OFS", - "type": "INT" - } - ], - "outputs": [ - { - "name": "UDT", - "type": "DT" - }, - { - "name": "LOCAL_DT", - "type": "DT" - }, - { - "name": "DSO", - "type": "BOOL" - }, - { - "name": "XMS", - "type": "INT" - } - ], - "inouts": [] - }, - { - "name": "RTC_MS", - "inputs": [ - { - "name": "SET", - "type": "BOOL" - }, - { - "name": "SDT", - "type": "DT" - }, - { - "name": "SMS", - "type": "INT" - } - ], - "outputs": [ - { - "name": "XDT", - "type": "DT" - }, - { - "name": "XMS", - "type": "INT" - } - ], - "inouts": [] - }, - { - "name": "SCHEDULER", - "inputs": [ - { - "name": "E0", - "type": "BOOL" - }, - { - "name": "E1", - "type": "BOOL" - }, - { - "name": "E2", - "type": "BOOL" - }, - { - "name": "E3", - "type": "BOOL" - }, - { - "name": "T0", - "type": "TIME" - }, - { - "name": "T1", - "type": "TIME" - }, - { - "name": "T2", - "type": "TIME" - }, - { - "name": "T3", - "type": "TIME" - } - ], - "outputs": [ - { - "name": "Q0", - "type": "BOOL" - }, - { - "name": "Q1", - "type": "BOOL" - }, - { - "name": "Q2", - "type": "BOOL" - }, - { - "name": "Q3", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "SCHEDULER_2", - "inputs": [ - { - "name": "E0", - "type": "BOOL" - }, - { - "name": "E1", - "type": "BOOL" - }, - { - "name": "E2", - "type": "BOOL" - }, - { - "name": "E3", - "type": "BOOL" - }, - { - "name": "C0", - "type": "UINT" - }, - { - "name": "C1", - "type": "UINT" - }, - { - "name": "C2", - "type": "UINT" - }, - { - "name": "C3", - "type": "UINT" - }, - { - "name": "O0", - "type": "UINT" - }, - { - "name": "O1", - "type": "UINT" - }, - { - "name": "O2", - "type": "UINT" - }, - { - "name": "O3", - "type": "UINT" - } - ], - "outputs": [ - { - "name": "Q0", - "type": "BOOL" - }, - { - "name": "Q1", - "type": "BOOL" - }, - { - "name": "Q2", - "type": "BOOL" - }, - { - "name": "Q3", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "SEL2_OF_3", - "inputs": [ - { - "name": "IN1", - "type": "REAL" - }, - { - "name": "IN2", - "type": "REAL" - }, - { - "name": "IN3", - "type": "REAL" - }, - { - "name": "D", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "Y", - "type": "REAL" - }, - { - "name": "W", - "type": "INT" - }, - { - "name": "E", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "SEL2_OF_3B", - "inputs": [ - { - "name": "IN1", - "type": "BOOL" - }, - { - "name": "IN2", - "type": "BOOL" - }, - { - "name": "IN3", - "type": "BOOL" - }, - { - "name": "TD", - "type": "TIME" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - }, - { - "name": "W", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "SELECT_8", - "inputs": [ - { - "name": "E", - "type": "BOOL" - }, - { - "name": "SET", - "type": "BOOL" - }, - { - "name": "IN", - "type": "BYTE" - }, - { - "name": "UP", - "type": "BOOL" - }, - { - "name": "DN", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q0", - "type": "BOOL" - }, - { - "name": "Q1", - "type": "BOOL" - }, - { - "name": "Q2", - "type": "BOOL" - }, - { - "name": "Q3", - "type": "BOOL" - }, - { - "name": "Q4", - "type": "BOOL" - }, - { - "name": "Q5", - "type": "BOOL" - }, - { - "name": "Q6", - "type": "BOOL" - }, - { - "name": "Q7", - "type": "BOOL" - }, - { - "name": "STATE", - "type": "INT" - } - ], - "inouts": [] - }, - { - "name": "SEQUENCE_4", - "inputs": [ - { - "name": "IN0", - "type": "BOOL" - }, - { - "name": "IN1", - "type": "BOOL" - }, - { - "name": "IN2", - "type": "BOOL" - }, - { - "name": "IN3", - "type": "BOOL" - }, - { - "name": "START", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - }, - { - "name": "WAIT0", - "type": "TIME" - }, - { - "name": "DELAY0", - "type": "TIME" - }, - { - "name": "WAIT1", - "type": "TIME" - }, - { - "name": "DELAY1", - "type": "TIME" - }, - { - "name": "WAIT2", - "type": "TIME" - }, - { - "name": "DELAY2", - "type": "TIME" - }, - { - "name": "WAIT3", - "type": "TIME" - }, - { - "name": "DELAY3", - "type": "TIME" - }, - { - "name": "STOP_ON_ERROR", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q0", - "type": "BOOL" - }, - { - "name": "Q1", - "type": "BOOL" - }, - { - "name": "Q2", - "type": "BOOL" - }, - { - "name": "Q3", - "type": "BOOL" - }, - { - "name": "QX", - "type": "BOOL" - }, - { - "name": "RUN", - "type": "BOOL" - }, - { - "name": "STEP", - "type": "INT" - }, - { - "name": "STATUS", - "type": "BYTE" - } - ], - "inouts": [] - }, - { - "name": "SEQUENCE_8", - "inputs": [ - { - "name": "IN0", - "type": "BOOL" - }, - { - "name": "IN1", - "type": "BOOL" - }, - { - "name": "IN2", - "type": "BOOL" - }, - { - "name": "IN3", - "type": "BOOL" - }, - { - "name": "IN4", - "type": "BOOL" - }, - { - "name": "IN5", - "type": "BOOL" - }, - { - "name": "IN6", - "type": "BOOL" - }, - { - "name": "IN7", - "type": "BOOL" - }, - { - "name": "START", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - }, - { - "name": "WAIT0", - "type": "TIME" - }, - { - "name": "DELAY0", - "type": "TIME" - }, - { - "name": "WAIT1", - "type": "TIME" - }, - { - "name": "DELAY1", - "type": "TIME" - }, - { - "name": "WAIT2", - "type": "TIME" - }, - { - "name": "DELAY2", - "type": "TIME" - }, - { - "name": "WAIT3", - "type": "TIME" - }, - { - "name": "DELAY3", - "type": "TIME" - }, - { - "name": "WAIT4", - "type": "TIME" - }, - { - "name": "DELAY4", - "type": "TIME" - }, - { - "name": "WAIT5", - "type": "TIME" - }, - { - "name": "DELAY5", - "type": "TIME" - }, - { - "name": "WAIT6", - "type": "TIME" - }, - { - "name": "DELAY6", - "type": "TIME" - }, - { - "name": "WAIT7", - "type": "TIME" - }, - { - "name": "DELAY7", - "type": "TIME" - }, - { - "name": "STOP_ON_ERROR", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q0", - "type": "BOOL" - }, - { - "name": "Q1", - "type": "BOOL" - }, - { - "name": "Q2", - "type": "BOOL" - }, - { - "name": "Q3", - "type": "BOOL" - }, - { - "name": "Q4", - "type": "BOOL" - }, - { - "name": "Q5", - "type": "BOOL" - }, - { - "name": "Q6", - "type": "BOOL" - }, - { - "name": "Q7", - "type": "BOOL" - }, - { - "name": "QX", - "type": "BOOL" - }, - { - "name": "RUN", - "type": "BOOL" - }, - { - "name": "STEP", - "type": "INT" - }, - { - "name": "STATUS", - "type": "BYTE" - } - ], - "inouts": [] - }, - { - "name": "SH", - "inputs": [ - { - "name": "IN", - "type": "REAL" - }, - { - "name": "CLK", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "OUT", - "type": "REAL" - }, - { - "name": "TRIG", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "SHR_4E", - "inputs": [ - { - "name": "SET", - "type": "BOOL" - }, - { - "name": "D0", - "type": "BOOL" - }, - { - "name": "CLK", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q0", - "type": "BOOL" - }, - { - "name": "Q1", - "type": "BOOL" - }, - { - "name": "Q2", - "type": "BOOL" - }, - { - "name": "Q3", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "SHR_4UDE", - "inputs": [ - { - "name": "SET", - "type": "BOOL" - }, - { - "name": "D0", - "type": "BOOL" - }, - { - "name": "D3", - "type": "BOOL" - }, - { - "name": "CLK", - "type": "BOOL" - }, - { - "name": "DN", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q0", - "type": "BOOL" - }, - { - "name": "Q1", - "type": "BOOL" - }, - { - "name": "Q2", - "type": "BOOL" - }, - { - "name": "Q3", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "SHR_8PLE", - "inputs": [ - { - "name": "DIN", - "type": "BOOL" - }, - { - "name": "DLOAD", - "type": "BYTE" - }, - { - "name": "CLK", - "type": "BOOL" - }, - { - "name": "UP", - "type": "BOOL" - }, - { - "name": "LOAD", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "DOUT", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "SHR_8UDE", - "inputs": [ - { - "name": "SET", - "type": "BOOL" - }, - { - "name": "D0", - "type": "BOOL" - }, - { - "name": "D7", - "type": "BOOL" - }, - { - "name": "CLK", - "type": "BOOL" - }, - { - "name": "DN", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q0", - "type": "BOOL" - }, - { - "name": "Q1", - "type": "BOOL" - }, - { - "name": "Q2", - "type": "BOOL" - }, - { - "name": "Q3", - "type": "BOOL" - }, - { - "name": "Q4", - "type": "BOOL" - }, - { - "name": "Q5", - "type": "BOOL" - }, - { - "name": "Q6", - "type": "BOOL" - }, - { - "name": "Q7", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "SH_1", - "inputs": [ - { - "name": "IN", - "type": "REAL" - }, - { - "name": "PT", - "type": "TIME" - } - ], - "outputs": [ - { - "name": "OUT", - "type": "REAL" - }, - { - "name": "TRIG", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "SH_2", - "inputs": [ - { - "name": "IN", - "type": "REAL" - }, - { - "name": "PT", - "type": "TIME" - }, - { - "name": "N", - "type": "INT" - }, - { - "name": "DISC", - "type": "INT" - } - ], - "outputs": [ - { - "name": "OUT", - "type": "REAL" - }, - { - "name": "TRIG", - "type": "BOOL" - }, - { - "name": "AVG", - "type": "REAL" - }, - { - "name": "HIGH", - "type": "REAL" - }, - { - "name": "LOW", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "SH_T", - "inputs": [ - { - "name": "IN", - "type": "REAL" - }, - { - "name": "E", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "OUT", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "SIGNAL", - "inputs": [ - { - "name": "IN", - "type": "BOOL" - }, - { - "name": "SIG", - "type": "BYTE" - }, - { - "name": "TS", - "type": "TIME" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "SIGNAL_4", - "inputs": [ - { - "name": "IN1", - "type": "BOOL" - }, - { - "name": "IN2", - "type": "BOOL" - }, - { - "name": "IN3", - "type": "BOOL" - }, - { - "name": "IN4", - "type": "BOOL" - }, - { - "name": "TS", - "type": "TIME" - }, - { - "name": "S1", - "type": "BYTE" - }, - { - "name": "S2", - "type": "BYTE" - }, - { - "name": "S3", - "type": "BYTE" - }, - { - "name": "S4", - "type": "BYTE" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "SPEED", - "inputs": [ - { - "name": "MS", - "type": "REAL" - }, - { - "name": "KMH", - "type": "REAL" - }, - { - "name": "KN", - "type": "REAL" - }, - { - "name": "MH", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "YMS", - "type": "REAL" - }, - { - "name": "YKMH", - "type": "REAL" - }, - { - "name": "YKN", - "type": "REAL" - }, - { - "name": "YMH", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "STACK_16", - "inputs": [ - { - "name": "DIN", - "type": "DWORD" - }, - { - "name": "E", - "type": "BOOL" - }, - { - "name": "RD", - "type": "BOOL" - }, - { - "name": "WD", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "DOUT", - "type": "DWORD" - }, - { - "name": "EMPTY", - "type": "BOOL" - }, - { - "name": "FULL", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "STACK_32", - "inputs": [ - { - "name": "DIN", - "type": "DWORD" - }, - { - "name": "E", - "type": "BOOL" - }, - { - "name": "RD", - "type": "BOOL" - }, - { - "name": "WD", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "DOUT", - "type": "DWORD" - }, - { - "name": "EMPTY", - "type": "BOOL" - }, - { - "name": "FULL", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "STAIR2", - "inputs": [ - { - "name": "X", - "type": "REAL" - }, - { - "name": "D", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "Y", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "STORE_8", - "inputs": [ - { - "name": "SET", - "type": "BOOL" - }, - { - "name": "D0", - "type": "BOOL" - }, - { - "name": "D1", - "type": "BOOL" - }, - { - "name": "D2", - "type": "BOOL" - }, - { - "name": "D3", - "type": "BOOL" - }, - { - "name": "D4", - "type": "BOOL" - }, - { - "name": "D5", - "type": "BOOL" - }, - { - "name": "D6", - "type": "BOOL" - }, - { - "name": "D7", - "type": "BOOL" - }, - { - "name": "CLR", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q0", - "type": "BOOL" - }, - { - "name": "Q1", - "type": "BOOL" - }, - { - "name": "Q2", - "type": "BOOL" - }, - { - "name": "Q3", - "type": "BOOL" - }, - { - "name": "Q4", - "type": "BOOL" - }, - { - "name": "Q5", - "type": "BOOL" - }, - { - "name": "Q6", - "type": "BOOL" - }, - { - "name": "Q7", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "SUN_POS", - "inputs": [ - { - "name": "LATITUDE", - "type": "REAL" - }, - { - "name": "LONGITUDE", - "type": "REAL" - }, - { - "name": "UTC", - "type": "DT" - } - ], - "outputs": [ - { - "name": "B", - "type": "REAL" - }, - { - "name": "H", - "type": "REAL" - }, - { - "name": "HR", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "SUN_TIME", - "inputs": [ - { - "name": "LATITUDE", - "type": "REAL" - }, - { - "name": "LONGITUDE", - "type": "REAL" - }, - { - "name": "UTC", - "type": "DATE" - }, - { - "name": "H", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "MIDDAY", - "type": "TOD" - }, - { - "name": "SUN_RISE", - "type": "TOD" - }, - { - "name": "SUN_SET", - "type": "TOD" - }, - { - "name": "SUN_DECLINATION", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "TC_MS", - "inputs": [], - "outputs": [ - { - "name": "TC", - "type": "DWORD" - } - ], - "inouts": [] - }, - { - "name": "TC_S", - "inputs": [], - "outputs": [ - { - "name": "TC", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "TC_US", - "inputs": [], - "outputs": [ - { - "name": "TC", - "type": "DWORD" - } - ], - "inouts": [] - }, - { - "name": "TEMPERATURE", - "inputs": [ - { - "name": "K", - "type": "REAL" - }, - { - "name": "C", - "type": "REAL" - }, - { - "name": "F", - "type": "REAL" - }, - { - "name": "RE", - "type": "REAL" - }, - { - "name": "RA", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "YK", - "type": "REAL" - }, - { - "name": "YC", - "type": "REAL" - }, - { - "name": "YF", - "type": "REAL" - }, - { - "name": "YRE", - "type": "REAL" - }, - { - "name": "YRA", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "TICKER", - "inputs": [ - { - "name": "N", - "type": "INT" - }, - { - "name": "PT", - "type": "TIME" - } - ], - "outputs": [ - { - "name": "DISPLAY", - "type": "STRING" - } - ], - "inouts": [ - { - "name": "TEXT", - "type": "STRING" - } - ] - }, - { - "name": "TOGGLE", - "inputs": [ - { - "name": "CLK", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "TONOF", - "inputs": [ - { - "name": "IN", - "type": "BOOL" - }, - { - "name": "T_ON", - "type": "TIME" - }, - { - "name": "T_OFF", - "type": "TIME" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - } - ], - "inouts": [] - }, - { - "name": "TP_X", - "inputs": [ - { - "name": "IN", - "type": "BOOL" - }, - { - "name": "PT", - "type": "TIME" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - }, - { - "name": "ET", - "type": "TIME" - } - ], - "inouts": [] - }, - { - "name": "TREND", - "inputs": [ - { - "name": "X", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - }, - { - "name": "TU", - "type": "BOOL" - }, - { - "name": "TD", - "type": "BOOL" - }, - { - "name": "D", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "TREND_DW", - "inputs": [ - { - "name": "X", - "type": "DWORD" - } - ], - "outputs": [ - { - "name": "Q", - "type": "BOOL" - }, - { - "name": "TU", - "type": "BOOL" - }, - { - "name": "TD", - "type": "BOOL" - }, - { - "name": "D", - "type": "DWORD" - } - ], - "inouts": [] - }, - { - "name": "TUNE", - "inputs": [ - { - "name": "SET", - "type": "BOOL" - }, - { - "name": "SU", - "type": "BOOL" - }, - { - "name": "SD", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - }, - { - "name": "SS", - "type": "REAL" - }, - { - "name": "LIMIT_L", - "type": "REAL" - }, - { - "name": "LIMIT_H", - "type": "REAL" - }, - { - "name": "RST_VAL", - "type": "REAL" - }, - { - "name": "SET_VAL", - "type": "REAL" - }, - { - "name": "T1", - "type": "TIME" - }, - { - "name": "T2", - "type": "TIME" - }, - { - "name": "S1", - "type": "REAL" - }, - { - "name": "S2", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "Y", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "TUNE2", - "inputs": [ - { - "name": "SET", - "type": "BOOL" - }, - { - "name": "SU", - "type": "BOOL" - }, - { - "name": "SD", - "type": "BOOL" - }, - { - "name": "FU", - "type": "BOOL" - }, - { - "name": "FD", - "type": "BOOL" - }, - { - "name": "RST", - "type": "BOOL" - }, - { - "name": "SS", - "type": "REAL" - }, - { - "name": "FS", - "type": "REAL" - }, - { - "name": "LIMIT_L", - "type": "REAL" - }, - { - "name": "LIMIT_H", - "type": "REAL" - }, - { - "name": "RST_VAL", - "type": "REAL" - }, - { - "name": "SET_VAL", - "type": "REAL" - }, - { - "name": "TR", - "type": "TIME" - }, - { - "name": "S1", - "type": "REAL" - }, - { - "name": "S2", - "type": "REAL" - } - ], - "outputs": [ - { - "name": "Y", - "type": "REAL" - } - ], - "inouts": [] - }, - { - "name": "_RMP_B", - "inputs": [ - { - "name": "DIR", - "type": "BOOL" - }, - { - "name": "E", - "type": "BOOL" - }, - { - "name": "TR", - "type": "TIME" - } - ], - "outputs": [], - "inouts": [ - { - "name": "RMP", - "type": "BYTE" - } - ] - }, - { - "name": "_RMP_NEXT", - "inputs": [ - { - "name": "E", - "type": "BOOL" - }, - { - "name": "IN", - "type": "BYTE" - }, - { - "name": "TR", - "type": "TIME" - }, - { - "name": "TF", - "type": "TIME" - }, - { - "name": "TL", - "type": "TIME" - } - ], - "outputs": [ - { - "name": "DIR", - "type": "BOOL" - }, - { - "name": "UP", - "type": "BOOL" - }, - { - "name": "DN", - "type": "BOOL" - } - ], - "inouts": [ - { - "name": "OUT", - "type": "BYTE" - } - ] - }, - { - "name": "_RMP_W", - "inputs": [ - { - "name": "DIR", - "type": "BOOL" - }, - { - "name": "E", - "type": "BOOL" - }, - { - "name": "TR", - "type": "TIME" - } - ], - "outputs": [], - "inouts": [ - { - "name": "RMP", - "type": "WORD" - } - ] - } - ], - "types": [ - { - "name": "CALENDAR", - "kind": "struct" - }, - { - "name": "COMPLEX", - "kind": "struct" - }, - { - "name": "CONSTANTS_LANGUAGE", - "kind": "struct" - }, - { - "name": "CONSTANTS_LOCATION", - "kind": "struct" - }, - { - "name": "CONSTANTS_MATH", - "kind": "struct" - }, - { - "name": "CONSTANTS_PHYS", - "kind": "struct" - }, - { - "name": "CONSTANTS_SETUP", - "kind": "struct" - }, - { - "name": "ESR_DATA", - "kind": "struct" - }, - { - "name": "FRACTION", - "kind": "struct" - }, - { - "name": "HOLIDAY_DATA", - "kind": "struct" - }, - { - "name": "REAL2", - "kind": "struct" - }, - { - "name": "SDT", - "kind": "struct" - }, - { - "name": "TIMER_EVENT", - "kind": "struct" - }, - { - "name": "VECTOR_3", - "kind": "struct" - } - ], - "headers": [], - "isBuiltin": false, - "sourceFiles": [ - "ACOSH.st", - "ACOTH.st", - "AGDF.st", - "AIN.st", - "AIN1.st", - "ALARM_2.st", - "AOUT.st", - "AOUT1.st", - "ARRAY_AVG.st", - "ARRAY_GAV.st", - "ARRAY_HAV.st", - "ARRAY_MAX.st", - "ARRAY_MIN.st", - "ARRAY_SDV.st", - "ARRAY_SPR.st", - "ARRAY_SUM.st", - "ARRAY_TREND.st", - "ARRAY_VAR.st", - "ASINH.st", - "ASTRO.st", - "ATAN2.st", - "ATANH.st", - "A_TRIG.st", - "BAND_B.st", - "BAR_GRAPH.st", - "BCDC_TO_INT.st", - "BETA.st", - "BFT_TO_MS.st", - "BINOM.st", - "BIN_TO_BYTE.st", - "BIN_TO_DWORD.st", - "BIT_COUNT.st", - "BIT_LOAD_B.st", - "BIT_LOAD_B2.st", - "BIT_LOAD_DW.st", - "BIT_LOAD_DW2.st", - "BIT_LOAD_W.st", - "BIT_LOAD_W2.st", - "BIT_OF_DWORD.st", - "BIT_TOGGLE_B.st", - "BIT_TOGGLE_DW.st", - "BIT_TOGGLE_W.st", - "BUFFER_COMP.st", - "BUFFER_SEARCH.st", - "BUFFER_TO_STRING.st", - "BYTE_OF_BIT.st", - "BYTE_OF_DWORD.st", - "BYTE_TO_BITS.st", - "BYTE_TO_GRAY.st", - "BYTE_TO_RANGE.st", - "BYTE_TO_STRB.st", - "BYTE_TO_STRH.st", - "B_TRIG.st", - "CABS.st", - "CACOS.st", - "CACOSH.st", - "CADD.st", - "CALENDAR.st", - "CALENDAR_CALC.st", - "CALIBRATE.st", - "CAPITALIZE.st", - "CARG.st", - "CASIN.st", - "CASINH.st", - "CATAN.st", - "CATANH.st", - "CAUCHY.st", - "CAUCHYCD.st", - "CCON.st", - "CCOS.st", - "CCOSH.st", - "CDIV.st", - "CEIL.st", - "CEIL2.st", - "CEXP.st", - "CHARCODE.st", - "CHARNAME.st", - "CHECK_PARITY.st", - "CHK_REAL.st", - "CHR_TO_STRING.st", - "CINV.st", - "CIRCLE_A.st", - "CIRCLE_C.st", - "CIRCLE_SEG.st", - "CLEAN.st", - "CLICK_CNT.st", - "CLICK_DEC.st", - "CLK_DIV.st", - "CLK_N.st", - "CLK_PRG.st", - "CLK_PULSE.st", - "CLOG.st", - "CMP.st", - "CMUL.st", - "CODE.st", - "COMPLEX.st", - "CONE_V.st", - "CONSTANTS_LANGUAGE.st", - "CONSTANTS_LOCATION.st", - "CONSTANTS_MATH.st", - "CONSTANTS_PHYS.st", - "CONSTANTS_SETUP.st", - "CONTROL_SET1.st", - "CONTROL_SET2.st", - "COSH.st", - "COTH.st", - "COUNT_BR.st", - "COUNT_CHAR.st", - "COUNT_DR.st", - "COUNT_SUBSTRING.st", - "CPOL.st", - "CPOW.st", - "CRC_GEN.st", - "CSET.st", - "CSIN.st", - "CSINH.st", - "CSQRT.st", - "CSUB.st", - "CTAN.st", - "CTANH.st", - "CTRL_IN.st", - "CTRL_OUT.st", - "CTRL_PI.st", - "CTRL_PID.st", - "CTRL_PWM.st", - "CYCLE_4.st", - "CYCLE_TIME.st", - "C_TO_F.st", - "C_TO_K.st", - "DATE_ADD.st", - "DAYS_DELTA.st", - "DAYS_IN_MONTH.st", - "DAYS_IN_YEAR.st", - "DAY_OF_DATE.st", - "DAY_OF_MONTH.st", - "DAY_OF_WEEK.st", - "DAY_OF_YEAR.st", - "DAY_TO_TIME.st", - "DCF77.st", - "DEAD_BAND.st", - "DEAD_BAND_A.st", - "DEAD_ZONE.st", - "DEAD_ZONE2.st", - "DEC1.st", - "DEC_2.st", - "DEC_4.st", - "DEC_8.st", - "DEC_TO_BYTE.st", - "DEC_TO_DWORD.st", - "DEC_TO_INT.st", - "DEG.st", - "DEG_TO_DIR.st", - "DELAY.st", - "DELAY_4.st", - "DEL_CHARS.st", - "DIFFER.st", - "DIR_TO_DEG.st", - "DRIVER_1.st", - "DRIVER_4.st", - "DRIVER_4C.st", - "DST.st", - "DT2_TO_SDT.st", - "DT_SIMU.st", - "DT_TO_SDT.st", - "DT_TO_STRF.st", - "DWORD_OF_BYTE.st", - "DWORD_OF_WORD.st", - "DWORD_TO_STRB.st", - "DWORD_TO_STRF.st", - "DWORD_TO_STRH.st", - "DW_TO_REAL.st", - "D_TRIG.st", - "D_TRUNC.st", - "EASTER.st", - "ELLIPSE_A.st", - "ELLIPSE_C.st", - "ENERGY.st", - "ERF.st", - "ERFC.st", - "ESR_COLLECT.st", - "ESR_DATA.st", - "ESR_MON_B8.st", - "ESR_MON_R4.st", - "ESR_MON_X8.st", - "EVEN.st", - "EVENTS.st", - "EXEC.st", - "EXP10.st", - "EXPN.st", - "FACT.st", - "FADE.st", - "FF_D2E.st", - "FF_D4E.st", - "FF_DRE.st", - "FF_JKE.st", - "FF_RSE.st", - "FIB.st", - "FIFO_16.st", - "FIFO_32.st", - "FILL.st", - "FILTER_DW.st", - "FILTER_I.st", - "FILTER_MAV_DW.st", - "FILTER_MAV_W.st", - "FILTER_W.st", - "FILTER_WAV.st", - "FINDB.st", - "FINDB_NONUM.st", - "FINDB_NUM.st", - "FINDP.st", - "FIND_CHAR.st", - "FIND_CTRL.st", - "FIND_NONUM.st", - "FIND_NUM.st", - "FIX.st", - "FLOAT_TO_REAL.st", - "FLOOR.st", - "FLOOR2.st", - "FLOW_METER.st", - "FRACT.st", - "FRACTION.st", - "FRMP_B.st", - "FSTRING_TO_BYTE.st", - "FSTRING_TO_DT.st", - "FSTRING_TO_DWORD.st", - "FSTRING_TO_MONTH.st", - "FSTRING_TO_WEEK.st", - "FSTRING_TO_WEEKDAY.st", - "FT_AVG.st", - "FT_DERIV.st", - "FT_IMP.st", - "FT_INT.st", - "FT_INT2.st", - "FT_MIN_MAX.st", - "FT_PD.st", - "FT_PDT1.st", - "FT_PI.st", - "FT_PID.st", - "FT_PIDW.st", - "FT_PIDWL.st", - "FT_PIW.st", - "FT_PIWL.st", - "FT_PT1.st", - "FT_PT2.st", - "FT_Profile.st", - "FT_RMP.st", - "FT_TN16.st", - "FT_TN64.st", - "FT_TN8.st", - "F_LIN.st", - "F_LIN2.st", - "F_POLY.st", - "F_POWER.st", - "F_QUAD.st", - "F_TO_C.st", - "F_TO_OM.st", - "F_TO_PT.st", - "GAMMA.st", - "GAUSS.st", - "GAUSSCD.st", - "GCD.st", - "GDF.st", - "GEN_BIT.st", - "GEN_PULSE.st", - "GEN_PW2.st", - "GEN_RDM.st", - "GEN_RDT.st", - "GEN_RMP.st", - "GEN_SIN.st", - "GEN_SQ.st", - "GEN_SQR.st", - "GEO_TO_DEG.st", - "GOLD.st", - "GRAY_TO_BYTE.st", - "GVL_1.gvl.st", - "GVL_2.gvl.st", - "HEX_TO_BYTE.st", - "HEX_TO_DWORD.st", - "HOLIDAY.st", - "HOLIDAY_DATA.st", - "HOUR.st", - "HOUR_OF_DT.st", - "HOUR_TO_TIME.st", - "HOUR_TO_TOD.st", - "HYPOT.st", - "HYST.st", - "HYST_1.st", - "HYST_2.st", - "HYST_3.st", - "INC.st", - "INC1.st", - "INC2.st", - "INC_DEC.st", - "INTEGRATE.st", - "INTERLOCK.st", - "INTERLOCK_4.st", - "INT_TO_BCDC.st", - "INV.st", - "ISC_ALPHA.st", - "ISC_CTRL.st", - "ISC_HEX.st", - "ISC_LOWER.st", - "ISC_NUM.st", - "ISC_UPPER.st", - "IS_ALNUM.st", - "IS_ALPHA.st", - "IS_CC.st", - "IS_CTRL.st", - "IS_HEX.st", - "IS_LOWER.st", - "IS_NCC.st", - "IS_NUM.st", - "IS_SORTED.st", - "IS_UPPER.st", - "JD2000.st", - "KMH_TO_MS.st", - "K_TO_C.st", - "LAMBERT_W.st", - "LANGEVIN.st", - "LEAP_DAY.st", - "LEAP_OF_DATE.st", - "LEAP_YEAR.st", - "LENGTH.st", - "LINEAR_INT.st", - "LIST_ADD.st", - "LIST_CLEAN.st", - "LIST_GET.st", - "LIST_INSERT.st", - "LIST_LEN.st", - "LIST_NEXT.st", - "LIST_RETRIEVE.st", - "LIST_RETRIEVE_LAST.st", - "LOWERCASE.st", - "LTCH.st", - "LTCH_4.st", - "LTIME_TO_UTC.st", - "MANUAL.st", - "MANUAL_1.st", - "MANUAL_2.st", - "MANUAL_4.st", - "MATRIX.st", - "MAX3.st", - "MESSAGE_4R.st", - "MESSAGE_8.st", - "METER.st", - "METER_STAT.st", - "MID3.st", - "MIN3.st", - "MINUTE.st", - "MINUTE_OF_DT.st", - "MINUTE_TO_TIME.st", - "MIRROR.st", - "MIX.st", - "MODR.st", - "MONTH_BEGIN.st", - "MONTH_END.st", - "MONTH_OF_DATE.st", - "MONTH_TO_STRING.st", - "MS_TO_BFT.st", - "MS_TO_KMH.st", - "MULTIME.st", - "MULTI_IN.st", - "MUL_ADD.st", - "MUX_2.st", - "MUX_4.st", - "MUX_R2.st", - "MUX_R4.st", - "M_D.st", - "M_T.st", - "M_TX.st", - "NEGX.st", - "OCT_TO_BYTE.st", - "OCT_TO_DWORD.st", - "OFFSET.st", - "OFFSET2.st", - "OM_TO_F.st", - "ONTIME.st", - "OSCAT_VERSION.st", - "OVERRIDE.st", - "PARITY.st", - "PARSET.st", - "PARSET2.st", - "PERIOD.st", - "PERIOD2.st", - "PIN_CODE.st", - "POLYNOM_INT.st", - "PRESSURE.st", - "PT_TO_F.st", - "PWM_DC.st", - "PWM_PW.st", - "R2_ABS.st", - "R2_ADD.st", - "R2_ADD2.st", - "R2_MUL.st", - "R2_SET.st", - "RAD.st", - "RANGE_TO_BYTE.st", - "RANGE_TO_WORD.st", - "RDM.st", - "RDM2.st", - "RDMDW.st", - "REAL2.st", - "REAL_TO_DW.st", - "REAL_TO_FRAC.st", - "REAL_TO_STRF.st", - "REFLECT.st", - "REFRACTION.st", - "REPLACE_ALL.st", - "REPLACE_CHARS.st", - "REPLACE_UML.st", - "RES_NI.st", - "RES_NTC.st", - "RES_PT.st", - "RES_SI.st", - "REVERSE.st", - "RMP_B.st", - "RMP_SOFT.st", - "RMP_W.st", - "RND.st", - "ROUND.st", - "RTC_2.st", - "RTC_MS.st", - "SCALE.st", - "SCALE_B.st", - "SCALE_B2.st", - "SCALE_B4.st", - "SCALE_B8.st", - "SCALE_D.st", - "SCALE_R.st", - "SCALE_X2.st", - "SCALE_X4.st", - "SCALE_X8.st", - "SCHEDULER.st", - "SCHEDULER_2.st", - "SDT.st", - "SDT_TO_DATE.st", - "SDT_TO_DT.st", - "SDT_TO_TOD.st", - "SECOND.st", - "SECOND_OF_DT.st", - "SECOND_TO_TIME.st", - "SEL2_OF_3.st", - "SEL2_OF_3B.st", - "SELECT_8.st", - "SENSOR_INT.st", - "SEQUENCE_4.st", - "SEQUENCE_8.st", - "SET_DATE.st", - "SET_DT.st", - "SET_TOD.st", - "SGN.st", - "SH.st", - "SHL1.st", - "SHR1.st", - "SHR_4E.st", - "SHR_4UDE.st", - "SHR_8PLE.st", - "SHR_8UDE.st", - "SH_1.st", - "SH_2.st", - "SH_T.st", - "SIGMOID.st", - "SIGNAL.st", - "SIGNAL_4.st", - "SIGN_I.st", - "SIGN_R.st", - "SINC.st", - "SINH.st", - "SPEED.st", - "SPHERE_V.st", - "SQRTN.st", - "STACK_16.st", - "STACK_32.st", - "STAIR.st", - "STAIR2.st", - "STATUS_TO_ESR.st", - "STORE_8.st", - "SUN_MIDDAY.st", - "SUN_POS.st", - "SUN_TIME.st", - "SWAP_BYTE.st", - "SWAP_BYTE2.st", - "TANC.st", - "TANH.st", - "TC_MS.st", - "TC_S.st", - "TC_US.st", - "TEMPERATURE.st", - "TEMP_NI.st", - "TEMP_NTC.st", - "TEMP_PT.st", - "TEMP_SI.st", - "TICKER.st", - "TIMECHECK.st", - "TIMER_EVENT.st", - "TOGGLE.st", - "TONOF.st", - "TO_LOWER.st", - "TO_UML.st", - "TO_UPPER.st", - "TP_X.st", - "TREND.st", - "TREND_DW.st", - "TRIANGLE_A.st", - "TRIM.st", - "TRIM1.st", - "TRIME.st", - "TUNE.st", - "TUNE2.st", - "T_PLC_MS.st", - "T_PLC_US.st", - "UPPERCASE.st", - "UTC_TO_LTIME.st", - "V3_ABS.st", - "V3_ADD.st", - "V3_ANG.st", - "V3_DPRO.st", - "V3_NORM.st", - "V3_NUL.st", - "V3_PAR.st", - "V3_REV.st", - "V3_SMUL.st", - "V3_SUB.st", - "V3_XANG.st", - "V3_XPRO.st", - "V3_YANG.st", - "V3_ZANG.st", - "VECTOR_3.st", - "WEEKDAY_TO_STRING.st", - "WINDOW.st", - "WINDOW2.st", - "WORD_OF_BYTE.st", - "WORD_OF_DWORD.st", - "WORD_TO_RANGE.st", - "WORK_WEEK.st", - "YEAR_BEGIN.st", - "YEAR_END.st", - "YEAR_OF_DATE.st", - "_ARRAY_ABS.st", - "_ARRAY_ADD.st", - "_ARRAY_INIT.st", - "_ARRAY_MEDIAN.st", - "_ARRAY_MUL.st", - "_ARRAY_SHUFFLE.st", - "_ARRAY_SORT.st", - "_BUFFER_CLEAR.st", - "_BUFFER_INIT.st", - "_BUFFER_INSERT.st", - "_BUFFER_UPPERCASE.st", - "_RMP_B.st", - "_RMP_NEXT.st", - "_RMP_W.st", - "_STRING_TO_BUFFER.st" - ] - }, - "headerCode": "\n// User-defined types\n\nstruct CALENDAR {\n IEC_DT UTC{};\n IEC_DT LOCAL_DT{};\n IEC_DATE LOCAL_DATE{};\n IEC_TOD LOCAL_TOD{};\n IEC_INT YEAR{};\n IEC_INT MONTH{};\n IEC_INT DAY{};\n IEC_INT WEEKDAY{};\n IEC_INT OFFSET{};\n IEC_BOOL DST_EN{};\n IEC_BOOL DST_ON{};\n IECStringVar<5> NAME{};\n IEC_INT LANGUAGE{};\n IEC_REAL LONGITUDE{};\n IEC_REAL LATITUDE{};\n IEC_TOD SUN_RISE{};\n IEC_TOD SUN_SET{};\n IEC_TOD SUN_MIDDAY{};\n IEC_REAL SUN_HEIGTH{};\n IEC_REAL SUN_HOR{};\n IEC_REAL SUN_VER{};\n IEC_BOOL NIGHT{};\n IEC_BOOL HOLIDAY{};\n IECStringVar<30> HOLY_NAME{};\n IEC_INT WORK_WEEK{};\n};\n\nusing IEC_CALENDAR = CALENDAR;\n\nstruct COMPLEX {\n IEC_REAL RE{};\n IEC_REAL IM{};\n};\n\nusing IEC_COMPLEX = COMPLEX;\n\nstruct CONSTANTS_LANGUAGE {\n IEC_INT DEFAULT = 1;\n IEC_INT LMAX = 3;\n Array2D, 1, 3, 1, 7> WEEKDAYS{};\n Array2D, 1, 3, 1, 7> WEEKDAYS2{};\n Array2D, 1, 3, 1, 12> MONTHS{};\n Array2D, 1, 3, 1, 12> MONTHS3{};\n Array2D, 1, 3, 0, 15> DIRS{};\n};\n\nusing IEC_CONSTANTS_LANGUAGE = CONSTANTS_LANGUAGE;\n\nstruct CONSTANTS_LOCATION {\n IEC_INT DEFAULT = 1;\n IEC_INT LMAX = 5;\n Array1D LANGUAGE{};\n};\n\nusing IEC_CONSTANTS_LOCATION = CONSTANTS_LOCATION;\n\nstruct CONSTANTS_MATH {\n IEC_REAL PI = 3.141592653589793;\n IEC_REAL PI2 = 6.283185307179586;\n IEC_REAL PI4 = 12.566370614359172;\n IEC_REAL PI05 = 1.5707963267949;\n IEC_REAL PI025 = 0.785398163397448;\n IEC_REAL PI_INV = 0.318309886183791;\n IEC_REAL E = 2.718281828459045;\n IEC_REAL E_INV = 0.367879441171442;\n IEC_REAL SQ2 = 1.4142135623731;\n Array1D FACTS{};\n};\n\nusing IEC_CONSTANTS_MATH = CONSTANTS_MATH;\n\nstruct CONSTANTS_PHYS {\n IEC_REAL C = 299792458;\n IEC_REAL E = 1.60217653e-19;\n IEC_REAL G = 9.80665;\n IEC_REAL T0 = -273.15;\n IEC_REAL RU = 8.314472;\n IEC_REAL PN = 101325;\n};\n\nusing IEC_CONSTANTS_PHYS = CONSTANTS_PHYS;\n\nstruct CONSTANTS_SETUP {\n IEC_BOOL EXTENDED_ASCII = true;\n Array1D, 1, 4> CHARNAMES{};\n Array1D MTH_OFS{};\n Array1D DECADES{};\n};\n\nusing IEC_CONSTANTS_SETUP = CONSTANTS_SETUP;\n\nstruct ESR_DATA {\n IEC_BYTE TYP{};\n IECStringVar<10> ADRESS{};\n IEC_DT DS{};\n IEC_TIME TS{};\n Array1D DATA{};\n};\n\nusing IEC_ESR_DATA = ESR_DATA;\n\nstruct FRACTION {\n IEC_INT NUMERATOR{};\n IEC_INT DENOMINATOR{};\n};\n\nusing IEC_FRACTION = FRACTION;\n\nstruct HOLIDAY_DATA {\n IECStringVar<30> NAME{};\n IEC_SINT DAY{};\n IEC_SINT MONTH{};\n IEC_SINT USE{};\n};\n\nusing IEC_HOLIDAY_DATA = HOLIDAY_DATA;\n\nstruct REAL2 {\n IEC_REAL R1{};\n IEC_REAL RX{};\n};\n\nusing IEC_REAL2 = REAL2;\n\nstruct SDT {\n IEC_INT YEAR{};\n IEC_INT MONTH{};\n IEC_INT DAY{};\n IEC_INT WEEKDAY{};\n IEC_INT HOUR{};\n IEC_INT MINUTE{};\n IEC_INT SECOND{};\n IEC_INT MS{};\n};\n\nusing IEC_SDT = SDT;\n\nstruct TIMER_EVENT {\n IEC_BYTE TYP{};\n IEC_BYTE CHANNEL{};\n IEC_BYTE DAY{};\n IEC_TOD START{};\n IEC_TIME DURATION{};\n IEC_BYTE LAND{};\n IEC_BYTE LOR{};\n IEC_DT LAST{};\n};\n\nusing IEC_TIMER_EVENT = TIMER_EVENT;\n\nstruct VECTOR_3 {\n IEC_REAL X{};\n IEC_REAL Y{};\n IEC_REAL Z{};\n};\n\nusing IEC_VECTOR_3 = VECTOR_3;\n\n// Global variables\ninline CONSTANTS_MATH MATH{};\ninline CONSTANTS_PHYS PHYS{};\ninline CONSTANTS_LANGUAGE LANGUAGE{};\ninline CONSTANTS_SETUP SETUP{};\ninline CONSTANTS_LOCATION LOCATION{};\n\nclass AIN1;\nclass ALARM_2;\nclass ASTRO;\nclass A_TRIG;\nclass BAR_GRAPH;\nclass BYTE_TO_BITS;\nclass B_TRIG;\nclass CALENDAR_CALC;\nclass CALIBRATE;\nclass CLICK_CNT;\nclass CLICK_DEC;\nclass CLK_DIV;\nclass CLK_N;\nclass CLK_PRG;\nclass CLK_PULSE;\nclass CONTROL_SET1;\nclass CONTROL_SET2;\nclass COUNT_BR;\nclass COUNT_DR;\nclass CTRL_OUT;\nclass CTRL_PI;\nclass CTRL_PID;\nclass CTRL_PWM;\nclass CYCLE_4;\nclass CYCLE_TIME;\nclass DCF77;\nclass DEAD_BAND_A;\nclass DEAD_ZONE2;\nclass DEC_2;\nclass DEC_4;\nclass DEC_8;\nclass DELAY;\nclass DELAY_4;\nclass DRIVER_1;\nclass DRIVER_4;\nclass DRIVER_4C;\nclass DT_SIMU;\nclass D_TRIG;\nclass ENERGY;\nclass ESR_COLLECT;\nclass ESR_MON_B8;\nclass ESR_MON_R4;\nclass ESR_MON_X8;\nclass EVENTS;\nclass FADE;\nclass FF_D2E;\nclass FF_D4E;\nclass FF_DRE;\nclass FF_JKE;\nclass FF_RSE;\nclass FIFO_16;\nclass FIFO_32;\nclass FILTER_DW;\nclass FILTER_I;\nclass FILTER_MAV_DW;\nclass FILTER_MAV_W;\nclass FILTER_W;\nclass FILTER_WAV;\nclass FLOW_METER;\nclass FT_AVG;\nclass FT_DERIV;\nclass FT_IMP;\nclass FT_INT;\nclass FT_INT2;\nclass FT_MIN_MAX;\nclass FT_PD;\nclass FT_PDT1;\nclass FT_PI;\nclass FT_PID;\nclass FT_PIDW;\nclass FT_PIDWL;\nclass FT_PIW;\nclass FT_PIWL;\nclass FT_PT1;\nclass FT_PT2;\nclass FT_PROFILE;\nclass FT_RMP;\nclass FT_TN16;\nclass FT_TN64;\nclass FT_TN8;\nclass GEN_BIT;\nclass GEN_PULSE;\nclass GEN_PW2;\nclass GEN_RDM;\nclass GEN_RDT;\nclass GEN_RMP;\nclass GEN_SIN;\nclass GEN_SQ;\nclass GEN_SQR;\nclass HOLIDAY;\nclass HYST;\nclass HYST_1;\nclass HYST_2;\nclass HYST_3;\nclass INC_DEC;\nclass INTEGRATE;\nclass INTERLOCK;\nclass INTERLOCK_4;\nclass LENGTH;\nclass LIST_NEXT;\nclass LTCH;\nclass LTCH_4;\nclass MANUAL_1;\nclass MANUAL_2;\nclass MANUAL_4;\nclass MATRIX;\nclass MESSAGE_4R;\nclass MESSAGE_8;\nclass METER;\nclass METER_STAT;\nclass M_D;\nclass M_T;\nclass M_TX;\nclass ONTIME;\nclass PARSET;\nclass PARSET2;\nclass PIN_CODE;\nclass PRESSURE;\nclass PWM_DC;\nclass PWM_PW;\nclass RMP_B;\nclass RMP_SOFT;\nclass RMP_W;\nclass RTC_2;\nclass RTC_MS;\nclass SCHEDULER;\nclass SCHEDULER_2;\nclass SEL2_OF_3;\nclass SEL2_OF_3B;\nclass SELECT_8;\nclass SEQUENCE_4;\nclass SEQUENCE_8;\nclass SH;\nclass SHR_4E;\nclass SHR_4UDE;\nclass SHR_8PLE;\nclass SHR_8UDE;\nclass SH_1;\nclass SH_2;\nclass SH_T;\nclass SIGNAL;\nclass SIGNAL_4;\nclass SPEED;\nclass STACK_16;\nclass STACK_32;\nclass STAIR2;\nclass STORE_8;\nclass SUN_POS;\nclass SUN_TIME;\nclass TC_MS;\nclass TC_S;\nclass TC_US;\nclass TEMPERATURE;\nclass TICKER;\nclass TOGGLE;\nclass TONOF;\nclass TP_X;\nclass TREND;\nclass TREND_DW;\nclass TUNE;\nclass TUNE2;\nclass _RMP_B;\nclass _RMP_NEXT;\nclass _RMP_W;\n\nclass AIN1 {\npublic:\n // Inputs\n IEC_DWORD IN;\n // Inputs\n IEC_INT SIGN_BIT;\n IEC_INT ERROR_BIT;\n IEC_BOOL ERROR_CODE_EN;\n IEC_DWORD ERROR_CODE;\n IEC_INT OVERFLOW_BIT;\n IEC_BOOL OVERFLOW_CODE_EN;\n IEC_DWORD OVERFLOW_CODE;\n IEC_INT BIT_0;\n IEC_INT BIT_N;\n IEC_REAL OUT_MIN;\n IEC_REAL OUT_MAX;\n IEC_DWORD CODE_MIN;\n IEC_DWORD CODE_MAX;\n IEC_REAL ERROR_OUTPUT;\n IEC_REAL OVERFLOW_OUTPUT;\n // Outputs\n IEC_REAL OUT;\n IEC_BOOL SIGN;\n IEC_BOOL ERROR;\n IEC_BOOL OVERFLOW;\n // Local variables\n IEC_DWORD TB;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n AIN1();\n\n // Execute function block\n void operator()();\n\n virtual ~AIN1() = default;\n};\n\nclass ALARM_2 {\npublic:\n // Inputs\n IEC_REAL X;\n IEC_REAL LO_1;\n IEC_REAL HI_1;\n IEC_REAL LO_2;\n IEC_REAL HI_2;\n IEC_REAL HYS;\n // Outputs\n IEC_BOOL Q1_LO;\n IEC_BOOL Q1_HI;\n IEC_BOOL Q2_LO;\n IEC_BOOL Q2_HI;\n // Local variables\n IEC_REAL TMP;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n ALARM_2();\n\n // Execute function block\n void operator()();\n\n virtual ~ALARM_2() = default;\n};\n\nclass ASTRO {\npublic:\n // Inputs\n IEC_REAL M;\n IEC_REAL AE;\n IEC_REAL PC;\n IEC_REAL LJ;\n // Outputs\n IEC_REAL YM;\n IEC_REAL YAE;\n IEC_REAL YPC;\n IEC_REAL YLJ;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n ASTRO();\n\n // Execute function block\n void operator()();\n\n virtual ~ASTRO() = default;\n};\n\nclass A_TRIG {\npublic:\n // Inputs\n IEC_REAL IN;\n IEC_REAL RES;\n // Outputs\n IEC_BOOL Q;\n IEC_REAL D;\n // Local variables\n IEC_REAL LAST_IN;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n A_TRIG();\n\n // Execute function block\n void operator()();\n\n virtual ~A_TRIG() = default;\n};\n\nclass BAR_GRAPH {\npublic:\n // Inputs\n IEC_REAL X;\n IEC_BOOL RST;\n // Inputs\n IEC_REAL TRIGGER_LOW;\n IEC_REAL TRIGGER_HIGH;\n IEC_BOOL ALARM_LOW;\n IEC_BOOL ALARM_HIGH;\n IEC_BOOL LOG_SCALE;\n // Outputs\n IEC_BOOL LOW;\n IEC_BOOL Q1;\n IEC_BOOL Q2;\n IEC_BOOL Q3;\n IEC_BOOL Q4;\n IEC_BOOL Q5;\n IEC_BOOL Q6;\n IEC_BOOL HIGH;\n IEC_BOOL ALARM;\n IEC_BYTE STATUS;\n // Local variables\n IEC_BOOL INIT;\n IEC_REAL T1;\n IEC_REAL T2;\n IEC_REAL T3;\n IEC_REAL T4;\n IEC_REAL T5;\n // Local variables\n IEC_REAL TEMP;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n BAR_GRAPH();\n\n // Execute function block\n void operator()();\n\n virtual ~BAR_GRAPH() = default;\n};\n\nclass BYTE_TO_BITS {\npublic:\n // Inputs\n IEC_BYTE IN;\n // Outputs\n IEC_BOOL B0;\n IEC_BOOL B1;\n IEC_BOOL B2;\n IEC_BOOL B3;\n IEC_BOOL B4;\n IEC_BOOL B5;\n IEC_BOOL B6;\n IEC_BOOL B7;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n BYTE_TO_BITS();\n\n // Execute function block\n void operator()();\n\n virtual ~BYTE_TO_BITS() = default;\n};\n\nclass B_TRIG {\npublic:\n // Inputs\n IEC_BOOL CLK;\n // Outputs\n IEC_BOOL Q;\n // Local variables\n IEC_BOOL EDGE;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n B_TRIG();\n\n // Execute function block\n void operator()();\n\n virtual ~B_TRIG() = default;\n};\n\nclass CALIBRATE {\npublic:\n // Inputs\n IEC_REAL X;\n IEC_BOOL CO;\n IEC_BOOL CS;\n // Inputs\n IEC_REAL Y_OFFSET;\n IEC_REAL Y_SCALE;\n // Outputs\n IEC_REAL Y;\n // Local variables\n IEC_REAL OFFSET;\n IEC_REAL SCALE;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n CALIBRATE();\n\n // Execute function block\n void operator()();\n\n virtual ~CALIBRATE() = default;\n};\n\nclass CLICK_CNT {\npublic:\n // Inputs\n IEC_BOOL IN;\n IEC_INT N;\n IEC_TIME TC;\n // Outputs\n IEC_BOOL Q;\n // Local variables\n TP TX;\n IEC_BOOL EDGE;\n IEC_INT CNT;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n CLICK_CNT();\n\n // Execute function block\n void operator()();\n\n virtual ~CLICK_CNT() = default;\n};\n\nclass CLICK_DEC {\npublic:\n // Inputs\n IEC_BOOL IN;\n IEC_TIME TC;\n // Outputs\n IEC_BOOL Q0;\n IEC_BOOL Q1;\n IEC_BOOL Q2;\n IEC_BOOL Q3;\n // Local variables\n TP TX;\n IEC_BOOL EDGE;\n IEC_INT CNT;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n CLICK_DEC();\n\n // Execute function block\n void operator()();\n\n virtual ~CLICK_DEC() = default;\n};\n\nclass CLK_DIV {\npublic:\n // Inputs\n IEC_BOOL CLK;\n IEC_BOOL RST;\n // Outputs\n IEC_BOOL Q0;\n IEC_BOOL Q1;\n IEC_BOOL Q2;\n IEC_BOOL Q3;\n IEC_BOOL Q4;\n IEC_BOOL Q5;\n IEC_BOOL Q6;\n IEC_BOOL Q7;\n // Local variables\n IEC_BYTE CNT;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n CLK_DIV();\n\n // Execute function block\n void operator()();\n\n virtual ~CLK_DIV() = default;\n};\n\nclass CLK_N {\npublic:\n // Inputs\n IEC_INT N;\n // Outputs\n IEC_BOOL Q;\n // Local variables\n IEC_BOOL EDGE;\n IEC_DWORD STIME;\n IEC_BOOL CLK;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n CLK_N();\n\n // Execute function block\n void operator()();\n\n virtual ~CLK_N() = default;\n};\n\nclass CLK_PRG {\npublic:\n // Inputs\n IEC_TIME PT;\n // Outputs\n IEC_BOOL Q;\n // Local variables\n IEC_BOOL INIT;\n IEC_TIME LAST;\n IEC_TIME TX;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n CLK_PRG();\n\n // Execute function block\n void operator()();\n\n virtual ~CLK_PRG() = default;\n};\n\nclass CLK_PULSE {\npublic:\n // Inputs\n IEC_TIME PT;\n IEC_INT N;\n IEC_BOOL RST;\n // Outputs\n IEC_BOOL Q;\n IEC_INT CNT;\n IEC_BOOL RUN;\n // Local variables\n IEC_DWORD TX;\n IEC_DWORD TN;\n IEC_BOOL INIT;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n CLK_PULSE();\n\n // Execute function block\n void operator()();\n\n virtual ~CLK_PULSE() = default;\n};\n\nclass CONTROL_SET1 {\npublic:\n // Inputs\n IEC_REAL KT;\n IEC_REAL TT;\n IEC_BOOL PI;\n IEC_BOOL PID;\n // Inputs\n IEC_REAL P_K;\n IEC_REAL PI_K;\n IEC_REAL PI_TN;\n IEC_REAL PID_K;\n IEC_REAL PID_TN;\n IEC_REAL PID_TV;\n // Outputs\n IEC_REAL KP;\n IEC_REAL TN;\n IEC_REAL TV;\n IEC_REAL KI;\n IEC_REAL KD;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n CONTROL_SET1();\n\n // Execute function block\n void operator()();\n\n virtual ~CONTROL_SET1() = default;\n};\n\nclass CONTROL_SET2 {\npublic:\n // Inputs\n IEC_REAL KS;\n IEC_REAL TU;\n IEC_REAL TG;\n IEC_BOOL PI;\n IEC_BOOL PID;\n // Inputs\n IEC_REAL P_K;\n IEC_REAL PI_K;\n IEC_REAL PI_TN;\n IEC_REAL PID_K;\n IEC_REAL PID_TN;\n IEC_REAL PID_TV;\n // Outputs\n IEC_REAL KP;\n IEC_REAL TN;\n IEC_REAL TV;\n IEC_REAL KI;\n IEC_REAL KD;\n // Local variables\n IEC_REAL TX;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n CONTROL_SET2();\n\n // Execute function block\n void operator()();\n\n virtual ~CONTROL_SET2() = default;\n};\n\nclass COUNT_BR {\npublic:\n // Inputs\n IEC_BOOL SET;\n IEC_BYTE IN;\n IEC_BOOL UP;\n IEC_BOOL DN;\n IEC_BYTE STEP;\n IEC_BYTE MX;\n IEC_BOOL RST;\n // Outputs\n IEC_BYTE CNT;\n // Local variables\n IEC_BOOL LAST_UP;\n IEC_BOOL LAST_DN;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n COUNT_BR();\n\n // Execute function block\n void operator()();\n\n virtual ~COUNT_BR() = default;\n};\n\nclass COUNT_DR {\npublic:\n // Inputs\n IEC_BOOL SET;\n IEC_DWORD IN;\n IEC_BOOL UP;\n IEC_BOOL DN;\n IEC_DWORD STEP;\n IEC_DWORD MX;\n IEC_BOOL RST;\n // Outputs\n IEC_DWORD CNT;\n // Local variables\n IEC_BOOL LAST_UP;\n IEC_BOOL LAST_DN;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n COUNT_DR();\n\n // Execute function block\n void operator()();\n\n virtual ~COUNT_DR() = default;\n};\n\nclass CTRL_OUT {\npublic:\n // Inputs\n IEC_REAL CI;\n IEC_REAL OFFSET;\n IEC_REAL MAN_IN;\n IEC_REAL LIM_L;\n IEC_REAL LIM_H;\n IEC_BOOL MANUAL;\n // Outputs\n IEC_REAL Y;\n IEC_BOOL LIM;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n CTRL_OUT();\n\n // Execute function block\n void operator()();\n\n virtual ~CTRL_OUT() = default;\n};\n\nclass CYCLE_4 {\npublic:\n // Inputs\n IEC_BOOL E;\n IEC_TIME T0;\n IEC_TIME T1;\n IEC_TIME T2;\n IEC_TIME T3;\n IEC_BOOL S0;\n IEC_INT SX;\n IEC_BOOL SL;\n // Outputs\n IEC_INT STATE;\n // Local variables\n IEC_TIME TX;\n IEC_TIME LAST;\n IEC_BOOL INIT;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n CYCLE_4();\n\n // Execute function block\n void operator()();\n\n virtual ~CYCLE_4() = default;\n};\n\nclass CYCLE_TIME {\npublic:\n // Inputs\n IEC_BOOL RST;\n // Outputs\n IEC_TIME CT_MIN;\n IEC_TIME CT_MAX;\n IEC_TIME CT_LAST;\n IEC_TIME SYSTIME;\n IEC_INT SYSDAYS;\n IEC_DWORD CYCLES;\n // Local variables\n IEC_TIME LAST_CYCLE;\n IEC_TIME TX;\n IEC_BOOL INIT;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n CYCLE_TIME();\n\n // Execute function block\n void operator()();\n\n virtual ~CYCLE_TIME() = default;\n};\n\nclass DCF77 {\npublic:\n // Inputs\n IEC_BOOL REC;\n IEC_BOOL SET;\n IEC_DT SDT;\n IEC_BOOL DSI;\n // Inputs\n IEC_TIME SYNC_TIMEOUT;\n IEC_INT TIME_OFFSET;\n IEC_BOOL DST_EN;\n // Outputs\n IEC_BOOL TP;\n IEC_BOOL DS;\n IEC_INT WDAY;\n IEC_BOOL ERROR;\n IEC_DT RTC;\n IEC_DT RTC1;\n IEC_INT MSEC;\n IEC_BOOL SYNC;\n // Local variables\n IEC_DT MEZ;\n IEC_DT UTC;\n IEC_INT STATE;\n IEC_BOOL EDGE;\n IEC_TIME TX;\n IEC_TIME TY;\n IEC_TIME LAST;\n Array1D BITS;\n IEC_INT CNT;\n IEC_INT I;\n IEC_DT OLD_TIME;\n IEC_INT MINUTE;\n IEC_INT HOUR;\n IEC_INT DAY;\n IEC_INT MONTH;\n IEC_INT YEAR;\n IEC_TIME LAST_SYNC;\n IEC_TIME T1;\n IEC_TIME TZ;\n IEC_BOOL INIT;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n DCF77();\n\n // Execute function block\n void operator()();\n\n virtual ~DCF77() = default;\n};\n\nclass DEAD_ZONE2 {\npublic:\n // Inputs\n IEC_REAL X;\n IEC_REAL L;\n // Outputs\n IEC_REAL Y;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n DEAD_ZONE2();\n\n // Execute function block\n void operator()();\n\n virtual ~DEAD_ZONE2() = default;\n};\n\nclass DEC_2 {\npublic:\n // Inputs\n IEC_BOOL D;\n IEC_BOOL A;\n // Outputs\n IEC_BOOL Q0;\n IEC_BOOL Q1;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n DEC_2();\n\n // Execute function block\n void operator()();\n\n virtual ~DEC_2() = default;\n};\n\nclass DEC_4 {\npublic:\n // Inputs\n IEC_BOOL D;\n IEC_BOOL A0;\n IEC_BOOL A1;\n // Outputs\n IEC_BOOL Q0;\n IEC_BOOL Q1;\n IEC_BOOL Q2;\n IEC_BOOL Q3;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n DEC_4();\n\n // Execute function block\n void operator()();\n\n virtual ~DEC_4() = default;\n};\n\nclass DEC_8 {\npublic:\n // Inputs\n IEC_BOOL D;\n IEC_BOOL A0;\n IEC_BOOL A1;\n IEC_BOOL A2;\n // Outputs\n IEC_BOOL Q0;\n IEC_BOOL Q1;\n IEC_BOOL Q2;\n IEC_BOOL Q3;\n IEC_BOOL Q4;\n IEC_BOOL Q5;\n IEC_BOOL Q6;\n IEC_BOOL Q7;\n // Local variables\n IEC_INT X;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n DEC_8();\n\n // Execute function block\n void operator()();\n\n virtual ~DEC_8() = default;\n};\n\nclass DELAY {\npublic:\n // Inputs\n IEC_REAL IN;\n IEC_INT N;\n IEC_BOOL RST;\n // Outputs\n IEC_REAL OUT;\n // Local variables\n Array1D BUF;\n IEC_INT I;\n IEC_BOOL INIT;\n IEC_INT STOP;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n DELAY();\n\n // Execute function block\n void operator()();\n\n virtual ~DELAY() = default;\n};\n\nclass DELAY_4 {\npublic:\n // Inputs\n IEC_REAL IN;\n // Outputs\n IEC_REAL OUT1;\n IEC_REAL OUT2;\n IEC_REAL OUT3;\n IEC_REAL OUT4;\n // Local variables\n IEC_REAL TEMP;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n DELAY_4();\n\n // Execute function block\n void operator()();\n\n virtual ~DELAY_4() = default;\n};\n\nclass DRIVER_1 {\npublic:\n // Inputs\n IEC_BOOL TOGGLE_MODE;\n IEC_TIME TIMEOUT;\n // Inputs\n IEC_BOOL SET;\n IEC_BOOL IN;\n IEC_BOOL RST;\n // Outputs\n IEC_BOOL Q;\n // Local variables\n TON OFF;\n IEC_BOOL EDGE;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n DRIVER_1();\n\n // Execute function block\n void operator()();\n\n virtual ~DRIVER_1() = default;\n};\n\nclass DRIVER_4C {\npublic:\n // Inputs\n IEC_BOOL IN;\n IEC_BOOL RST;\n // Inputs\n IEC_TIME TIMEOUT;\n Array1D SX;\n // Outputs\n IEC_INT SN;\n IEC_BOOL Q0;\n IEC_BOOL Q1;\n IEC_BOOL Q2;\n IEC_BOOL Q3;\n // Local variables\n TON OFF;\n IEC_BOOL EDGE;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n DRIVER_4C();\n\n // Execute function block\n void operator()();\n\n virtual ~DRIVER_4C() = default;\n};\n\nclass DT_SIMU {\npublic:\n // Inputs\n IEC_DT START;\n IEC_REAL SPEED;\n // Outputs\n IEC_DT DTS;\n // Local variables\n IEC_DWORD TC;\n IEC_BOOL INIT;\n IEC_DWORD LAST;\n IEC_DWORD TX;\n IEC_DWORD TD;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n DT_SIMU();\n\n // Execute function block\n void operator()();\n\n virtual ~DT_SIMU() = default;\n};\n\nclass D_TRIG {\npublic:\n // Inputs\n IEC_DWORD IN;\n // Outputs\n IEC_BOOL Q;\n IEC_DWORD X;\n // Local variables\n IEC_DWORD LAST_IN;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n D_TRIG();\n\n // Execute function block\n void operator()();\n\n virtual ~D_TRIG() = default;\n};\n\nclass ENERGY {\npublic:\n // Inputs\n IEC_REAL J;\n IEC_REAL C;\n IEC_REAL WH;\n // Outputs\n IEC_REAL YJ;\n IEC_REAL YC;\n IEC_REAL YWH;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n ENERGY();\n\n // Execute function block\n void operator()();\n\n virtual ~ENERGY() = default;\n};\n\nclass ESR_COLLECT {\npublic:\n // Inputs\n Array1D ESR_0;\n Array1D ESR_1;\n Array1D ESR_2;\n Array1D ESR_3;\n Array1D ESR_4;\n Array1D ESR_5;\n Array1D ESR_6;\n Array1D ESR_7;\n IEC_BOOL RST;\n // In-Out\n IEC_INT POS;\n // Outputs\n Array1D ESR_OUT;\n // Local variables\n IEC_INT MAX_IN;\n IEC_INT MAX_OUT;\n // Local variables\n IEC_INT CNT;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n ESR_COLLECT();\n\n // Execute function block\n void operator()();\n\n virtual ~ESR_COLLECT() = default;\n};\n\nclass ESR_MON_B8 {\npublic:\n // Inputs\n IEC_BOOL S0;\n IEC_BOOL S1;\n IEC_BOOL S2;\n IEC_BOOL S3;\n IEC_BOOL S4;\n IEC_BOOL S5;\n IEC_BOOL S6;\n IEC_BOOL S7;\n IEC_DT DT_IN;\n // Inputs\n IECStringVar<10> A0;\n IECStringVar<10> A1;\n IECStringVar<10> A2;\n IECStringVar<10> A3;\n IECStringVar<10> A4;\n IECStringVar<10> A5;\n IECStringVar<10> A6;\n IECStringVar<10> A7;\n // Outputs\n IEC_BOOL ESR_FLAG;\n // In-Out\n Array1D ESR_OUT;\n // Local variables\n IEC_BOOL X0;\n IEC_BOOL X1;\n IEC_BOOL X2;\n IEC_BOOL X3;\n IEC_BOOL X4;\n IEC_BOOL X5;\n IEC_BOOL X6;\n IEC_BOOL X7;\n IEC_TIME TX;\n IEC_INT CNT;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n ESR_MON_B8();\n\n // Execute function block\n void operator()();\n\n virtual ~ESR_MON_B8() = default;\n};\n\nclass ESR_MON_R4 {\npublic:\n // Inputs\n IEC_REAL R0;\n IEC_REAL R1;\n IEC_REAL R2;\n IEC_REAL R3;\n IEC_DT DT_IN;\n // Inputs\n IECStringVar<10> A0;\n IECStringVar<10> A1;\n IECStringVar<10> A2;\n IECStringVar<10> A3;\n IEC_REAL S0;\n IEC_REAL S1;\n IEC_REAL S2;\n IEC_REAL S3;\n // Outputs\n IEC_BOOL ESR_FLAG;\n // In-Out\n Array1D ESR_OUT;\n // Local variables\n IEC_Ptr P0;\n IEC_Ptr P1;\n IEC_Ptr P2;\n IEC_Ptr P3;\n IEC_REAL X0;\n IEC_REAL X1;\n IEC_REAL X2;\n IEC_REAL X3;\n IEC_TIME TX;\n IEC_INT CNT;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n ESR_MON_R4();\n\n // Execute function block\n void operator()();\n\n virtual ~ESR_MON_R4() = default;\n};\n\nclass ESR_MON_X8 {\npublic:\n // Inputs\n IEC_BYTE S0;\n IEC_BYTE S1;\n IEC_BYTE S2;\n IEC_BYTE S3;\n IEC_BYTE S4;\n IEC_BYTE S5;\n IEC_BYTE S6;\n IEC_BYTE S7;\n IEC_DT DT_IN;\n IEC_BYTE MODE;\n // Inputs\n IECStringVar<10> A0;\n IECStringVar<10> A1;\n IECStringVar<10> A2;\n IECStringVar<10> A3;\n IECStringVar<10> A4;\n IECStringVar<10> A5;\n IECStringVar<10> A6;\n IECStringVar<10> A7;\n // Outputs\n IEC_BOOL ESR_FLAG;\n // In-Out\n Array1D ESR_OUT;\n // Local variables\n IEC_BYTE X0;\n IEC_BYTE X1;\n IEC_BYTE X2;\n IEC_BYTE X3;\n IEC_BYTE X4;\n IEC_BYTE X5;\n IEC_BYTE X6;\n IEC_BYTE X7;\n IEC_TIME TX;\n IEC_INT CNT;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n ESR_MON_X8();\n\n // Execute function block\n void operator()();\n\n virtual ~ESR_MON_X8() = default;\n};\n\nclass EVENTS {\npublic:\n // Inputs\n IEC_DATE DATE_IN;\n IEC_BOOL ENA;\n // Outputs\n IEC_BOOL Y;\n IECStringVar<30> NAME;\n // Local variables\n IEC_INT I;\n IEC_DATE LAST_ACTIVE;\n IEC_INT SIZE;\n IEC_DINT DAY_IN;\n IEC_INT CYR;\n IEC_DINT LDAY;\n HOLIDAY_DATA CHECK;\n IEC_BOOL Y_INT;\n IECStringVar<30> NAME_INT;\n // In-Out\n Array1D ELIST;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n EVENTS();\n\n // Execute function block\n void operator()();\n\n virtual ~EVENTS() = default;\n};\n\nclass FF_D2E {\npublic:\n // Inputs\n IEC_BOOL D0;\n IEC_BOOL D1;\n IEC_BOOL CLK;\n IEC_BOOL RST;\n // Outputs\n IEC_BOOL Q0;\n IEC_BOOL Q1;\n // Local variables\n IEC_BOOL EDGE;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FF_D2E();\n\n // Execute function block\n void operator()();\n\n virtual ~FF_D2E() = default;\n};\n\nclass FF_D4E {\npublic:\n // Inputs\n IEC_BOOL D0;\n IEC_BOOL D1;\n IEC_BOOL D2;\n IEC_BOOL D3;\n IEC_BOOL CLK;\n IEC_BOOL RST;\n // Outputs\n IEC_BOOL Q0;\n IEC_BOOL Q1;\n IEC_BOOL Q2;\n IEC_BOOL Q3;\n // Local variables\n IEC_BOOL EDGE;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FF_D4E();\n\n // Execute function block\n void operator()();\n\n virtual ~FF_D4E() = default;\n};\n\nclass FF_DRE {\npublic:\n // Inputs\n IEC_BOOL SET;\n IEC_BOOL D;\n IEC_BOOL CLK;\n IEC_BOOL RST;\n // Outputs\n IEC_BOOL Q;\n // Local variables\n IEC_BOOL EDGE;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FF_DRE();\n\n // Execute function block\n void operator()();\n\n virtual ~FF_DRE() = default;\n};\n\nclass FF_JKE {\npublic:\n // Inputs\n IEC_BOOL SET;\n IEC_BOOL J;\n IEC_BOOL CLK;\n IEC_BOOL K;\n IEC_BOOL RST;\n // Outputs\n IEC_BOOL Q;\n // Local variables\n IEC_BOOL EDGE;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FF_JKE();\n\n // Execute function block\n void operator()();\n\n virtual ~FF_JKE() = default;\n};\n\nclass FF_RSE {\npublic:\n // Inputs\n IEC_BOOL CS;\n IEC_BOOL CR;\n IEC_BOOL RST;\n // Outputs\n IEC_BOOL Q;\n // Local variables\n IEC_BOOL ES;\n IEC_BOOL ER;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FF_RSE();\n\n // Execute function block\n void operator()();\n\n virtual ~FF_RSE() = default;\n};\n\nclass FIFO_16 {\npublic:\n // Inputs\n IEC_DWORD DIN;\n IEC_BOOL E;\n IEC_BOOL RD;\n IEC_BOOL WD;\n IEC_BOOL RST;\n // Outputs\n IEC_DWORD DOUT;\n IEC_BOOL EMPTY;\n IEC_BOOL FULL;\n // Local variables\n Array1D FIFO;\n IEC_INT PR;\n IEC_INT PW;\n // Local variables\n IEC_INT N;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FIFO_16();\n\n // Execute function block\n void operator()();\n\n virtual ~FIFO_16() = default;\n};\n\nclass FIFO_32 {\npublic:\n // Inputs\n IEC_DWORD DIN;\n IEC_BOOL E;\n IEC_BOOL RD;\n IEC_BOOL WD;\n IEC_BOOL RST;\n // Outputs\n IEC_DWORD DOUT;\n IEC_BOOL EMPTY;\n IEC_BOOL FULL;\n // Local variables\n Array1D FIFO;\n IEC_INT PR;\n IEC_INT PW;\n // Local variables\n IEC_INT N;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FIFO_32();\n\n // Execute function block\n void operator()();\n\n virtual ~FIFO_32() = default;\n};\n\nclass FILTER_DW {\npublic:\n // Inputs\n IEC_DWORD X;\n IEC_TIME T;\n // Outputs\n IEC_DWORD Y;\n // Local variables\n IEC_DWORD LAST;\n IEC_DWORD TX;\n IEC_BOOL INIT;\n IEC_REAL YI;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FILTER_DW();\n\n // Execute function block\n void operator()();\n\n virtual ~FILTER_DW() = default;\n};\n\nclass FILTER_I {\npublic:\n // Inputs\n IEC_INT X;\n IEC_TIME T;\n // Outputs\n IEC_INT Y;\n // Local variables\n IEC_DINT YI;\n IEC_DWORD LAST;\n IEC_DWORD TX;\n IEC_BOOL INIT;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FILTER_I();\n\n // Execute function block\n void operator()();\n\n virtual ~FILTER_I() = default;\n};\n\nclass FILTER_MAV_DW {\npublic:\n // Inputs\n IEC_DWORD X;\n IEC_UINT N;\n IEC_BOOL RST;\n // Outputs\n IEC_DWORD Y;\n // Local variables\n IEC_BOOL INIT;\n Array1D BUFFER;\n IEC_INT I;\n // Local variables\n IEC_INT TMP;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FILTER_MAV_DW();\n\n // Execute function block\n void operator()();\n\n virtual ~FILTER_MAV_DW() = default;\n};\n\nclass FILTER_MAV_W {\npublic:\n // Inputs\n IEC_WORD X;\n IEC_UINT N;\n IEC_BOOL RST;\n // Outputs\n IEC_WORD Y;\n // Local variables\n IEC_BOOL INIT;\n Array1D BUFFER;\n IEC_INT I;\n IEC_DWORD SUM;\n // Local variables\n IEC_INT TMP;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FILTER_MAV_W();\n\n // Execute function block\n void operator()();\n\n virtual ~FILTER_MAV_W() = default;\n};\n\nclass FILTER_W {\npublic:\n // Inputs\n IEC_WORD X;\n IEC_TIME T;\n // Outputs\n IEC_WORD Y;\n // Local variables\n IEC_DWORD LAST;\n IEC_DWORD TX;\n IEC_BOOL INIT;\n IEC_DWORD TMP;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FILTER_W();\n\n // Execute function block\n void operator()();\n\n virtual ~FILTER_W() = default;\n};\n\nclass FILTER_WAV {\npublic:\n // Inputs\n IEC_REAL X;\n Array1D W;\n IEC_BOOL RST;\n // Outputs\n IEC_REAL Y;\n // Local variables\n IEC_BOOL INIT;\n Array1D BUFFER;\n IEC_INT I;\n IEC_INT N;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FILTER_WAV();\n\n // Execute function block\n void operator()();\n\n virtual ~FILTER_WAV() = default;\n};\n\nclass FT_DERIV {\npublic:\n // Inputs\n IEC_REAL IN;\n IEC_REAL K;\n IEC_BOOL RUN;\n // Outputs\n IEC_REAL OUT;\n // Local variables\n IEC_REAL OLD;\n IEC_DWORD TX;\n IEC_DWORD LAST;\n IEC_BOOL INIT;\n IEC_REAL TC;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FT_DERIV();\n\n // Execute function block\n void operator()();\n\n virtual ~FT_DERIV() = default;\n};\n\nclass FT_MIN_MAX {\npublic:\n // Inputs\n IEC_REAL IN;\n IEC_BOOL RST;\n // Outputs\n IEC_REAL MX;\n IEC_REAL MN;\n // Local variables\n IEC_BOOL INIT;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FT_MIN_MAX();\n\n // Execute function block\n void operator()();\n\n virtual ~FT_MIN_MAX() = default;\n};\n\nclass FT_PIWL {\npublic:\n // Inputs\n IEC_REAL IN;\n IEC_REAL KP;\n IEC_REAL KI;\n IEC_REAL LIM_L;\n IEC_REAL LIM_H;\n IEC_BOOL RST;\n // Outputs\n IEC_REAL Y;\n IEC_BOOL LIM;\n // Local variables\n IEC_BOOL INIT;\n IEC_DWORD TX;\n IEC_REAL TC;\n IEC_DWORD T_LAST;\n IEC_REAL IN_LAST;\n IEC_REAL I;\n IEC_REAL P;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FT_PIWL();\n\n // Execute function block\n void operator()();\n\n virtual ~FT_PIWL() = default;\n};\n\nclass FT_PT1 {\npublic:\n // Inputs\n IEC_REAL IN;\n IEC_TIME T;\n IEC_REAL K;\n // Outputs\n IEC_REAL OUT;\n // Local variables\n IEC_DWORD LAST;\n IEC_DWORD TX;\n IEC_BOOL INIT;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FT_PT1();\n\n // Execute function block\n void operator()();\n\n virtual ~FT_PT1() = default;\n};\n\nclass FT_PROFILE {\npublic:\n // Inputs\n IEC_REAL K;\n IEC_REAL O;\n IEC_REAL M;\n IEC_BOOL E;\n // Inputs\n IEC_REAL VALUE_0;\n IEC_TIME TIME_1;\n IEC_REAL VALUE_1;\n IEC_TIME TIME_2;\n IEC_REAL VALUE_2;\n IEC_TIME TIME_3;\n IEC_REAL VALUE_3;\n IEC_TIME TIME_10;\n IEC_REAL VALUE_10;\n IEC_TIME TIME_11;\n IEC_REAL VALUE_11;\n IEC_TIME TIME_12;\n IEC_REAL VALUE_12;\n IEC_TIME TIME_13;\n IEC_REAL VALUE_13;\n // Outputs\n IEC_REAL Y;\n IEC_BOOL RUN;\n IEC_TIME ET;\n // Local variables\n IEC_TIME TX;\n IEC_BOOL EDGE;\n IEC_BYTE STATE;\n IEC_TIME TA;\n IEC_TIME TB;\n IEC_TIME T0;\n IEC_REAL TEMP;\n IEC_REAL VA;\n IEC_REAL VB;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FT_PROFILE();\n\n // Execute function block\n void operator()();\n\n virtual ~FT_PROFILE() = default;\n};\n\nclass FT_RMP {\npublic:\n // Inputs\n IEC_BOOL RMP;\n IEC_REAL IN;\n IEC_REAL KR;\n IEC_REAL KF;\n // Outputs\n IEC_REAL OUT;\n IEC_BOOL BUSY;\n IEC_BOOL UD;\n // Local variables\n IEC_TIME TX;\n IEC_TIME LAST;\n IEC_BOOL INIT;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FT_RMP();\n\n // Execute function block\n void operator()();\n\n virtual ~FT_RMP() = default;\n};\n\nclass FT_TN16 {\npublic:\n // Inputs\n IEC_REAL IN;\n IEC_TIME T;\n // Outputs\n IEC_REAL OUT;\n IEC_BOOL TRIG;\n // Local variables\n IEC_INT LENGTH;\n Array1D X;\n IEC_INT CNT;\n IEC_TIME LAST;\n IEC_TIME TX;\n IEC_BOOL INIT;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FT_TN16();\n\n // Execute function block\n void operator()();\n\n virtual ~FT_TN16() = default;\n};\n\nclass FT_TN64 {\npublic:\n // Inputs\n IEC_REAL IN;\n IEC_TIME T;\n // Outputs\n IEC_REAL OUT;\n IEC_BOOL TRIG;\n // Local variables\n IEC_INT LENGTH;\n Array1D X;\n IEC_INT CNT;\n IEC_TIME LAST;\n IEC_TIME TX;\n IEC_BOOL INIT;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FT_TN64();\n\n // Execute function block\n void operator()();\n\n virtual ~FT_TN64() = default;\n};\n\nclass FT_TN8 {\npublic:\n // Inputs\n IEC_REAL IN;\n IEC_TIME T;\n // Outputs\n IEC_REAL OUT;\n IEC_BOOL TRIG;\n // Local variables\n IEC_INT LENGTH;\n Array1D X;\n IEC_INT CNT;\n IEC_TIME LAST;\n IEC_TIME TX;\n IEC_BOOL INIT;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FT_TN8();\n\n // Execute function block\n void operator()();\n\n virtual ~FT_TN8() = default;\n};\n\nclass GEN_BIT {\npublic:\n // Inputs\n IEC_DWORD IN0;\n IEC_DWORD IN1;\n IEC_DWORD IN2;\n IEC_DWORD IN3;\n IEC_BOOL CLK;\n IEC_INT STEPS;\n IEC_INT REP;\n IEC_BOOL RST;\n // Outputs\n IEC_BOOL Q0;\n IEC_BOOL Q1;\n IEC_BOOL Q2;\n IEC_BOOL Q3;\n IEC_INT CNT;\n IEC_BOOL RUN;\n // Local variables\n IEC_DWORD R0;\n IEC_DWORD R1;\n IEC_DWORD R2;\n IEC_DWORD R3;\n IEC_INT RX;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n GEN_BIT();\n\n // Execute function block\n void operator()();\n\n virtual ~GEN_BIT() = default;\n};\n\nclass GEN_PULSE {\npublic:\n // Inputs\n IEC_BOOL ENQ;\n IEC_TIME PTH;\n IEC_TIME PTL;\n // Outputs\n IEC_BOOL Q;\n // Local variables\n IEC_TIME TX;\n IEC_TIME TN;\n IEC_BOOL INIT;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n GEN_PULSE();\n\n // Execute function block\n void operator()();\n\n virtual ~GEN_PULSE() = default;\n};\n\nclass GEN_PW2 {\npublic:\n // Inputs\n IEC_BOOL ENQ;\n IEC_TIME TH1;\n IEC_TIME TL1;\n IEC_TIME TH2;\n IEC_TIME TL2;\n IEC_BOOL TS;\n // Outputs\n IEC_BOOL Q;\n IEC_TIME TH;\n IEC_TIME TL;\n // Local variables\n IEC_TIME T_HIGH;\n IEC_TIME T_LOW;\n IEC_TIME TX;\n IEC_TIME START;\n IEC_BOOL INIT;\n IEC_TIME ET;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n GEN_PW2();\n\n // Execute function block\n void operator()();\n\n virtual ~GEN_PW2() = default;\n};\n\nclass GEN_RDM {\npublic:\n // Inputs\n IEC_TIME PT;\n IEC_REAL AM;\n IEC_REAL OS;\n // Outputs\n IEC_BOOL Q;\n IEC_REAL OUT;\n // Local variables\n IEC_TIME TX;\n IEC_TIME LAST;\n IEC_BOOL INIT;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n GEN_RDM();\n\n // Execute function block\n void operator()();\n\n virtual ~GEN_RDM() = default;\n};\n\nclass GEN_RDT {\npublic:\n // Inputs\n IEC_BOOL ENABLE;\n IEC_TIME MIN_TIME_MS;\n IEC_TIME MAX_TIME_MS;\n IEC_TIME TP_Q;\n // Outputs\n IEC_BOOL XQ;\n // Local variables\n TON TONRDMTIMER;\n TOF TOF_XQ;\n IEC_TIME TRDMTIME;\n IEC_REAL RRDMTIME;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n GEN_RDT();\n\n // Execute function block\n void operator()();\n\n virtual ~GEN_RDT() = default;\n};\n\nclass GEN_RMP {\npublic:\n // Inputs\n IEC_TIME PT;\n IEC_REAL AM;\n IEC_REAL OS;\n IEC_REAL DL;\n // Outputs\n IEC_BOOL Q;\n IEC_REAL OUT;\n // Local variables\n IEC_TIME TX;\n IEC_TIME LAST;\n IEC_BOOL INIT;\n IEC_REAL TEMP;\n IEC_REAL LTEMP;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n GEN_RMP();\n\n // Execute function block\n void operator()();\n\n virtual ~GEN_RMP() = default;\n};\n\nclass GEN_SIN {\npublic:\n // Inputs\n IEC_TIME PT;\n IEC_REAL AM;\n IEC_REAL OS;\n IEC_REAL DL;\n // Outputs\n IEC_BOOL Q;\n IEC_REAL OUT;\n // Local variables\n IEC_TIME TX;\n IEC_TIME LAST;\n IEC_BOOL INIT;\n IEC_REAL TEMP;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n GEN_SIN();\n\n // Execute function block\n void operator()();\n\n virtual ~GEN_SIN() = default;\n};\n\nclass GEN_SQ {\npublic:\n // Inputs\n IEC_TIME PT;\n // Outputs\n IEC_BOOL Q;\n // Local variables\n IEC_DWORD TN;\n IEC_DWORD TX;\n IEC_BOOL INIT;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n GEN_SQ();\n\n // Execute function block\n void operator()();\n\n virtual ~GEN_SQ() = default;\n};\n\nclass GEN_SQR {\npublic:\n // Inputs\n IEC_TIME PT;\n IEC_REAL AM;\n IEC_REAL OS;\n IEC_REAL DC;\n IEC_REAL DL;\n // Outputs\n IEC_BOOL Q;\n IEC_REAL OUT;\n // Local variables\n IEC_TIME TX;\n IEC_TIME LAST;\n IEC_BOOL INIT;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n GEN_SQR();\n\n // Execute function block\n void operator()();\n\n virtual ~GEN_SQR() = default;\n};\n\nclass HOLIDAY {\npublic:\n // Inputs\n IEC_DATE DATE_IN;\n IEC_INT LANGU;\n IEC_BOOL FRIDAY;\n IEC_BOOL SATURDAY;\n IEC_BOOL SUNDAY;\n // In-Out\n Array1D HOLIDAYS;\n // Local variables\n IEC_INT SIZE;\n // Outputs\n IEC_BOOL Y;\n IECStringVar<30> NAME;\n // Local variables\n IEC_DATE LAST_ACTIVE;\n IEC_DATE OSTERN;\n IEC_INT I;\n IEC_INT JAHR;\n IEC_DATE X_DATE;\n IEC_INT LX;\n IEC_INT WDX;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n HOLIDAY();\n\n // Execute function block\n void operator()();\n\n virtual ~HOLIDAY() = default;\n};\n\nclass HYST {\npublic:\n // Inputs\n IEC_REAL IN;\n IEC_REAL ON;\n IEC_REAL OFF;\n // Outputs\n IEC_BOOL Q;\n IEC_BOOL WIN;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n HYST();\n\n // Execute function block\n void operator()();\n\n virtual ~HYST() = default;\n};\n\nclass HYST_1 {\npublic:\n // Inputs\n IEC_REAL IN;\n IEC_REAL HIGH;\n IEC_REAL LOW;\n // Outputs\n IEC_BOOL Q;\n IEC_BOOL WIN;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n HYST_1();\n\n // Execute function block\n void operator()();\n\n virtual ~HYST_1() = default;\n};\n\nclass HYST_2 {\npublic:\n // Inputs\n IEC_REAL IN;\n IEC_REAL VAL;\n IEC_REAL HYS;\n // Outputs\n IEC_BOOL Q;\n IEC_BOOL WIN;\n // Local variables\n IEC_REAL TMP;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n HYST_2();\n\n // Execute function block\n void operator()();\n\n virtual ~HYST_2() = default;\n};\n\nclass HYST_3 {\npublic:\n // Inputs\n IEC_REAL IN;\n IEC_REAL HYST;\n IEC_REAL VAL1;\n IEC_REAL VAL2;\n // Outputs\n IEC_BOOL Q1;\n IEC_BOOL Q2;\n // Local variables\n IEC_REAL X;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n HYST_3();\n\n // Execute function block\n void operator()();\n\n virtual ~HYST_3() = default;\n};\n\nclass INC_DEC {\npublic:\n // Inputs\n IEC_BOOL CHA;\n IEC_BOOL CHB;\n IEC_BOOL RST;\n // Outputs\n IEC_BOOL DIR;\n IEC_INT CNT;\n // Local variables\n IEC_BOOL EDGEA;\n IEC_BOOL CLK;\n IEC_BOOL CLKA;\n IEC_BOOL CLKB;\n IEC_BOOL EDGEB;\n IEC_BOOL AXB;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n INC_DEC();\n\n // Execute function block\n void operator()();\n\n virtual ~INC_DEC() = default;\n};\n\nclass INTEGRATE {\npublic:\n // Inputs\n IEC_BOOL E;\n IEC_REAL X;\n IEC_REAL K;\n // In-Out\n IEC_REAL Y;\n // Local variables\n IEC_REAL X_LAST;\n IEC_BOOL INIT;\n IEC_DWORD LAST;\n IEC_DWORD TX;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n INTEGRATE();\n\n // Execute function block\n void operator()();\n\n virtual ~INTEGRATE() = default;\n};\n\nclass INTERLOCK {\npublic:\n // Inputs\n IEC_BOOL I1;\n IEC_BOOL I2;\n IEC_TIME TL;\n // Outputs\n IEC_BOOL Q1;\n IEC_BOOL Q2;\n // Local variables\n TOF T1;\n TOF T2;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n INTERLOCK();\n\n // Execute function block\n void operator()();\n\n virtual ~INTERLOCK() = default;\n};\n\nclass INTERLOCK_4 {\npublic:\n // Inputs\n // Inputs\n IEC_BOOL I0;\n IEC_BOOL I1;\n IEC_BOOL I2;\n IEC_BOOL I3;\n IEC_BOOL E;\n IEC_INT MODE;\n // Outputs\n IEC_BYTE OUT;\n IEC_BOOL TP;\n // Local variables\n IEC_BYTE IN;\n IEC_BYTE LAST;\n IEC_BYTE OLD;\n IEC_INT LMODE;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n INTERLOCK_4();\n\n // Execute function block\n void operator()();\n\n virtual ~INTERLOCK_4() = default;\n};\n\nclass LENGTH {\npublic:\n // Inputs\n IEC_REAL M;\n IEC_REAL P;\n IEC_REAL IN;\n IEC_REAL FT;\n IEC_REAL YD;\n IEC_REAL MILE;\n IEC_REAL SM;\n IEC_REAL FM;\n // Outputs\n IEC_REAL YM;\n IEC_REAL YP;\n IEC_REAL YIN;\n IEC_REAL YFT;\n IEC_REAL YYD;\n IEC_REAL YMILE;\n IEC_REAL YSM;\n IEC_REAL YFM;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n LENGTH();\n\n // Execute function block\n void operator()();\n\n virtual ~LENGTH() = default;\n};\n\nclass LIST_NEXT {\npublic:\n // Inputs\n IEC_BYTE SEP;\n IEC_BOOL RST;\n // In-Out\n IECStringVar LIST;\n // Outputs\n IECStringVar LEL;\n IEC_BOOL NUL;\n // Local variables\n IEC_INT POS;\n IEC_Ptr> PT;\n IEC_Ptr> PO;\n IEC_BYTE C;\n IEC_INT WRITE;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n LIST_NEXT();\n\n // Execute function block\n void operator()();\n\n virtual ~LIST_NEXT() = default;\n};\n\nclass LTCH {\npublic:\n // Inputs\n IEC_BOOL D;\n IEC_BOOL L;\n IEC_BOOL RST;\n // Outputs\n IEC_BOOL Q;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n LTCH();\n\n // Execute function block\n void operator()();\n\n virtual ~LTCH() = default;\n};\n\nclass LTCH_4 {\npublic:\n // Inputs\n IEC_BOOL D0;\n IEC_BOOL D1;\n IEC_BOOL D2;\n IEC_BOOL D3;\n IEC_BOOL L;\n IEC_BOOL RST;\n // Outputs\n IEC_BOOL Q0;\n IEC_BOOL Q1;\n IEC_BOOL Q2;\n IEC_BOOL Q3;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n LTCH_4();\n\n // Execute function block\n void operator()();\n\n virtual ~LTCH_4() = default;\n};\n\nclass MANUAL_1 {\npublic:\n // Inputs\n IEC_BOOL IN;\n IEC_BOOL MAN;\n IEC_BOOL M_I;\n IEC_BOOL SET;\n IEC_BOOL RST;\n // Outputs\n IEC_BOOL Q;\n IEC_BYTE STATUS;\n // Local variables\n IEC_BOOL S_EDGE;\n IEC_BOOL R_EDGE;\n IEC_BOOL EDGE;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n MANUAL_1();\n\n // Execute function block\n void operator()();\n\n virtual ~MANUAL_1() = default;\n};\n\nclass MANUAL_2 {\npublic:\n // Inputs\n IEC_BOOL IN;\n IEC_BOOL ENA;\n IEC_BOOL ON;\n IEC_BOOL OFF;\n IEC_BOOL MAN;\n // Outputs\n IEC_BOOL Q;\n IEC_BYTE STATUS;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n MANUAL_2();\n\n // Execute function block\n void operator()();\n\n virtual ~MANUAL_2() = default;\n};\n\nclass MANUAL_4 {\npublic:\n // Inputs\n IEC_BOOL I0;\n IEC_BOOL I1;\n IEC_BOOL I2;\n IEC_BOOL I3;\n IEC_BOOL MAN;\n IEC_BOOL STP;\n IEC_BOOL M0;\n IEC_BOOL M1;\n IEC_BOOL M2;\n IEC_BOOL M3;\n // Outputs\n IEC_BOOL Q0;\n IEC_BOOL Q1;\n IEC_BOOL Q2;\n IEC_BOOL Q3;\n IEC_BYTE STATUS;\n // Local variables\n IEC_BOOL EDGE;\n IEC_INT POS;\n IEC_BOOL TOG;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n MANUAL_4();\n\n // Execute function block\n void operator()();\n\n virtual ~MANUAL_4() = default;\n};\n\nclass MATRIX {\npublic:\n // Inputs\n IEC_BOOL X1;\n IEC_BOOL X2;\n IEC_BOOL X3;\n IEC_BOOL X4;\n IEC_BOOL X5;\n // Inputs\n IEC_BOOL RELEASE;\n // Outputs\n IEC_BYTE CODE;\n IEC_BOOL TP;\n IEC_BOOL Y1;\n IEC_BOOL Y2;\n IEC_BOOL Y3;\n IEC_BOOL Y4;\n // Local variables\n IEC_BYTE LINE;\n Array1D X;\n Array1D L;\n IEC_INT I;\n IEC_BYTE TEMP;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n MATRIX();\n\n // Execute function block\n void operator()();\n\n virtual ~MATRIX() = default;\n};\n\nclass MESSAGE_4R {\npublic:\n // Inputs\n IECStringVar M0;\n IECStringVar M1;\n IECStringVar M2;\n IECStringVar M3;\n IEC_INT MM;\n IEC_BOOL ENQ;\n IEC_BOOL CLK;\n IEC_TIME T1;\n // Outputs\n IECStringVar MX;\n IEC_INT MN;\n IEC_BOOL TR;\n // Local variables\n TON TIMER;\n IEC_BOOL EDGE;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n MESSAGE_4R();\n\n // Execute function block\n void operator()();\n\n virtual ~MESSAGE_4R() = default;\n};\n\nclass MESSAGE_8 {\npublic:\n // Inputs\n IEC_BOOL IN1;\n IEC_BOOL IN2;\n IEC_BOOL IN3;\n IEC_BOOL IN4;\n IEC_BOOL IN5;\n IEC_BOOL IN6;\n IEC_BOOL IN7;\n IEC_BOOL IN8;\n // Inputs\n IECStringVar S1;\n IECStringVar S2;\n IECStringVar S3;\n IECStringVar S4;\n IECStringVar S5;\n IECStringVar S6;\n IECStringVar S7;\n IECStringVar S8;\n // Outputs\n IECStringVar M;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n MESSAGE_8();\n\n // Execute function block\n void operator()();\n\n virtual ~MESSAGE_8() = default;\n};\n\nclass METER {\npublic:\n // Inputs\n IEC_REAL M1;\n IEC_REAL M2;\n IEC_BOOL I1;\n IEC_BOOL I2;\n IEC_REAL D;\n IEC_BOOL RST;\n // In-Out\n IEC_REAL MX;\n // Local variables\n REAL2 MR;\n IEC_REAL MX1;\n IEC_REAL MX2;\n IEC_DWORD TX;\n IEC_DWORD LAST;\n IEC_REAL TC;\n IEC_BOOL INIT;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n METER();\n\n // Execute function block\n void operator()();\n\n virtual ~METER() = default;\n};\n\nclass METER_STAT {\npublic:\n // Inputs\n IEC_REAL IN;\n IEC_DATE DI;\n IEC_BOOL RST;\n // In-Out\n IEC_REAL LAST_DAY;\n IEC_REAL CURRENT_DAY;\n IEC_REAL LAST_WEEK;\n IEC_REAL CURRENT_WEEK;\n IEC_REAL LAST_MONTH;\n IEC_REAL CURRENT_MONTH;\n IEC_REAL LAST_YEAR;\n IEC_REAL CURRENT_YEAR;\n // Local variables\n IEC_REAL YEAR_START;\n IEC_REAL MONTH_START;\n IEC_REAL WEEK_START;\n IEC_REAL DAY_START;\n IEC_DATE LAST_RUN;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n METER_STAT();\n\n // Execute function block\n void operator()();\n\n virtual ~METER_STAT() = default;\n};\n\nclass M_D {\npublic:\n // Inputs\n IEC_BOOL START;\n IEC_BOOL STOP;\n IEC_TIME TMAX;\n IEC_BOOL RST;\n // Outputs\n IEC_TIME PT;\n IEC_TIME ET;\n IEC_BOOL RUN;\n // Local variables\n IEC_BOOL EDGE;\n IEC_TIME T0;\n IEC_TIME TX;\n IEC_BOOL STARTUP;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n M_D();\n\n // Execute function block\n void operator()();\n\n virtual ~M_D() = default;\n};\n\nclass M_T {\npublic:\n // Inputs\n IEC_BOOL IN;\n IEC_TIME TMAX;\n IEC_BOOL RST;\n // Outputs\n IEC_TIME PT;\n IEC_TIME ET;\n // Local variables\n IEC_BOOL EDGE;\n IEC_TIME START;\n IEC_TIME TX;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n M_T();\n\n // Execute function block\n void operator()();\n\n virtual ~M_T() = default;\n};\n\nclass M_TX {\npublic:\n // Inputs\n IEC_BOOL IN;\n IEC_TIME TMAX;\n IEC_BOOL RST;\n // Outputs\n IEC_TIME TH;\n IEC_TIME TL;\n IEC_REAL DC;\n IEC_REAL F;\n IEC_TIME ET;\n // Local variables\n IEC_BOOL EDGE;\n IEC_TIME START;\n IEC_TIME STOP;\n IEC_TIME TX;\n IEC_BOOL RISE;\n IEC_BOOL FALL;\n IEC_BOOL STARTUP;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n M_TX();\n\n // Execute function block\n void operator()();\n\n virtual ~M_TX() = default;\n};\n\nclass ONTIME {\npublic:\n // Inputs\n IEC_BOOL IN;\n IEC_BOOL RST;\n // In-Out\n IEC_UDINT SECONDS;\n IEC_UDINT CYCLES;\n // Local variables\n IEC_DWORD TX;\n IEC_DWORD LAST;\n IEC_BOOL EDGE;\n IEC_BOOL INIT;\n IEC_DWORD MS;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n ONTIME();\n\n // Execute function block\n void operator()();\n\n virtual ~ONTIME() = default;\n};\n\nclass PARSET {\npublic:\n // Inputs\n IEC_BOOL A0;\n IEC_BOOL A1;\n // Inputs\n IEC_REAL X01;\n IEC_REAL X02;\n IEC_REAL X03;\n IEC_REAL X04;\n IEC_REAL X11;\n IEC_REAL X12;\n IEC_REAL X13;\n IEC_REAL X14;\n IEC_REAL X21;\n IEC_REAL X22;\n IEC_REAL X23;\n IEC_REAL X24;\n IEC_REAL X31;\n IEC_REAL X32;\n IEC_REAL X33;\n IEC_REAL X34;\n IEC_TIME TC;\n // Outputs\n IEC_REAL P1;\n IEC_REAL P2;\n IEC_REAL P3;\n IEC_REAL P4;\n // Local variables\n Array2D X;\n IEC_REAL S1;\n IEC_REAL S2;\n IEC_REAL S3;\n IEC_REAL S4;\n IEC_DWORD TX;\n IEC_DWORD LAST;\n IEC_BOOL START;\n IEC_BYTE SET;\n IEC_BOOL INIT;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n PARSET();\n\n // Execute function block\n void operator()();\n\n virtual ~PARSET() = default;\n};\n\nclass PIN_CODE {\npublic:\n // Inputs\n IEC_BYTE CB;\n IEC_BOOL E;\n // Inputs\n IECStringVar<8> PIN;\n // Outputs\n IEC_BOOL TP;\n // Local variables\n IEC_INT POS;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n PIN_CODE();\n\n // Execute function block\n void operator()();\n\n virtual ~PIN_CODE() = default;\n};\n\nclass PRESSURE {\npublic:\n // Inputs\n IEC_REAL MWS;\n IEC_REAL TORR;\n IEC_REAL ATT;\n IEC_REAL ATM;\n IEC_REAL PA;\n IEC_REAL BAR;\n // Outputs\n IEC_REAL YMWS;\n IEC_REAL YTORR;\n IEC_REAL YATT;\n IEC_REAL YATM;\n IEC_REAL YPA;\n IEC_REAL YBAR;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n PRESSURE();\n\n // Execute function block\n void operator()();\n\n virtual ~PRESSURE() = default;\n};\n\nclass RTC_MS {\npublic:\n // Inputs\n IEC_BOOL SET;\n IEC_DT SDT;\n IEC_INT SMS;\n // Outputs\n IEC_DT XDT;\n IEC_INT XMS;\n // Local variables\n IEC_BOOL INIT;\n IEC_DWORD LAST;\n IEC_DWORD TX;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n RTC_MS();\n\n // Execute function block\n void operator()();\n\n virtual ~RTC_MS() = default;\n};\n\nclass SCHEDULER {\npublic:\n // Inputs\n IEC_BOOL E0;\n IEC_BOOL E1;\n IEC_BOOL E2;\n IEC_BOOL E3;\n // Inputs\n IEC_TIME T0;\n IEC_TIME T1;\n IEC_TIME T2;\n IEC_TIME T3;\n // Outputs\n IEC_BOOL Q0;\n IEC_BOOL Q1;\n IEC_BOOL Q2;\n IEC_BOOL Q3;\n // Local variables\n IEC_BOOL INIT;\n IEC_TIME S0;\n IEC_TIME S1;\n IEC_TIME S2;\n IEC_TIME S3;\n IEC_TIME TX;\n IEC_INT C;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n SCHEDULER();\n\n // Execute function block\n void operator()();\n\n virtual ~SCHEDULER() = default;\n};\n\nclass SCHEDULER_2 {\npublic:\n // Inputs\n IEC_BOOL E0;\n IEC_BOOL E1;\n IEC_BOOL E2;\n IEC_BOOL E3;\n // Inputs\n IEC_UINT C0;\n IEC_UINT C1;\n IEC_UINT C2;\n IEC_UINT C3;\n IEC_UINT O0;\n IEC_UINT O1;\n IEC_UINT O2;\n IEC_UINT O3;\n // Outputs\n IEC_BOOL Q0;\n IEC_BOOL Q1;\n IEC_BOOL Q2;\n IEC_BOOL Q3;\n // Local variables\n IEC_UINT SX;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n SCHEDULER_2();\n\n // Execute function block\n void operator()();\n\n virtual ~SCHEDULER_2() = default;\n};\n\nclass SEL2_OF_3 {\npublic:\n // Inputs\n IEC_REAL IN1;\n IEC_REAL IN2;\n IEC_REAL IN3;\n IEC_REAL D;\n // Outputs\n IEC_REAL Y;\n IEC_INT W;\n IEC_BOOL E;\n // Local variables\n IEC_BOOL D12;\n IEC_BOOL D23;\n IEC_BOOL D31;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n SEL2_OF_3();\n\n // Execute function block\n void operator()();\n\n virtual ~SEL2_OF_3() = default;\n};\n\nclass SEL2_OF_3B {\npublic:\n // Inputs\n IEC_BOOL IN1;\n IEC_BOOL IN2;\n IEC_BOOL IN3;\n IEC_TIME TD;\n // Outputs\n IEC_BOOL Q;\n IEC_BOOL W;\n // Local variables\n TON TDEL;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n SEL2_OF_3B();\n\n // Execute function block\n void operator()();\n\n virtual ~SEL2_OF_3B() = default;\n};\n\nclass SELECT_8 {\npublic:\n // Inputs\n IEC_BOOL E;\n IEC_BOOL SET;\n IEC_BYTE IN;\n IEC_BOOL UP;\n IEC_BOOL DN;\n IEC_BOOL RST;\n // Outputs\n IEC_BOOL Q0;\n IEC_BOOL Q1;\n IEC_BOOL Q2;\n IEC_BOOL Q3;\n IEC_BOOL Q4;\n IEC_BOOL Q5;\n IEC_BOOL Q6;\n IEC_BOOL Q7;\n IEC_INT STATE;\n // Local variables\n IEC_BOOL LAST_UP;\n IEC_BOOL LAST_DN;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n SELECT_8();\n\n // Execute function block\n void operator()();\n\n virtual ~SELECT_8() = default;\n};\n\nclass SEQUENCE_4 {\npublic:\n // Inputs\n IEC_BOOL IN0;\n IEC_BOOL IN1;\n IEC_BOOL IN2;\n IEC_BOOL IN3;\n IEC_BOOL START;\n IEC_BOOL RST;\n IEC_TIME WAIT0;\n IEC_TIME DELAY0;\n IEC_TIME WAIT1;\n IEC_TIME DELAY1;\n IEC_TIME WAIT2;\n IEC_TIME DELAY2;\n IEC_TIME WAIT3;\n IEC_TIME DELAY3;\n // Inputs\n IEC_BOOL STOP_ON_ERROR;\n // Outputs\n IEC_BOOL Q0;\n IEC_BOOL Q1;\n IEC_BOOL Q2;\n IEC_BOOL Q3;\n IEC_BOOL QX;\n IEC_BOOL RUN;\n IEC_INT STEP;\n IEC_BYTE STATUS;\n // Local variables\n IEC_TIME LAST;\n IEC_BOOL EDGE;\n IEC_TIME TX;\n IEC_BOOL INIT;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n SEQUENCE_4();\n\n // Execute function block\n void operator()();\n\n virtual ~SEQUENCE_4() = default;\n};\n\nclass SEQUENCE_8 {\npublic:\n // Inputs\n IEC_BOOL IN0;\n IEC_BOOL IN1;\n IEC_BOOL IN2;\n IEC_BOOL IN3;\n IEC_BOOL IN4;\n IEC_BOOL IN5;\n IEC_BOOL IN6;\n IEC_BOOL IN7;\n IEC_BOOL START;\n IEC_BOOL RST;\n IEC_TIME WAIT0;\n IEC_TIME DELAY0;\n IEC_TIME WAIT1;\n IEC_TIME DELAY1;\n IEC_TIME WAIT2;\n IEC_TIME DELAY2;\n IEC_TIME WAIT3;\n IEC_TIME DELAY3;\n IEC_TIME WAIT4;\n IEC_TIME DELAY4;\n IEC_TIME WAIT5;\n IEC_TIME DELAY5;\n IEC_TIME WAIT6;\n IEC_TIME DELAY6;\n IEC_TIME WAIT7;\n IEC_TIME DELAY7;\n // Inputs\n IEC_BOOL STOP_ON_ERROR;\n // Outputs\n IEC_BOOL Q0;\n IEC_BOOL Q1;\n IEC_BOOL Q2;\n IEC_BOOL Q3;\n IEC_BOOL Q4;\n IEC_BOOL Q5;\n IEC_BOOL Q6;\n IEC_BOOL Q7;\n IEC_BOOL QX;\n IEC_BOOL RUN;\n IEC_INT STEP;\n IEC_BYTE STATUS;\n // Local variables\n IEC_TIME LAST;\n IEC_BOOL EDGE;\n IEC_TIME TX;\n IEC_BOOL INIT;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n SEQUENCE_8();\n\n // Execute function block\n void operator()();\n\n virtual ~SEQUENCE_8() = default;\n};\n\nclass SH {\npublic:\n // Inputs\n IEC_REAL IN;\n IEC_BOOL CLK;\n // Outputs\n IEC_REAL OUT;\n IEC_BOOL TRIG;\n // Local variables\n IEC_BOOL EDGE;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n SH();\n\n // Execute function block\n void operator()();\n\n virtual ~SH() = default;\n};\n\nclass SHR_4E {\npublic:\n // Inputs\n IEC_BOOL SET;\n IEC_BOOL D0;\n IEC_BOOL CLK;\n IEC_BOOL RST;\n // Outputs\n IEC_BOOL Q0;\n IEC_BOOL Q1;\n IEC_BOOL Q2;\n IEC_BOOL Q3;\n // Local variables\n R_TRIG TRIG;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n SHR_4E();\n\n // Execute function block\n void operator()();\n\n virtual ~SHR_4E() = default;\n};\n\nclass SHR_4UDE {\npublic:\n // Inputs\n IEC_BOOL SET;\n IEC_BOOL D0;\n IEC_BOOL D3;\n IEC_BOOL CLK;\n IEC_BOOL DN;\n IEC_BOOL RST;\n // Outputs\n IEC_BOOL Q0;\n IEC_BOOL Q1;\n IEC_BOOL Q2;\n IEC_BOOL Q3;\n // Local variables\n R_TRIG TRIG;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n SHR_4UDE();\n\n // Execute function block\n void operator()();\n\n virtual ~SHR_4UDE() = default;\n};\n\nclass SHR_8PLE {\npublic:\n // Inputs\n IEC_BOOL DIN;\n IEC_BYTE DLOAD;\n IEC_BOOL CLK;\n IEC_BOOL UP;\n IEC_BOOL LOAD;\n IEC_BOOL RST;\n // Outputs\n IEC_BOOL DOUT;\n // Local variables\n IEC_BOOL EDGE;\n IEC_BYTE REGISTER;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n SHR_8PLE();\n\n // Execute function block\n void operator()();\n\n virtual ~SHR_8PLE() = default;\n};\n\nclass SHR_8UDE {\npublic:\n // Inputs\n IEC_BOOL SET;\n IEC_BOOL D0;\n IEC_BOOL D7;\n IEC_BOOL CLK;\n IEC_BOOL DN;\n IEC_BOOL RST;\n // Outputs\n IEC_BOOL Q0;\n IEC_BOOL Q1;\n IEC_BOOL Q2;\n IEC_BOOL Q3;\n IEC_BOOL Q4;\n IEC_BOOL Q5;\n IEC_BOOL Q6;\n IEC_BOOL Q7;\n // Local variables\n R_TRIG TRIG;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n SHR_8UDE();\n\n // Execute function block\n void operator()();\n\n virtual ~SHR_8UDE() = default;\n};\n\nclass SH_1 {\npublic:\n // Inputs\n IEC_REAL IN;\n IEC_TIME PT;\n // Outputs\n IEC_REAL OUT;\n IEC_BOOL TRIG;\n // Local variables\n IEC_TIME LAST;\n IEC_TIME TX;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n SH_1();\n\n // Execute function block\n void operator()();\n\n virtual ~SH_1() = default;\n};\n\nclass SH_2 {\npublic:\n // Inputs\n IEC_REAL IN;\n IEC_TIME PT;\n IEC_INT N;\n IEC_INT DISC;\n // Outputs\n IEC_REAL OUT;\n IEC_BOOL TRIG;\n IEC_REAL AVG;\n IEC_REAL HIGH;\n IEC_REAL LOW;\n // Local variables\n IEC_INT M;\n Array1D BUF;\n Array1D BUF2;\n IEC_TIME LAST;\n IEC_INT I;\n IEC_INT START;\n IEC_REAL TEMP;\n IEC_INT STOP;\n IEC_TIME TX;\n IEC_INT D2;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n SH_2();\n\n // Execute function block\n void operator()();\n\n virtual ~SH_2() = default;\n};\n\nclass SH_T {\npublic:\n // Inputs\n IEC_REAL IN;\n IEC_BOOL E;\n // Outputs\n IEC_REAL OUT;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n SH_T();\n\n // Execute function block\n void operator()();\n\n virtual ~SH_T() = default;\n};\n\nclass SIGNAL {\npublic:\n // Inputs\n IEC_BOOL IN;\n IEC_BYTE SIG;\n IEC_TIME TS;\n // Outputs\n IEC_BOOL Q;\n // Local variables\n IEC_DWORD TX;\n IEC_BYTE STEP;\n // Local variables\n IEC_BYTE ONE;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n SIGNAL();\n\n // Execute function block\n void operator()();\n\n virtual ~SIGNAL() = default;\n};\n\nclass SPEED {\npublic:\n // Inputs\n IEC_REAL MS;\n IEC_REAL KMH;\n IEC_REAL KN;\n IEC_REAL MH;\n // Outputs\n IEC_REAL YMS;\n IEC_REAL YKMH;\n IEC_REAL YKN;\n IEC_REAL YMH;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n SPEED();\n\n // Execute function block\n void operator()();\n\n virtual ~SPEED() = default;\n};\n\nclass STACK_16 {\npublic:\n // Inputs\n IEC_DWORD DIN;\n IEC_BOOL E;\n IEC_BOOL RD;\n IEC_BOOL WD;\n IEC_BOOL RST;\n // Outputs\n IEC_DWORD DOUT;\n IEC_BOOL EMPTY;\n IEC_BOOL FULL;\n // Local variables\n Array1D STACK;\n IEC_INT PT;\n // Local variables\n IEC_INT N;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n STACK_16();\n\n // Execute function block\n void operator()();\n\n virtual ~STACK_16() = default;\n};\n\nclass STACK_32 {\npublic:\n // Inputs\n IEC_DWORD DIN;\n IEC_BOOL E;\n IEC_BOOL RD;\n IEC_BOOL WD;\n IEC_BOOL RST;\n // Outputs\n IEC_DWORD DOUT;\n IEC_BOOL EMPTY;\n IEC_BOOL FULL;\n // Local variables\n Array1D STACK;\n IEC_INT PT;\n // Local variables\n IEC_INT N;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n STACK_32();\n\n // Execute function block\n void operator()();\n\n virtual ~STACK_32() = default;\n};\n\nclass STAIR2 {\npublic:\n // Inputs\n IEC_REAL X;\n IEC_REAL D;\n // Outputs\n IEC_REAL Y;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n STAIR2();\n\n // Execute function block\n void operator()();\n\n virtual ~STAIR2() = default;\n};\n\nclass STORE_8 {\npublic:\n // Inputs\n IEC_BOOL SET;\n IEC_BOOL D0;\n IEC_BOOL D1;\n IEC_BOOL D2;\n IEC_BOOL D3;\n IEC_BOOL D4;\n IEC_BOOL D5;\n IEC_BOOL D6;\n IEC_BOOL D7;\n IEC_BOOL CLR;\n IEC_BOOL RST;\n // Outputs\n IEC_BOOL Q0;\n IEC_BOOL Q1;\n IEC_BOOL Q2;\n IEC_BOOL Q3;\n IEC_BOOL Q4;\n IEC_BOOL Q5;\n IEC_BOOL Q6;\n IEC_BOOL Q7;\n // Local variables\n IEC_BOOL EDGE;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n STORE_8();\n\n // Execute function block\n void operator()();\n\n virtual ~STORE_8() = default;\n};\n\nclass SUN_POS {\npublic:\n // Inputs\n IEC_REAL LATITUDE;\n IEC_REAL LONGITUDE;\n IEC_DT UTC;\n // Outputs\n IEC_REAL B;\n IEC_REAL H;\n IEC_REAL HR;\n // Local variables\n IEC_REAL G;\n IEC_REAL A;\n IEC_REAL D;\n IEC_REAL T1;\n IEC_REAL N;\n IEC_REAL E;\n IEC_REAL C;\n IEC_REAL TAU;\n IEC_REAL SIN_D;\n IEC_REAL RLAT;\n IEC_REAL SIN_LAT;\n IEC_REAL COS_LAT;\n IEC_REAL COS_TAU;\n IEC_REAL COS_D;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n SUN_POS();\n\n // Execute function block\n void operator()();\n\n virtual ~SUN_POS() = default;\n};\n\nclass SUN_TIME {\npublic:\n // Inputs\n IEC_REAL LATITUDE;\n IEC_REAL LONGITUDE;\n IEC_DATE UTC;\n IEC_REAL H;\n // Outputs\n IEC_TOD MIDDAY;\n IEC_TOD SUN_RISE;\n IEC_TOD SUN_SET;\n IEC_REAL SUN_DECLINATION;\n // Local variables\n IEC_REAL DK;\n IEC_TIME DELTA;\n IEC_REAL B;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n SUN_TIME();\n\n // Execute function block\n void operator()();\n\n virtual ~SUN_TIME() = default;\n};\n\nclass TC_MS {\npublic:\n // Outputs\n IEC_DWORD TC;\n // Local variables\n IEC_BOOL INIT;\n IEC_DWORD TX;\n IEC_DWORD LAST;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n TC_MS();\n\n // Execute function block\n void operator()();\n\n virtual ~TC_MS() = default;\n};\n\nclass TC_S {\npublic:\n // Outputs\n IEC_REAL TC;\n // Local variables\n IEC_BOOL INIT;\n IEC_DWORD TX;\n IEC_DWORD LAST;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n TC_S();\n\n // Execute function block\n void operator()();\n\n virtual ~TC_S() = default;\n};\n\nclass TC_US {\npublic:\n // Outputs\n IEC_DWORD TC;\n // Local variables\n IEC_BOOL INIT;\n IEC_DWORD TX;\n IEC_DWORD LAST;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n TC_US();\n\n // Execute function block\n void operator()();\n\n virtual ~TC_US() = default;\n};\n\nclass TEMPERATURE {\npublic:\n // Inputs\n IEC_REAL K;\n IEC_REAL C;\n IEC_REAL F;\n IEC_REAL RE;\n IEC_REAL RA;\n // Outputs\n IEC_REAL YK;\n IEC_REAL YC;\n IEC_REAL YF;\n IEC_REAL YRE;\n IEC_REAL YRA;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n TEMPERATURE();\n\n // Execute function block\n void operator()();\n\n virtual ~TEMPERATURE() = default;\n};\n\nclass TICKER {\npublic:\n // Inputs\n IEC_INT N;\n IEC_TIME PT;\n // In-Out\n IECStringVar TEXT;\n // Outputs\n IECStringVar DISPLAY;\n // Local variables\n TP DELAY;\n IEC_INT STEP;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n TICKER();\n\n // Execute function block\n void operator()();\n\n virtual ~TICKER() = default;\n};\n\nclass TOGGLE {\npublic:\n // Inputs\n IEC_BOOL CLK;\n IEC_BOOL RST;\n // Outputs\n IEC_BOOL Q;\n // Local variables\n IEC_BOOL EDGE;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n TOGGLE();\n\n // Execute function block\n void operator()();\n\n virtual ~TOGGLE() = default;\n};\n\nclass TONOF {\npublic:\n // Inputs\n IEC_BOOL IN;\n IEC_TIME T_ON;\n IEC_TIME T_OFF;\n // Outputs\n IEC_BOOL Q;\n // Local variables\n TON X;\n IEC_BOOL OLD;\n IEC_BOOL MODE;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n TONOF();\n\n // Execute function block\n void operator()();\n\n virtual ~TONOF() = default;\n};\n\nclass TP_X {\npublic:\n // Inputs\n IEC_BOOL IN;\n IEC_TIME PT;\n // Outputs\n IEC_BOOL Q;\n IEC_TIME ET;\n // Local variables\n IEC_BOOL EDGE;\n IEC_TIME START;\n IEC_TIME TX;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n TP_X();\n\n // Execute function block\n void operator()();\n\n virtual ~TP_X() = default;\n};\n\nclass TREND {\npublic:\n // Inputs\n IEC_REAL X;\n // Outputs\n IEC_BOOL Q;\n IEC_BOOL TU;\n IEC_BOOL TD;\n IEC_REAL D;\n // Local variables\n IEC_REAL LAST_X;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n TREND();\n\n // Execute function block\n void operator()();\n\n virtual ~TREND() = default;\n};\n\nclass TREND_DW {\npublic:\n // Inputs\n IEC_DWORD X;\n // Outputs\n IEC_BOOL Q;\n IEC_BOOL TU;\n IEC_BOOL TD;\n IEC_DWORD D;\n // Local variables\n IEC_DWORD LAST_X;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n TREND_DW();\n\n // Execute function block\n void operator()();\n\n virtual ~TREND_DW() = default;\n};\n\nclass TUNE {\npublic:\n // Inputs\n IEC_BOOL SET;\n IEC_BOOL SU;\n IEC_BOOL SD;\n IEC_BOOL RST;\n // Inputs\n IEC_REAL SS;\n IEC_REAL LIMIT_L;\n IEC_REAL LIMIT_H;\n IEC_REAL RST_VAL;\n IEC_REAL SET_VAL;\n IEC_TIME T1;\n IEC_TIME T2;\n IEC_REAL S1;\n IEC_REAL S2;\n // Outputs\n IEC_REAL Y;\n // Local variables\n IEC_DWORD TX;\n IEC_DWORD START;\n IEC_DWORD START2;\n IEC_INT STATE;\n IEC_BOOL IN;\n IEC_REAL STEP;\n IEC_REAL SPEED;\n IEC_REAL Y_START;\n IEC_REAL Y_START2;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n TUNE();\n\n // Execute function block\n void operator()();\n\n virtual ~TUNE() = default;\n};\n\nclass TUNE2 {\npublic:\n // Inputs\n IEC_BOOL SET;\n IEC_BOOL SU;\n IEC_BOOL SD;\n IEC_BOOL FU;\n IEC_BOOL FD;\n IEC_BOOL RST;\n // Inputs\n IEC_REAL SS;\n IEC_REAL FS;\n IEC_REAL LIMIT_L;\n IEC_REAL LIMIT_H;\n IEC_REAL RST_VAL;\n IEC_REAL SET_VAL;\n IEC_TIME TR;\n IEC_REAL S1;\n IEC_REAL S2;\n // Outputs\n IEC_REAL Y;\n // Local variables\n IEC_DWORD TX;\n IEC_DWORD START;\n IEC_INT STATE;\n IEC_BOOL IN;\n IEC_REAL STEP;\n IEC_REAL SPEED;\n IEC_REAL Y_START;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n TUNE2();\n\n // Execute function block\n void operator()();\n\n virtual ~TUNE2() = default;\n};\n\nclass _RMP_B {\npublic:\n // Inputs\n IEC_BOOL DIR;\n IEC_BOOL E;\n IEC_TIME TR;\n // In-Out\n IEC_BYTE RMP;\n // Local variables\n IEC_TIME TX;\n IEC_TIME TL;\n IEC_TIME TN;\n IEC_BOOL INIT;\n IEC_BOOL LAST_DIR;\n IEC_BYTE START;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n _RMP_B();\n\n // Execute function block\n void operator()();\n\n virtual ~_RMP_B() = default;\n};\n\nclass _RMP_W {\npublic:\n // Inputs\n IEC_BOOL DIR;\n IEC_BOOL E;\n IEC_TIME TR;\n // In-Out\n IEC_WORD RMP;\n // Local variables\n IEC_DWORD TX;\n IEC_DWORD TL;\n IEC_DINT STEP;\n IEC_BOOL INIT;\n IEC_BOOL LAST_DIR;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n _RMP_W();\n\n // Execute function block\n void operator()();\n\n virtual ~_RMP_W() = default;\n};\n\nclass FT_AVG {\npublic:\n // Inputs\n IEC_REAL IN;\n IEC_BOOL E;\n IEC_INT N;\n IEC_BOOL RST;\n // Outputs\n IEC_REAL AVG;\n // Local variables\n DELAY BUFF;\n IEC_INT I;\n IEC_BOOL INIT;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FT_AVG();\n\n // Execute function block\n void operator()();\n\n virtual ~FT_AVG() = default;\n};\n\nclass DRIVER_4 {\npublic:\n // Inputs\n IEC_BOOL TOGGLE_MODE;\n IEC_TIME TIMEOUT;\n // Inputs\n IEC_BOOL SET;\n IEC_BOOL IN0;\n IEC_BOOL IN1;\n IEC_BOOL IN2;\n IEC_BOOL IN3;\n IEC_BOOL RST;\n // Outputs\n IEC_BOOL Q0;\n IEC_BOOL Q1;\n IEC_BOOL Q2;\n IEC_BOOL Q3;\n // Local variables\n DRIVER_1 D0;\n DRIVER_1 D1;\n DRIVER_1 D2;\n DRIVER_1 D3;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n DRIVER_4();\n\n // Execute function block\n void operator()();\n\n virtual ~DRIVER_4() = default;\n};\n\nclass FT_PD {\npublic:\n // Inputs\n IEC_REAL IN;\n IEC_REAL KP;\n IEC_REAL TV;\n // Outputs\n IEC_REAL Y;\n // Local variables\n FT_DERIV DIFF;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FT_PD();\n\n // Execute function block\n void operator()();\n\n virtual ~FT_PD() = default;\n};\n\nclass CTRL_PI {\npublic:\n // Inputs\n IEC_REAL ACT;\n IEC_REAL SET;\n IEC_REAL SUP;\n IEC_REAL OFS;\n IEC_REAL M_I;\n IEC_BOOL MAN;\n IEC_BOOL RST;\n IEC_REAL KP;\n IEC_REAL KI;\n IEC_REAL LL;\n IEC_REAL LH;\n // Outputs\n IEC_REAL Y;\n IEC_REAL DIFF;\n IEC_BOOL LIM;\n // Local variables\n FT_PIWL PI;\n CTRL_OUT CO;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n CTRL_PI();\n\n // Execute function block\n void operator()();\n\n virtual ~CTRL_PI() = default;\n};\n\nclass FT_PIDWL {\npublic:\n // Inputs\n IEC_REAL IN;\n IEC_REAL KP;\n IEC_REAL TN;\n IEC_REAL TV;\n IEC_REAL LIM_L;\n IEC_REAL LIM_H;\n IEC_BOOL RST;\n // Outputs\n IEC_REAL Y;\n IEC_BOOL LIM;\n // Local variables\n FT_PIWL PIWL;\n FT_DERIV DIFF;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FT_PIDWL();\n\n // Execute function block\n void operator()();\n\n virtual ~FT_PIDWL() = default;\n};\n\nclass DEAD_BAND_A {\npublic:\n // Inputs\n IEC_REAL X;\n IEC_TIME T;\n IEC_REAL KL;\n IEC_REAL LM;\n // Outputs\n IEC_REAL Y;\n IEC_REAL L;\n // Local variables\n FT_PT1 TP1;\n FT_PT1 TP2;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n DEAD_BAND_A();\n\n // Execute function block\n void operator()();\n\n virtual ~DEAD_BAND_A() = default;\n};\n\nclass FT_IMP {\npublic:\n // Inputs\n IEC_REAL IN;\n IEC_TIME T;\n IEC_REAL K;\n // Outputs\n IEC_REAL OUT;\n // Local variables\n FT_PT1 T1;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FT_IMP();\n\n // Execute function block\n void operator()();\n\n virtual ~FT_IMP() = default;\n};\n\nclass FT_PDT1 {\npublic:\n // Inputs\n IEC_REAL IN;\n IEC_REAL KP;\n IEC_REAL TV;\n IEC_REAL T1;\n // Outputs\n IEC_REAL Y;\n // Local variables\n FT_DERIV DIFF;\n FT_PT1 TP;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FT_PDT1();\n\n // Execute function block\n void operator()();\n\n virtual ~FT_PDT1() = default;\n};\n\nclass FLOW_METER {\npublic:\n // Inputs\n IEC_REAL VX;\n IEC_BOOL E;\n IEC_BOOL RST;\n // Inputs\n IEC_BOOL PULSE_MODE;\n IEC_TIME UPDATE_TIME;\n // Outputs\n IEC_REAL F;\n // In-Out\n IEC_REAL X;\n IEC_UDINT Y;\n // Local variables\n IEC_TIME TX;\n IEC_TIME TL;\n INTEGRATE INT1;\n IEC_BOOL INIT;\n IEC_BOOL E_LAST;\n IEC_INT TMP;\n IEC_REAL X_LAST;\n IEC_UDINT Y_LAST;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FLOW_METER();\n\n // Execute function block\n void operator()();\n\n virtual ~FLOW_METER() = default;\n};\n\nclass FT_INT {\npublic:\n // Inputs\n IEC_REAL IN;\n IEC_REAL K;\n IEC_BOOL RUN;\n IEC_BOOL RST;\n IEC_REAL OUT_MIN;\n IEC_REAL OUT_MAX;\n // Outputs\n IEC_REAL OUT;\n IEC_BOOL LIM;\n // Local variables\n INTEGRATE INTEG;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FT_INT();\n\n // Execute function block\n void operator()();\n\n virtual ~FT_INT() = default;\n};\n\nclass FT_INT2 {\npublic:\n // Inputs\n IEC_REAL IN;\n IEC_REAL K;\n IEC_BOOL RUN;\n IEC_BOOL RST;\n IEC_REAL OUT_MIN;\n IEC_REAL OUT_MAX;\n // Outputs\n IEC_REAL OUT;\n IEC_BOOL LIM;\n // Local variables\n INTEGRATE INTEG;\n IEC_REAL IX;\n REAL2 VAL;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FT_INT2();\n\n // Execute function block\n void operator()();\n\n virtual ~FT_INT2() = default;\n};\n\nclass FT_PIDW {\npublic:\n // Inputs\n IEC_REAL IN;\n IEC_REAL KP;\n IEC_REAL TN;\n IEC_REAL TV;\n IEC_REAL LIM_L;\n IEC_REAL LIM_H;\n IEC_BOOL RST;\n // Outputs\n IEC_REAL Y;\n IEC_BOOL LIM;\n // Local variables\n INTEGRATE INTEG;\n FT_DERIV DIFF;\n IEC_REAL YI;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FT_PIDW();\n\n // Execute function block\n void operator()();\n\n virtual ~FT_PIDW() = default;\n};\n\nclass FT_PT2 {\npublic:\n // Inputs\n IEC_REAL IN;\n IEC_TIME T;\n IEC_REAL D;\n IEC_REAL K;\n // Outputs\n IEC_REAL OUT;\n // Local variables\n IEC_BOOL INIT;\n INTEGRATE INT1;\n INTEGRATE INT2;\n IEC_REAL TN;\n IEC_REAL I1;\n IEC_REAL I2;\n IEC_REAL TN2;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FT_PT2();\n\n // Execute function block\n void operator()();\n\n virtual ~FT_PT2() = default;\n};\n\nclass PARSET2 {\npublic:\n // Inputs\n IEC_REAL X;\n // Inputs\n IEC_REAL X01;\n IEC_REAL X02;\n IEC_REAL X03;\n IEC_REAL X04;\n IEC_REAL X11;\n IEC_REAL X12;\n IEC_REAL X13;\n IEC_REAL X14;\n IEC_REAL X21;\n IEC_REAL X22;\n IEC_REAL X23;\n IEC_REAL X24;\n IEC_REAL X31;\n IEC_REAL X32;\n IEC_REAL X33;\n IEC_REAL X34;\n IEC_REAL L1;\n IEC_REAL L2;\n IEC_REAL L3;\n IEC_TIME TC;\n // Outputs\n IEC_REAL P1;\n IEC_REAL P2;\n IEC_REAL P3;\n IEC_REAL P4;\n // Local variables\n PARSET PSET;\n IEC_BOOL INIT;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n PARSET2();\n\n // Execute function block\n void operator()();\n\n virtual ~PARSET2() = default;\n};\n\nclass RTC_2 {\npublic:\n // Inputs\n IEC_BOOL SET;\n IEC_DT SDT;\n IEC_INT SMS;\n IEC_BOOL DEN;\n IEC_INT OFS;\n // Outputs\n IEC_DT UDT;\n IEC_DT LOCAL_DT;\n IEC_BOOL DSO;\n IEC_INT XMS;\n // Local variables\n RTC_MS RT;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n RTC_2();\n\n // Execute function block\n void operator()();\n\n virtual ~RTC_2() = default;\n};\n\nclass SIGNAL_4 {\npublic:\n // Inputs\n IEC_BOOL IN1;\n IEC_BOOL IN2;\n IEC_BOOL IN3;\n IEC_BOOL IN4;\n IEC_TIME TS;\n // Inputs\n IEC_BYTE S1;\n IEC_BYTE S2;\n IEC_BYTE S3;\n IEC_BYTE S4;\n // Outputs\n IEC_BOOL Q;\n // Local variables\n SIGNAL SIG;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n SIGNAL_4();\n\n // Execute function block\n void operator()();\n\n virtual ~SIGNAL_4() = default;\n};\n\nclass CALENDAR_CALC {\npublic:\n // Inputs\n IEC_BOOL SPE;\n IEC_REAL H;\n // In-Out\n CALENDAR XCAL;\n Array1D HOLIDAYS;\n // Local variables\n IEC_DT LAST;\n IEC_DINT LAST_DAY;\n HOLIDAY HOLY;\n SUN_TIME SUN;\n IEC_INT LAST_HOUR;\n IEC_TOD UTOD;\n SUN_POS POS;\n IEC_DT PLAST;\n // Local variables\n IEC_DINT DTEMP;\n IEC_INT TMP;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n CALENDAR_CALC();\n\n // Execute function block\n void operator()();\n\n virtual ~CALENDAR_CALC() = default;\n};\n\nclass PWM_DC {\npublic:\n // Inputs\n IEC_REAL F;\n IEC_REAL DC;\n // Outputs\n IEC_BOOL Q;\n // Local variables\n CLK_PRG CLK;\n TP_X PULSE;\n IEC_REAL TMP;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n PWM_DC();\n\n // Execute function block\n void operator()();\n\n virtual ~PWM_DC() = default;\n};\n\nclass PWM_PW {\npublic:\n // Inputs\n IEC_REAL F;\n IEC_TIME PW;\n // Outputs\n IEC_BOOL Q;\n // Local variables\n CLK_PRG CLK;\n TP_X PULSE;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n PWM_PW();\n\n // Execute function block\n void operator()();\n\n virtual ~PWM_PW() = default;\n};\n\nclass RMP_B {\npublic:\n // Inputs\n IEC_BOOL SET;\n IEC_TIME PT;\n IEC_BOOL E;\n IEC_BOOL UP;\n IEC_BOOL RST;\n // Outputs\n IEC_BYTE OUT;\n IEC_BOOL BUSY;\n IEC_BOOL HIGH;\n IEC_BOOL LOW;\n // Local variables\n _RMP_B RMP;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n RMP_B();\n\n // Execute function block\n void operator()();\n\n virtual ~RMP_B() = default;\n};\n\nclass RMP_SOFT {\npublic:\n // Inputs\n IEC_BOOL IN;\n IEC_BYTE VAL;\n // Inputs\n IEC_TIME PT_ON;\n IEC_TIME PT_OFF;\n // Outputs\n IEC_BYTE OUT;\n // Local variables\n _RMP_B RMP;\n IEC_BYTE TMP;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n RMP_SOFT();\n\n // Execute function block\n void operator()();\n\n virtual ~RMP_SOFT() = default;\n};\n\nclass _RMP_NEXT {\npublic:\n // Inputs\n IEC_BOOL E;\n IEC_BYTE IN;\n IEC_TIME TR;\n IEC_TIME TF;\n IEC_TIME TL;\n // Outputs\n IEC_BOOL DIR;\n IEC_BOOL UP;\n IEC_BOOL DN;\n // In-Out\n IEC_BYTE OUT;\n // Local variables\n _RMP_B RMX;\n TREND_DW DIRX;\n TP T_LOCK;\n IEC_BOOL XEN;\n IEC_BOOL XDIR;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n _RMP_NEXT();\n\n // Execute function block\n void operator()();\n\n virtual ~_RMP_NEXT() = default;\n};\n\nclass RMP_W {\npublic:\n // Inputs\n IEC_BOOL SET;\n IEC_TIME PT;\n IEC_BOOL E;\n IEC_BOOL UP;\n IEC_BOOL RST;\n // Outputs\n IEC_WORD OUT;\n IEC_BOOL BUSY;\n IEC_BOOL HIGH;\n IEC_BOOL LOW;\n // Local variables\n _RMP_W RMP;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n RMP_W();\n\n // Execute function block\n void operator()();\n\n virtual ~RMP_W() = default;\n};\n\nclass CTRL_PID {\npublic:\n // Inputs\n IEC_REAL ACT;\n IEC_REAL SET;\n IEC_REAL SUP;\n IEC_REAL OFS;\n IEC_REAL M_I;\n IEC_BOOL MAN;\n IEC_BOOL RST;\n IEC_REAL KP;\n IEC_REAL TN;\n IEC_REAL TV;\n IEC_REAL LL;\n IEC_REAL LH;\n // Outputs\n IEC_REAL Y;\n IEC_REAL DIFF;\n IEC_BOOL LIM;\n // Local variables\n FT_PIDWL PID;\n CTRL_OUT CO;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n CTRL_PID();\n\n // Execute function block\n void operator()();\n\n virtual ~CTRL_PID() = default;\n};\n\nclass FT_PI {\npublic:\n // Inputs\n IEC_REAL IN;\n IEC_REAL KP;\n IEC_REAL KI;\n IEC_REAL ILIM_L;\n IEC_REAL ILIM_H;\n IEC_BOOL IEN;\n IEC_BOOL RST;\n // Outputs\n IEC_REAL Y;\n IEC_BOOL LIM;\n // Local variables\n FT_INT INTEG;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FT_PI();\n\n // Execute function block\n void operator()();\n\n virtual ~FT_PI() = default;\n};\n\nclass FT_PID {\npublic:\n // Inputs\n IEC_REAL IN;\n IEC_REAL KP;\n IEC_REAL TN;\n IEC_REAL TV;\n IEC_REAL ILIM_L;\n IEC_REAL ILIM_H;\n IEC_BOOL IEN;\n IEC_BOOL RST;\n // Outputs\n IEC_REAL Y;\n IEC_BOOL LIM;\n // Local variables\n FT_INT INTEG;\n FT_DERIV DIFF;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FT_PID();\n\n // Execute function block\n void operator()();\n\n virtual ~FT_PID() = default;\n};\n\nclass FT_PIW {\npublic:\n // Inputs\n IEC_REAL IN;\n IEC_REAL KP;\n IEC_REAL KI;\n IEC_REAL LIM_L;\n IEC_REAL LIM_H;\n IEC_BOOL RST;\n // Outputs\n IEC_REAL Y;\n IEC_BOOL LIM;\n // Local variables\n FT_INT INTEG;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FT_PIW();\n\n // Execute function block\n void operator()();\n\n virtual ~FT_PIW() = default;\n};\n\nclass CTRL_PWM {\npublic:\n // Inputs\n IEC_REAL CI;\n IEC_REAL MAN_IN;\n IEC_BOOL MANUAL;\n IEC_REAL F;\n // Outputs\n IEC_BOOL Q;\n // Local variables\n PWM_DC PW;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n CTRL_PWM();\n\n // Execute function block\n void operator()();\n\n virtual ~CTRL_PWM() = default;\n};\n\nclass FADE {\npublic:\n // Inputs\n IEC_REAL IN1;\n IEC_REAL IN2;\n IEC_BOOL F;\n IEC_TIME TF;\n IEC_BOOL RST;\n // Outputs\n IEC_REAL Y;\n // Local variables\n RMP_W RMX;\n\n // Implicit IEC 61131-3 ENO pin (mirrors EN)\n IEC_BOOL ENO = true;\n\n // Constructor\n FADE();\n\n // Execute function block\n void operator()();\n\n virtual ~FADE() = default;\n};\n\nIEC_REAL ACOSH(IEC_REAL X);\nIEC_REAL ACOTH(IEC_REAL X);\nIEC_REAL AGDF(IEC_REAL X);\nIEC_REAL AIN(IEC_DWORD IN, IEC_BYTE BITS, IEC_BYTE SIGN, IEC_REAL LOW, IEC_REAL HIGH);\nIEC_DWORD AOUT(IEC_REAL IN, IEC_BYTE BITS, IEC_BYTE SIGN, IEC_REAL LOW, IEC_REAL HIGH);\nIEC_DWORD AOUT1(IEC_REAL IN, IEC_INT BIT_0, IEC_INT BIT_N, IEC_INT SIGN, IEC_REAL LOW, IEC_REAL HIGH);\nIEC_REAL ARRAY_AVG(IEC_Ptr> PT, IEC_UINT SIZE);\nIEC_REAL ARRAY_GAV(IEC_Ptr> PT, IEC_UINT SIZE);\nIEC_REAL ARRAY_HAV(IEC_Ptr> PT, IEC_UINT SIZE);\nIEC_REAL ARRAY_MAX(IEC_Ptr> PT, IEC_UINT SIZE);\nIEC_REAL ARRAY_MIN(IEC_Ptr> PT, IEC_UINT SIZE);\nIEC_REAL ARRAY_SDV(IEC_Ptr> PT, IEC_UINT SIZE);\nIEC_REAL ARRAY_SPR(IEC_Ptr> PT, IEC_UINT SIZE);\nIEC_REAL ARRAY_SUM(IEC_Ptr> PT, IEC_UINT SIZE);\nIEC_REAL ARRAY_TREND(IEC_Ptr> PT, IEC_UINT SIZE);\nIEC_REAL ARRAY_VAR(IEC_Ptr> PT, IEC_UINT SIZE);\nIEC_REAL ASINH(IEC_REAL X);\nIEC_REAL ATAN2(IEC_REAL Y, IEC_REAL X);\nIEC_REAL ATANH(IEC_REAL X);\nIEC_BYTE BAND_B(IEC_BYTE X, IEC_BYTE B);\nIEC_INT BCDC_TO_INT(IEC_BYTE IN);\nIEC_REAL BETA(IEC_REAL X, IEC_REAL Y);\nIEC_REAL BFT_TO_MS(IEC_INT BFT);\nIEC_DINT BINOM(IEC_INT N, IEC_INT K);\nIEC_BYTE BIN_TO_BYTE(IECStringVar<12> BIN);\nIEC_DWORD BIN_TO_DWORD(IECStringVar<40> BIN);\nIEC_INT BIT_COUNT(IEC_DWORD IN);\nIEC_BYTE BIT_LOAD_B(IEC_BYTE IN, IEC_BOOL VAL, IEC_INT POS);\nIEC_BYTE BIT_LOAD_B2(IEC_BYTE I, IEC_BOOL D, IEC_INT P, IEC_INT N);\nIEC_DWORD BIT_LOAD_DW(IEC_DWORD IN, IEC_BOOL VAL, IEC_INT POS);\nIEC_DWORD BIT_LOAD_DW2(IEC_DWORD I, IEC_BOOL D, IEC_INT P, IEC_INT N);\nIEC_WORD BIT_LOAD_W(IEC_WORD IN, IEC_BOOL VAL, IEC_INT POS);\nIEC_WORD BIT_LOAD_W2(IEC_WORD I, IEC_BOOL D, IEC_INT P, IEC_INT N);\nIEC_BOOL BIT_OF_DWORD(IEC_DWORD IN, IEC_INT N);\nIEC_BYTE BIT_TOGGLE_B(IEC_BYTE IN, IEC_INT POS);\nIEC_DWORD BIT_TOGGLE_DW(IEC_DWORD IN, IEC_INT POS);\nIEC_WORD BIT_TOGGLE_W(IEC_WORD IN, IEC_INT POS);\nIEC_INT BUFFER_COMP(IEC_Ptr> PT1, IEC_INT SIZE1, IEC_Ptr> PT2, IEC_INT SIZE2, IEC_INT START);\nIEC_INT BUFFER_SEARCH(IEC_Ptr> PT, IEC_INT SIZE, IECStringVar STR, IEC_INT POS, IEC_BOOL IGN);\nIECStringVar BUFFER_TO_STRING(IEC_Ptr> PT, IEC_UINT SIZE, IEC_UINT START, IEC_UINT STOP);\nIEC_BYTE BYTE_OF_BIT(IEC_BOOL B0, IEC_BOOL B1, IEC_BOOL B2, IEC_BOOL B3, IEC_BOOL B4, IEC_BOOL B5, IEC_BOOL B6, IEC_BOOL B7);\nIEC_BYTE BYTE_OF_DWORD(IEC_DWORD IN, IEC_BYTE N);\nIEC_BYTE BYTE_TO_GRAY(IEC_BYTE IN);\nIEC_REAL BYTE_TO_RANGE(IEC_BYTE X, IEC_REAL LOW, IEC_REAL HIGH);\nIECStringVar<8> BYTE_TO_STRB(IEC_BYTE IN);\nIECStringVar<2> BYTE_TO_STRH(IEC_BYTE IN);\nIEC_REAL CABS(COMPLEX X);\nCOMPLEX CACOS(COMPLEX X);\nCOMPLEX CACOSH(COMPLEX X);\nCOMPLEX CADD(COMPLEX X, COMPLEX Y);\nIECStringVar CAPITALIZE(IECStringVar STR);\nIEC_REAL CARG(COMPLEX X);\nCOMPLEX CASIN(COMPLEX X);\nCOMPLEX CASINH(COMPLEX X);\nCOMPLEX CATAN(COMPLEX X);\nCOMPLEX CATANH(COMPLEX X);\nIEC_REAL CAUCHY(IEC_REAL X, IEC_REAL T, IEC_REAL U);\nIEC_REAL CAUCHYCD(IEC_REAL X, IEC_REAL T, IEC_REAL U);\nCOMPLEX CCON(COMPLEX X);\nCOMPLEX CCOS(COMPLEX X);\nCOMPLEX CCOSH(COMPLEX X);\nCOMPLEX CDIV(COMPLEX X, COMPLEX Y);\nIEC_INT CEIL(IEC_REAL X);\nIEC_DINT CEIL2(IEC_REAL X);\nCOMPLEX CEXP(COMPLEX X);\nIEC_BYTE CHARCODE(IECStringVar<10> STR);\nIECStringVar<10> CHARNAME(IEC_BYTE C);\nIEC_BOOL CHECK_PARITY(IEC_DWORD IN, IEC_BOOL P);\nIEC_BYTE CHK_REAL(IEC_REAL X);\nIECStringVar<1> CHR_TO_STRING(IEC_BYTE C);\nCOMPLEX CINV(COMPLEX X);\nIEC_REAL CIRCLE_A(IEC_REAL RX, IEC_REAL AX);\nIEC_REAL CIRCLE_C(IEC_REAL RX, IEC_REAL AX);\nIEC_REAL CIRCLE_SEG(IEC_REAL RX, IEC_REAL HX);\nIECStringVar CLEAN(IECStringVar IN, IECStringVar<80> CX);\nCOMPLEX CLOG(COMPLEX X);\nIEC_BOOL CMP(IEC_REAL X, IEC_REAL Y, IEC_INT N);\nCOMPLEX CMUL(COMPLEX X, COMPLEX Y);\nIEC_BYTE CODE(IECStringVar STR, IEC_INT POS);\nIEC_REAL CONE_V(IEC_REAL RX, IEC_REAL HX);\nIEC_REAL COSH(IEC_REAL X);\nIEC_REAL COTH(IEC_REAL X);\nIEC_INT COUNT_CHAR(IECStringVar STR, IEC_BYTE CHR);\nIEC_INT COUNT_SUBSTRING(IEC_STRING SEARCH, IEC_STRING STR);\nCOMPLEX CPOL(IEC_REAL L, IEC_REAL A);\nCOMPLEX CPOW(COMPLEX X, COMPLEX Y);\nIEC_DWORD CRC_GEN(IEC_Ptr> PT, IEC_INT SIZE, IEC_INT PL, IEC_DWORD PN, IEC_DWORD INIT, IEC_BOOL REV_IN, IEC_BOOL REV_OUT, IEC_DWORD XOR_OUT);\nCOMPLEX CSET(IEC_REAL RE, IEC_REAL IM);\nCOMPLEX CSIN(COMPLEX X);\nCOMPLEX CSINH(COMPLEX X);\nCOMPLEX CSQRT(COMPLEX X);\nCOMPLEX CSUB(COMPLEX X, COMPLEX Y);\nCOMPLEX CTAN(COMPLEX X);\nCOMPLEX CTANH(COMPLEX X);\nIEC_REAL CTRL_IN(IEC_REAL SET_POINT, IEC_REAL ACTUAL, IEC_REAL NOISE);\nIEC_REAL C_TO_F(IEC_REAL CELSIUS);\nIEC_REAL C_TO_K(IEC_REAL CELSIUS);\nIEC_DATE DATE_ADD(IEC_DATE IDATE, IEC_INT D, IEC_INT W, IEC_INT M, IEC_INT Y);\nIEC_DINT DAYS_DELTA(IEC_DATE DATE_1, IEC_DATE DATE_2);\nIEC_INT DAYS_IN_MONTH(IEC_DATE IDATE);\nIEC_INT DAYS_IN_YEAR(IEC_DATE IDATE);\nIEC_DINT DAY_OF_DATE(IEC_DATE IDATE);\nIEC_INT DAY_OF_MONTH(IEC_DATE IDATE);\nIEC_INT DAY_OF_WEEK(IEC_DATE IDATE);\nIEC_INT DAY_OF_YEAR(IEC_DATE IDATE);\nIEC_TIME DAY_TO_TIME(IEC_REAL IN);\nIEC_REAL DEAD_BAND(IEC_REAL X, IEC_REAL L);\nIEC_REAL DEAD_ZONE(IEC_REAL X, IEC_REAL L);\nIEC_INT DEC1(IEC_INT X, IEC_INT N);\nIEC_BYTE DEC_TO_BYTE(IECStringVar<10> DEC);\nIEC_DWORD DEC_TO_DWORD(IECStringVar<20> DEC);\nIEC_INT DEC_TO_INT(IECStringVar<10> DEC);\nIEC_REAL DEG(IEC_REAL RAD);\nIECStringVar<3> DEG_TO_DIR(IEC_INT DEG, IEC_INT N, IEC_INT L);\nIECStringVar DEL_CHARS(IECStringVar IN, IECStringVar<80> CX);\nIEC_BOOL DIFFER(IEC_REAL IN1, IEC_REAL IN2, IEC_REAL X);\nIEC_INT DIR_TO_DEG(IECStringVar<3> DIR, IEC_INT L);\nIEC_BOOL DST(IEC_DT UTC);\nSDT DT2_TO_SDT(IEC_DATE DI, IEC_TOD TI);\nSDT DT_TO_SDT(IEC_DT DTI);\nIEC_STRING DT_TO_STRF(IEC_DT DTI, IEC_INT MS, IEC_STRING FMT, IEC_INT LANG);\nIEC_DWORD DWORD_OF_BYTE(IEC_BYTE B3, IEC_BYTE B2, IEC_BYTE B1, IEC_BYTE B0);\nIEC_DWORD DWORD_OF_WORD(IEC_WORD W1, IEC_WORD W0);\nIECStringVar<32> DWORD_TO_STRB(IEC_DWORD IN);\nIECStringVar<20> DWORD_TO_STRF(IEC_DWORD IN, IEC_INT N);\nIECStringVar<8> DWORD_TO_STRH(IEC_DWORD IN);\nIEC_REAL DW_TO_REAL(IEC_DWORD X);\nIEC_DINT D_TRUNC(IEC_REAL X);\nIEC_DATE EASTER(IEC_INT YEAR);\nIEC_REAL ELLIPSE_A(IEC_REAL R1, IEC_REAL R2);\nIEC_REAL ELLIPSE_C(IEC_REAL R1, IEC_REAL R2);\nIEC_REAL ERF(IEC_REAL X);\nIEC_REAL ERFC(IEC_REAL X);\nIEC_BOOL EVEN(IEC_DINT IN);\nIECStringVar EXEC(IECStringVar STR);\nIEC_REAL EXP10(IEC_REAL X);\nIEC_REAL EXPN(IEC_REAL X, IEC_INT N);\nIEC_DINT FACT(IEC_INT X);\nIEC_DINT FIB(IEC_INT X);\nIECStringVar FILL(IEC_BYTE C, IEC_INT L);\nIEC_INT FINDB(IECStringVar STR1, IECStringVar STR2);\nIEC_INT FINDB_NONUM(IECStringVar STR);\nIEC_INT FINDB_NUM(IECStringVar STR);\nIEC_INT FINDP(IECStringVar STR, IECStringVar SRC, IEC_INT POS);\nIEC_INT FIND_CHAR(IECStringVar STR, IEC_INT POS);\nIEC_INT FIND_CTRL(IECStringVar STR, IEC_INT POS);\nIEC_INT FIND_NONUM(IECStringVar STR, IEC_INT POS);\nIEC_INT FIND_NUM(IECStringVar STR, IEC_INT POS);\nIECStringVar FIX(IECStringVar STR, IEC_INT L, IEC_BYTE C, IEC_INT M);\nIEC_REAL FLOAT_TO_REAL(IECStringVar<20> FLT);\nIEC_INT FLOOR(IEC_REAL X);\nIEC_DINT FLOOR2(IEC_REAL X);\nIEC_REAL FRACT(IEC_REAL X);\nIEC_BYTE FRMP_B(IEC_BYTE START, IEC_BOOL DIR, IEC_TIME TD, IEC_TIME TR);\nIEC_BYTE FSTRING_TO_BYTE(IECStringVar<12> IN);\nIEC_DT FSTRING_TO_DT(IECStringVar<60> SDT, IECStringVar<60> FMT);\nIEC_DWORD FSTRING_TO_DWORD(IECStringVar<40> IN);\nIEC_INT FSTRING_TO_MONTH(IECStringVar<20> MTH, IEC_INT LANG);\nIEC_BYTE FSTRING_TO_WEEK(IECStringVar<60> WEEK, IEC_INT LANG);\nIEC_INT FSTRING_TO_WEEKDAY(IECStringVar<20> WDAY, IEC_INT LANG);\nIEC_REAL F_LIN(IEC_REAL X, IEC_REAL A, IEC_REAL B);\nIEC_REAL F_LIN2(IEC_REAL X, IEC_REAL X1, IEC_REAL Y1, IEC_REAL X2, IEC_REAL Y2);\nIEC_REAL F_POLY(IEC_REAL X, Array1D C);\nIEC_REAL F_POWER(IEC_REAL A, IEC_REAL X, IEC_REAL N);\nIEC_REAL F_QUAD(IEC_REAL X, IEC_REAL A, IEC_REAL B, IEC_REAL C);\nIEC_REAL F_TO_C(IEC_REAL FAHRENHEIT);\nIEC_REAL F_TO_OM(IEC_REAL F);\nIEC_TIME F_TO_PT(IEC_REAL F);\nIEC_REAL GAMMA(IEC_REAL X);\nIEC_REAL GAUSS(IEC_REAL X, IEC_REAL U, IEC_REAL SI);\nIEC_REAL GAUSSCD(IEC_REAL X, IEC_REAL U, IEC_REAL SI);\nIEC_INT GCD(IEC_DINT A, IEC_DINT B);\nIEC_REAL GDF(IEC_REAL X);\nIEC_REAL GEO_TO_DEG(IEC_INT D, IEC_INT M, IEC_REAL SEC);\nIEC_REAL GOLD(IEC_REAL X);\nIEC_BYTE GRAY_TO_BYTE(IEC_BYTE IN);\nIEC_BYTE HEX_TO_BYTE(IECStringVar<5> HEX);\nIEC_DWORD HEX_TO_DWORD(IECStringVar<20> HEX);\nIEC_INT HOUR(IEC_TOD ITOD);\nIEC_INT HOUR_OF_DT(IEC_DT XDT);\nIEC_TIME HOUR_TO_TIME(IEC_REAL IN);\nIEC_TOD HOUR_TO_TOD(IEC_REAL IN);\nIEC_REAL HYPOT(IEC_REAL X, IEC_REAL Y);\nIEC_INT INC(IEC_INT X, IEC_INT D, IEC_INT M);\nIEC_INT INC1(IEC_INT X, IEC_INT N);\nIEC_INT INC2(IEC_INT X, IEC_INT D, IEC_INT L, IEC_INT U);\nIEC_BYTE INT_TO_BCDC(IEC_INT IN);\nIEC_REAL INV(IEC_REAL X);\nIEC_BOOL ISC_ALPHA(IEC_BYTE IN);\nIEC_BOOL ISC_CTRL(IEC_BYTE IN);\nIEC_BOOL ISC_HEX(IEC_BYTE IN);\nIEC_BOOL ISC_LOWER(IEC_BYTE IN);\nIEC_BOOL ISC_NUM(IEC_BYTE IN);\nIEC_BOOL ISC_UPPER(IEC_BYTE IN);\nIEC_BOOL IS_ALNUM(IECStringVar STR);\nIEC_BOOL IS_ALPHA(IECStringVar STR);\nIEC_BOOL IS_CC(IECStringVar STR, IECStringVar CMP);\nIEC_BOOL IS_CTRL(IECStringVar STR);\nIEC_BOOL IS_HEX(IECStringVar STR);\nIEC_BOOL IS_LOWER(IECStringVar STR);\nIEC_BOOL IS_NCC(IECStringVar STR, IECStringVar CMP);\nIEC_BOOL IS_NUM(IECStringVar STR);\nIEC_BOOL IS_SORTED(IEC_Ptr> PT, IEC_UINT SIZE);\nIEC_BOOL IS_UPPER(IECStringVar STR);\nIEC_REAL JD2000(IEC_DT DTI);\nIEC_REAL KMH_TO_MS(IEC_REAL KMH);\nIEC_REAL K_TO_C(IEC_REAL KELVIN);\nIEC_REAL LAMBERT_W(IEC_REAL X);\nIEC_REAL LANGEVIN(IEC_REAL X);\nIEC_BOOL LEAP_DAY(IEC_DATE IDATE);\nIEC_BOOL LEAP_OF_DATE(IEC_DATE IDATE);\nIEC_BOOL LEAP_YEAR(IEC_INT YR);\nIEC_REAL LINEAR_INT(IEC_REAL X, Array2D XY, IEC_INT PTS);\nIEC_BOOL LIST_ADD(IEC_BYTE SEP, IECStringVar INS, IEC_STRING& LIST);\nIEC_BOOL LIST_CLEAN(IEC_BYTE SEP, IEC_STRING& LIST);\nIECStringVar LIST_GET(IEC_BYTE SEP, IEC_INT POS, IEC_STRING& LIST);\nIEC_BOOL LIST_INSERT(IEC_BYTE SEP, IEC_INT POS, IECStringVar INS, IEC_STRING& LIST);\nIEC_INT LIST_LEN(IEC_BYTE SEP, IEC_STRING& LIST);\nIECStringVar LIST_RETRIEVE(IEC_BYTE SEP, IEC_INT POS, IEC_STRING& LIST);\nIECStringVar LIST_RETRIEVE_LAST(IEC_BYTE SEP, IEC_STRING& LIST);\nIECStringVar LOWERCASE(IECStringVar STR);\nIEC_DT LTIME_TO_UTC(IEC_DT LTIME, IEC_BOOL DST, IEC_INT TIME_ZONE_OFFSET);\nIEC_BOOL MANUAL(IEC_BOOL IN, IEC_BOOL ON, IEC_BOOL OFF);\nIEC_REAL MAX3(IEC_REAL IN1, IEC_REAL IN2, IEC_REAL IN3);\nIEC_REAL MID3(IEC_REAL IN1, IEC_REAL IN2, IEC_REAL IN3);\nIEC_REAL MIN3(IEC_REAL IN1, IEC_REAL IN2, IEC_REAL IN3);\nIEC_INT MINUTE(IEC_TOD ITOD);\nIEC_INT MINUTE_OF_DT(IEC_DT XDT);\nIEC_TIME MINUTE_TO_TIME(IEC_REAL IN);\nIECStringVar MIRROR(IECStringVar STR);\nIEC_REAL MIX(IEC_REAL A, IEC_REAL B, IEC_REAL M);\nIEC_REAL MODR(IEC_REAL IN, IEC_REAL DIVI);\nIEC_DATE MONTH_BEGIN(IEC_DATE IDATE);\nIEC_DATE MONTH_END(IEC_DATE IDATE);\nIEC_INT MONTH_OF_DATE(IEC_DATE IDATE);\nIECStringVar<10> MONTH_TO_STRING(IEC_INT MTH, IEC_INT LANG, IEC_INT LX);\nIEC_INT MS_TO_BFT(IEC_REAL MS);\nIEC_REAL MS_TO_KMH(IEC_REAL MS);\nIEC_TIME MULTIME(IEC_TIME T, IEC_REAL M);\nIEC_REAL MULTI_IN(IEC_REAL IN_1, IEC_REAL IN_2, IEC_REAL IN_3, IEC_REAL DEFAULT, IEC_REAL IN_MIN, IEC_REAL IN_MAX, IEC_BYTE MODE);\nIEC_REAL MUL_ADD(IEC_REAL X, IEC_REAL K, IEC_REAL O);\nIEC_BOOL MUX_2(IEC_BOOL D0, IEC_BOOL D1, IEC_BOOL A0);\nIEC_BOOL MUX_4(IEC_BOOL D0, IEC_BOOL D1, IEC_BOOL D2, IEC_BOOL D3, IEC_BOOL A0, IEC_BOOL A1);\nIEC_REAL MUX_R2(IEC_REAL IN0, IEC_REAL IN1, IEC_BOOL A);\nIEC_REAL MUX_R4(IEC_REAL IN0, IEC_REAL IN1, IEC_REAL IN2, IEC_REAL IN3, IEC_BOOL A0, IEC_BOOL A1);\nIEC_REAL NEGX(IEC_REAL X);\nIEC_BYTE OCT_TO_BYTE(IECStringVar<10> OCT);\nIEC_DWORD OCT_TO_DWORD(IECStringVar<20> OCT);\nIEC_REAL OFFSET(IEC_REAL X, IEC_BOOL O1, IEC_BOOL O2, IEC_BOOL O3, IEC_BOOL O4, IEC_BOOL D, IEC_REAL OFFSET_1, IEC_REAL OFFSET_2, IEC_REAL OFFSET_3, IEC_REAL OFFSET_4, IEC_REAL DEFAULT);\nIEC_REAL OFFSET2(IEC_REAL X, IEC_BOOL O1, IEC_BOOL O2, IEC_BOOL O3, IEC_BOOL O4, IEC_BOOL D, IEC_REAL OFFSET_1, IEC_REAL OFFSET_2, IEC_REAL OFFSET_3, IEC_REAL OFFSET_4, IEC_REAL DEFAULT);\nIEC_REAL OM_TO_F(IEC_REAL OM);\nIEC_DWORD OSCAT_VERSION(IEC_BOOL IN);\nIEC_REAL OVERRIDE(IEC_REAL X1, IEC_REAL X2, IEC_REAL X3, IEC_BOOL E1, IEC_BOOL E2, IEC_BOOL E3);\nIEC_BOOL PARITY(IEC_DWORD IN);\nIEC_BOOL PERIOD(IEC_DATE D1, IEC_DATE DX, IEC_DATE D2);\nIEC_BOOL PERIOD2(Array2D DP, IEC_DATE DX);\nIEC_REAL POLYNOM_INT(IEC_REAL X, Array2D XY, IEC_INT PTS);\nIEC_REAL PT_TO_F(IEC_TIME PT);\nREAL2 R2_ABS(REAL2 X);\nREAL2 R2_ADD(REAL2 X, IEC_REAL Y);\nREAL2 R2_ADD2(REAL2 X, REAL2 Y);\nREAL2 R2_MUL(REAL2 X, IEC_REAL Y);\nREAL2 R2_SET(IEC_REAL X);\nIEC_REAL RAD(IEC_REAL DEG);\nIEC_BYTE RANGE_TO_BYTE(IEC_REAL X, IEC_REAL LOW, IEC_REAL HIGH);\nIEC_WORD RANGE_TO_WORD(IEC_REAL X, IEC_REAL LOW, IEC_REAL HIGH);\nIEC_REAL RDM(IEC_REAL LAST);\nIEC_INT RDM2(IEC_INT LAST, IEC_INT LOW, IEC_INT HIGH);\nIEC_DWORD RDMDW(IEC_DWORD LAST);\nIEC_DWORD REAL_TO_DW(IEC_REAL X);\nFRACTION REAL_TO_FRAC(IEC_REAL X, IEC_INT N);\nIECStringVar<20> REAL_TO_STRF(IEC_REAL IN, IEC_INT N, IECStringVar<1> D);\nIEC_DWORD REFLECT(IEC_DWORD D, IEC_INT L);\nIEC_REAL REFRACTION(IEC_REAL ELEV);\nIECStringVar REPLACE_ALL(IECStringVar STR, IECStringVar SRC, IECStringVar REP);\nIECStringVar REPLACE_CHARS(IECStringVar STR, IEC_STRING SRC, IEC_STRING REP);\nIECStringVar REPLACE_UML(IECStringVar STR);\nIEC_REAL RES_NI(IEC_REAL T, IEC_REAL R0);\nIEC_REAL RES_NTC(IEC_REAL T, IEC_REAL RN, IEC_REAL B);\nIEC_REAL RES_PT(IEC_REAL T, IEC_REAL R0);\nIEC_REAL RES_SI(IEC_REAL T, IEC_REAL RS, IEC_REAL TS);\nIEC_BYTE REVERSE(IEC_BYTE IN);\nIEC_REAL RND(IEC_REAL X, IEC_INT N);\nIEC_REAL ROUND(IEC_REAL IN, IEC_INT N);\nIEC_REAL SCALE(IEC_REAL X, IEC_REAL K, IEC_REAL O, IEC_REAL MX, IEC_REAL MN);\nIEC_REAL SCALE_B(IEC_BYTE X, IEC_BYTE I_LO, IEC_BYTE I_HI, IEC_REAL O_LO, IEC_REAL O_HI);\nIEC_REAL SCALE_B2(IEC_BYTE IN1, IEC_BYTE IN2, IEC_REAL K, IEC_REAL O, IEC_REAL IN1_MIN, IEC_REAL IN1_MAX, IEC_REAL IN2_MIN, IEC_REAL IN2_MAX);\nIEC_REAL SCALE_B4(IEC_BYTE IN1, IEC_BYTE IN2, IEC_BYTE IN3, IEC_BYTE IN4, IEC_REAL K, IEC_REAL O, IEC_REAL IN1_MIN, IEC_REAL IN1_MAX, IEC_REAL IN2_MIN, IEC_REAL IN2_MAX, IEC_REAL IN3_MIN, IEC_REAL IN3_MAX, IEC_REAL IN4_MIN, IEC_REAL IN4_MAX);\nIEC_REAL SCALE_B8(IEC_BYTE IN1, IEC_BYTE IN2, IEC_BYTE IN3, IEC_BYTE IN4, IEC_BYTE IN5, IEC_BYTE IN6, IEC_BYTE IN7, IEC_BYTE IN8, IEC_REAL K, IEC_REAL O, IEC_REAL IN1_MIN, IEC_REAL IN1_MAX, IEC_REAL IN2_MIN, IEC_REAL IN2_MAX, IEC_REAL IN3_MIN, IEC_REAL IN3_MAX, IEC_REAL IN4_MIN, IEC_REAL IN4_MAX, IEC_REAL IN5_MIN, IEC_REAL IN5_MAX, IEC_REAL IN6_MIN, IEC_REAL IN6_MAX, IEC_REAL IN7_MIN, IEC_REAL IN7_MAX, IEC_REAL IN8_MIN, IEC_REAL IN8_MAX);\nIEC_REAL SCALE_D(IEC_DWORD X, IEC_DWORD I_LO, IEC_DWORD I_HI, IEC_REAL O_LO, IEC_REAL O_HI);\nIEC_REAL SCALE_R(IEC_REAL X, IEC_REAL I_LO, IEC_REAL I_HI, IEC_REAL O_LO, IEC_REAL O_HI);\nIEC_REAL SCALE_X2(IEC_BOOL IN1, IEC_BOOL IN2, IEC_REAL K, IEC_REAL O, IEC_REAL IN1_MIN, IEC_REAL IN1_MAX, IEC_REAL IN2_MIN, IEC_REAL IN2_MAX);\nIEC_REAL SCALE_X4(IEC_BOOL IN1, IEC_BOOL IN2, IEC_BOOL IN3, IEC_BOOL IN4, IEC_REAL K, IEC_REAL O, IEC_REAL IN1_MIN, IEC_REAL IN1_MAX, IEC_REAL IN2_MIN, IEC_REAL IN2_MAX, IEC_REAL IN3_MIN, IEC_REAL IN3_MAX, IEC_REAL IN4_MIN, IEC_REAL IN4_MAX);\nIEC_REAL SCALE_X8(IEC_BOOL IN1, IEC_BOOL IN2, IEC_BOOL IN3, IEC_BOOL IN4, IEC_BOOL IN5, IEC_BOOL IN6, IEC_BOOL IN7, IEC_BOOL IN8, IEC_REAL K, IEC_REAL O, IEC_REAL IN1_MIN, IEC_REAL IN1_MAX, IEC_REAL IN2_MIN, IEC_REAL IN2_MAX, IEC_REAL IN3_MIN, IEC_REAL IN3_MAX, IEC_REAL IN4_MIN, IEC_REAL IN4_MAX, IEC_REAL IN5_MIN, IEC_REAL IN5_MAX, IEC_REAL IN6_MIN, IEC_REAL IN6_MAX, IEC_REAL IN7_MIN, IEC_REAL IN7_MAX, IEC_REAL IN8_MIN, IEC_REAL IN8_MAX);\nIEC_DATE SDT_TO_DATE(SDT DTI);\nIEC_DT SDT_TO_DT(SDT DTI);\nIEC_TOD SDT_TO_TOD(SDT DTI);\nIEC_REAL SECOND(IEC_TOD ITOD);\nIEC_INT SECOND_OF_DT(IEC_DT XDT);\nIEC_TIME SECOND_TO_TIME(IEC_REAL IN);\nIEC_REAL SENSOR_INT(IEC_REAL VOLTAGE, IEC_REAL CURRENT, IEC_REAL RP, IEC_REAL RS);\nIEC_DATE SET_DATE(IEC_INT YEAR, IEC_INT MONTH, IEC_INT DAY);\nIEC_DT SET_DT(IEC_INT YEAR, IEC_INT MONTH, IEC_INT DAY, IEC_INT HOUR, IEC_INT MINUTE, IEC_INT SECOND);\nIEC_TOD SET_TOD(IEC_INT HOUR, IEC_INT MINUTE, IEC_REAL SECOND);\nIEC_INT SGN(IEC_REAL X);\nIEC_DWORD SHL1(IEC_DWORD IN, IEC_INT N);\nIEC_DWORD SHR1(IEC_DWORD IN, IEC_INT N);\nIEC_REAL SIGMOID(IEC_REAL X);\nIEC_BOOL SIGN_I(IEC_DINT IN);\nIEC_BOOL SIGN_R(IEC_REAL IN);\nIEC_REAL SINC(IEC_REAL X);\nIEC_REAL SINH(IEC_REAL X);\nIEC_REAL SPHERE_V(IEC_REAL RX);\nIEC_REAL SQRTN(IEC_REAL X, IEC_INT N);\nIEC_REAL STAIR(IEC_REAL X, IEC_REAL D);\nESR_DATA STATUS_TO_ESR(IEC_BYTE STATUS, IECStringVar<10> ADRESS, IEC_DT DT_IN, IEC_TIME TS);\nIEC_TOD SUN_MIDDAY(IEC_REAL LON, IEC_DATE UTC);\nIEC_WORD SWAP_BYTE(IEC_WORD IN);\nIEC_DWORD SWAP_BYTE2(IEC_DWORD IN);\nIEC_REAL TANC(IEC_REAL X);\nIEC_REAL TANH(IEC_REAL X);\nIEC_REAL TEMP_NI(IEC_REAL RES, IEC_REAL R0);\nIEC_REAL TEMP_NTC(IEC_REAL RES, IEC_REAL RN, IEC_REAL B);\nIEC_REAL TEMP_PT(IEC_REAL RES, IEC_REAL R0);\nIEC_REAL TEMP_SI(IEC_REAL RES, IEC_REAL RS, IEC_REAL TS);\nIEC_BOOL TIMECHECK(IEC_TOD TD, IEC_TOD START, IEC_TOD STOP);\nIEC_BYTE TO_LOWER(IEC_BYTE IN);\nIECStringVar<2> TO_UML(IEC_BYTE IN);\nIEC_BYTE TO_UPPER(IEC_BYTE IN);\nIEC_REAL TRIANGLE_A(IEC_REAL S1, IEC_REAL A, IEC_REAL S2, IEC_REAL S3);\nIECStringVar TRIM(IECStringVar STR);\nIECStringVar TRIM1(IECStringVar STR);\nIECStringVar TRIME(IECStringVar STR);\nIEC_DWORD T_PLC_MS();\nIEC_DWORD T_PLC_US();\nIECStringVar UPPERCASE(IECStringVar STR);\nIEC_DT UTC_TO_LTIME(IEC_DT UTC, IEC_BOOL DST_ENABLE, IEC_INT TIME_ZONE_OFFSET);\nIEC_REAL V3_ABS(VECTOR_3 A);\nVECTOR_3 V3_ADD(VECTOR_3 A, VECTOR_3 B);\nIEC_REAL V3_ANG(VECTOR_3 A, VECTOR_3 B);\nIEC_REAL V3_DPRO(VECTOR_3 A, VECTOR_3 B);\nVECTOR_3 V3_NORM(VECTOR_3 A);\nIEC_BOOL V3_NUL(VECTOR_3 A);\nIEC_BOOL V3_PAR(VECTOR_3 A, VECTOR_3 B);\nVECTOR_3 V3_REV(VECTOR_3 A);\nVECTOR_3 V3_SMUL(VECTOR_3 A, IEC_REAL M);\nVECTOR_3 V3_SUB(VECTOR_3 A, VECTOR_3 B);\nIEC_REAL V3_XANG(VECTOR_3 A);\nVECTOR_3 V3_XPRO(VECTOR_3 A, VECTOR_3 B);\nIEC_REAL V3_YANG(VECTOR_3 A);\nIEC_REAL V3_ZANG(VECTOR_3 A);\nIECStringVar<10> WEEKDAY_TO_STRING(IEC_INT WDAY, IEC_INT LANG, IEC_INT LX);\nIEC_BOOL WINDOW(IEC_REAL LOW, IEC_REAL IN, IEC_REAL HIGH);\nIEC_BOOL WINDOW2(IEC_REAL LOW, IEC_REAL IN, IEC_REAL HIGH);\nIEC_WORD WORD_OF_BYTE(IEC_BYTE B1, IEC_BYTE B0);\nIEC_WORD WORD_OF_DWORD(IEC_DWORD IN, IEC_BYTE N);\nIEC_REAL WORD_TO_RANGE(IEC_WORD X, IEC_REAL LOW, IEC_REAL HIGH);\nIEC_INT WORK_WEEK(IEC_DATE IDATE);\nIEC_DATE YEAR_BEGIN(IEC_INT Y);\nIEC_DATE YEAR_END(IEC_INT Y);\nIEC_INT YEAR_OF_DATE(IEC_DATE IDATE);\nIEC_BOOL _ARRAY_ABS(IEC_Ptr> PT, IEC_UINT SIZE);\nIEC_BOOL _ARRAY_ADD(IEC_Ptr> PT, IEC_UINT SIZE, IEC_REAL X);\nIEC_BOOL _ARRAY_INIT(IEC_Ptr> PT, IEC_UINT SIZE, IEC_REAL INIT);\nIEC_REAL _ARRAY_MEDIAN(IEC_Ptr> PT, IEC_UINT SIZE);\nIEC_BOOL _ARRAY_MUL(IEC_Ptr> PT, IEC_UINT SIZE, IEC_REAL X);\nIEC_BOOL _ARRAY_SHUFFLE(IEC_Ptr> PT, IEC_UINT SIZE);\nIEC_BOOL _ARRAY_SORT(IEC_Ptr> PT, IEC_UINT SIZE);\nIEC_BOOL _BUFFER_CLEAR(IEC_Ptr PT, IEC_UINT SIZE);\nIEC_BOOL _BUFFER_INIT(IEC_Ptr PT, IEC_UINT SIZE, IEC_BYTE INIT);\nIEC_INT _BUFFER_INSERT(IECStringVar STR, IEC_INT POS, IEC_Ptr> PT, IEC_UINT SIZE);\nIEC_BOOL _BUFFER_UPPERCASE(IEC_Ptr> PT, IEC_INT SIZE);\nIEC_INT _STRING_TO_BUFFER(IECStringVar STR, IEC_INT POS, IEC_Ptr> PT, IEC_UINT SIZE);", - "cppCode": "\nAIN1::AIN1()\n : SIGN_BIT(255), ERROR_BIT(255), OVERFLOW_BIT(255), BIT_N(31), OUT_MAX(10.0), CODE_MAX(0xFFFFFFFF), OVERFLOW_OUTPUT(10.0)\n{\n // Initialize variables\n}\n\nvoid AIN1::operator()() {\n ERROR = ((((SHR(IN, ERROR_BIT)) & (0x00000001)) == 1)) | (((ERROR_CODE_EN) & (ERROR_CODE == IN)));\n if (ERROR) {\n OUT = ERROR_OUTPUT;\n return;\n }\n TB = SHR(SHL(IN, 31 - BIT_N), 31 - BIT_N + BIT_0);\n OVERFLOW = (((((SHR(IN, OVERFLOW_BIT)) & (0x00000001)) == 1)) | (((OVERFLOW_CODE_EN) & (OVERFLOW_CODE == IN)))) | (((TB < CODE_MIN) | (TB > CODE_MAX)));\n if (OVERFLOW) {\n OUT = OVERFLOW_OUTPUT;\n return;\n }\n SIGN = ((SHR(IN, SIGN_BIT)) & (0x00000001)) == 1;\n OUT = (TO_REAL(TB - CODE_MIN) * (OUT_MAX - OUT_MIN) / TO_REAL(CODE_MAX - CODE_MIN) + OUT_MIN);\n if (SIGN) {\n OUT = OUT * -1.0;\n }\n}\n\n\nALARM_2::ALARM_2() {\n // Initialize variables\n}\n\nvoid ALARM_2::operator()() {\n TMP = X - HYS * 0.5;\n if (TMP > LO_1) {\n Q1_LO = false;\n }\n if (TMP > LO_2) {\n Q2_LO = false;\n }\n if (TMP > HI_1) {\n Q1_HI = true;\n }\n if (TMP > HI_2) {\n Q2_HI = true;\n }\n TMP = TMP + HYS;\n if (TMP < LO_1) {\n Q1_LO = true;\n }\n if (TMP < LO_2) {\n Q2_LO = true;\n }\n if (TMP < HI_1) {\n Q1_HI = false;\n }\n if (TMP < HI_2) {\n Q2_HI = false;\n }\n}\n\n\nASTRO::ASTRO() {\n // Initialize variables\n}\n\nvoid ASTRO::operator()() {\n YAE = AE + M * 6.6845871535e-12 + PC * 206265.0 + LJ * 63240.0;\n YM = YAE * 149597870000.0;\n YPC = YAE * 0.000004848132257;\n YLJ = YAE * 0.000015812776724;\n}\n\n\nA_TRIG::A_TRIG() {\n // Initialize variables\n}\n\nvoid A_TRIG::operator()() {\n D = IN - LAST_IN;\n Q = ABS(D) > RES;\n if (Q) {\n LAST_IN = IN;\n }\n D = IN - LAST_IN;\n}\n\n\nBAR_GRAPH::BAR_GRAPH() {\n // Initialize variables\n}\n\nvoid BAR_GRAPH::operator()() {\n if (!INIT) {\n INIT = true;\n if (LOG_SCALE) {\n TEMP = EXP(LN(TRIGGER_HIGH / TRIGGER_LOW) * 0.16666666666666666);\n T1 = TRIGGER_LOW * TEMP;\n T2 = T1 * TEMP;\n T3 = T2 * TEMP;\n T4 = T3 * TEMP;\n T5 = T4 * TEMP;\n } else {\n TEMP = (TRIGGER_HIGH - TRIGGER_LOW) * 0.142857142;\n T1 = TRIGGER_LOW + TEMP;\n T2 = T1 + TEMP;\n T3 = T2 + TEMP;\n T4 = T3 + TEMP;\n T5 = T4 + TEMP;\n }\n }\n Q1 = false;\n Q2 = false;\n Q3 = false;\n Q4 = false;\n Q5 = false;\n Q6 = false;\n STATUS = 110;\n if (!ALARM_LOW) {\n LOW = false;\n }\n if (!ALARM_HIGH) {\n HIGH = false;\n }\n if (RST) {\n ALARM = false;\n LOW = false;\n HIGH = false;\n }\n if (X < TRIGGER_LOW) {\n LOW = true;\n STATUS = 111;\n if (ALARM_LOW) {\n ALARM = true;\n STATUS = 1;\n }\n } else if (X < T1) {\n Q1 = true;\n } else if (X < T2) {\n Q2 = true;\n } else if (X < T3) {\n Q3 = true;\n } else if (X < T4) {\n Q4 = true;\n } else if (X < T5) {\n Q5 = true;\n } else if (X < TRIGGER_HIGH) {\n Q6 = true;\n } else {\n HIGH = true;\n STATUS = 112;\n if (ALARM_HIGH) {\n ALARM = true;\n STATUS = 2;\n }\n }\n}\n\n\nBYTE_TO_BITS::BYTE_TO_BITS() {\n // Initialize variables\n}\n\nvoid BYTE_TO_BITS::operator()() {\n B0 = ((static_cast(IN) >> 0) & 1);\n B1 = ((static_cast(IN) >> 1) & 1);\n B2 = ((static_cast(IN) >> 2) & 1);\n B3 = ((static_cast(IN) >> 3) & 1);\n B4 = ((static_cast(IN) >> 4) & 1);\n B5 = ((static_cast(IN) >> 5) & 1);\n B6 = ((static_cast(IN) >> 6) & 1);\n B7 = ((static_cast(IN) >> 7) & 1);\n}\n\n\nB_TRIG::B_TRIG() {\n // Initialize variables\n}\n\nvoid B_TRIG::operator()() {\n Q = (CLK) ^ (EDGE);\n EDGE = CLK;\n}\n\n\nCALIBRATE::CALIBRATE()\n : SCALE(1.0)\n{\n // Initialize variables\n}\n\nvoid CALIBRATE::operator()() {\n if (CO) {\n OFFSET = Y_OFFSET - X;\n } else if (CS) {\n SCALE = Y_SCALE / (X + OFFSET);\n }\n Y = (X + OFFSET) * SCALE;\n}\n\n\nCLICK_CNT::CLICK_CNT()\n : CNT(-1)\n{\n // Initialize variables\n}\n\nvoid CLICK_CNT::operator()() {\n Q = false;\n if (((IN) & (!EDGE)) & (!TX.Q)) {\n CNT = 0;\n } else if (((TX.Q) & (!IN)) & (EDGE)) {\n CNT = CNT + 1;\n } else if (!TX.Q) {\n Q = CNT == N;\n CNT = -1;\n }\n EDGE = IN;\n TX.IN = IN;\n TX.PT = TC;\n TX();\n TX.ENO = true;\n}\n\n\nCLICK_DEC::CLICK_DEC()\n : CNT(-1)\n{\n // Initialize variables\n}\n\nvoid CLICK_DEC::operator()() {\n if (IN == false) {\n Q0 = false;\n Q1 = false;\n Q2 = false;\n Q3 = false;\n }\n if (((IN) & (!EDGE)) & (!TX.Q)) {\n CNT = 0;\n } else if (((TX.Q) & (!IN)) & (EDGE)) {\n CNT = CNT + 1;\n } else if (!TX.Q) {\n switch (CNT) {\n case 0:\n Q0 = true;\n break;\n case 1:\n Q1 = true;\n break;\n case 2:\n Q2 = true;\n break;\n case 3:\n Q3 = true;\n break;\n }\n CNT = -1;\n }\n EDGE = IN;\n TX.IN = IN;\n TX.PT = TC;\n TX();\n TX.ENO = true;\n}\n\n\nCLK_DIV::CLK_DIV() {\n // Initialize variables\n}\n\nvoid CLK_DIV::operator()() {\n if (RST) {\n CNT = 0;\n Q0 = 0;\n Q1 = 0;\n Q2 = 0;\n Q3 = 0;\n Q4 = 0;\n Q5 = 0;\n Q6 = 0;\n Q7 = 0;\n } else if (CLK) {\n CNT = CNT + 1;\n Q0 = ((static_cast(CNT) >> 0) & 1);\n Q1 = ((static_cast(CNT) >> 1) & 1);\n Q2 = ((static_cast(CNT) >> 2) & 1);\n Q3 = ((static_cast(CNT) >> 3) & 1);\n Q4 = ((static_cast(CNT) >> 4) & 1);\n Q5 = ((static_cast(CNT) >> 5) & 1);\n Q6 = ((static_cast(CNT) >> 6) & 1);\n Q7 = ((static_cast(CNT) >> 7) & 1);\n }\n}\n\n\nCLK_N::CLK_N() {\n // Initialize variables\n}\n\nvoid CLK_N::operator()() {\n STIME = SHR(T_PLC_MS(), N);\n CLK = ((static_cast(STIME) >> 0) & 1);\n Q = (CLK) ^ (EDGE);\n EDGE = CLK;\n}\n\n\nCLK_PRG::CLK_PRG()\n : PT(10000000LL)\n{\n // Initialize variables\n}\n\nvoid CLK_PRG::operator()() {\n TX = TO_TIME(T_PLC_MS());\n if (!INIT) {\n INIT = true;\n LAST = TX - PT;\n }\n Q = TX - LAST >= PT;\n if (Q) {\n LAST = TX;\n }\n}\n\n\nCLK_PULSE::CLK_PULSE() {\n // Initialize variables\n}\n\nvoid CLK_PULSE::operator()() {\n TX = T_PLC_MS();\n Q = false;\n RUN = CNT < N;\n if ((!INIT) | (RST)) {\n INIT = true;\n CNT = 0;\n TN = TX - TO_DWORD(PT);\n RUN = false;\n } else if ((((CNT < N) | (N == 0))) & (TX - TN >= TO_DWORD(PT))) {\n CNT = CNT + 1;\n Q = true;\n TN = TN + TO_DWORD(PT);\n }\n}\n\n\nCONTROL_SET1::CONTROL_SET1()\n : P_K(0.5), PI_K(0.45), PI_TN(0.83), PID_K(0.6), PID_TN(0.5), PID_TV(0.125)\n{\n // Initialize variables\n}\n\nvoid CONTROL_SET1::operator()() {\n if ((PI) & (PID)) {\n KP = 0.0;\n TN = 0.0;\n TV = 0.0;\n } else if (PID) {\n KP = PID_K * KT;\n TN = PID_TN * TT;\n TV = PID_TV * TT;\n } else if (PI) {\n KP = PI_K * KT;\n TN = PI_TN * TT;\n } else {\n KP = P_K * KT;\n }\n if (TN > 0.0) {\n KI = KP / TN;\n } else {\n KI = 0.0;\n }\n KD = KP * TV;\n}\n\n\nCONTROL_SET2::CONTROL_SET2()\n : P_K(1.0), PI_K(0.9), PI_TN(3.33), PID_K(1.2), PID_TN(2.0), PID_TV(0.5)\n{\n // Initialize variables\n}\n\nvoid CONTROL_SET2::operator()() {\n if ((TU > 0.0) & (KS > 0.0)) {\n TX = TG / TU / KS;\n }\n if ((PI) & (PID)) {\n KP = 0.0;\n TN = 0.0;\n TV = 0.0;\n } else if (PID) {\n KP = PID_K * TX;\n TN = PID_TN * TU;\n TV = PID_TV * TU;\n } else if (PI) {\n KP = PI_K * TX;\n TN = PI_TN * TU;\n } else {\n KP = P_K * TX;\n }\n if (TN > 0.0) {\n KI = KP / TN;\n } else {\n KI = 0.0;\n }\n KD = KP * TV;\n}\n\n\nCOUNT_BR::COUNT_BR()\n : STEP(1), MX(255)\n{\n // Initialize variables\n}\n\nvoid COUNT_BR::operator()() {\n if (RST) {\n CNT = 0;\n } else if (SET) {\n CNT = LIMIT(static_cast(0), IN, MX);\n } else if ((UP) & (!LAST_UP)) {\n CNT = TO_BYTE(INC(static_cast(CNT), static_cast(STEP), static_cast(MX)));\n } else if ((DN) & (!LAST_DN)) {\n CNT = TO_BYTE(INC(static_cast(CNT), static_cast(-STEP), static_cast(MX)));\n }\n LAST_UP = UP;\n LAST_DN = DN;\n}\n\n\nCOUNT_DR::COUNT_DR()\n : STEP(1), MX(0xFFFFFFFF)\n{\n // Initialize variables\n}\n\nvoid COUNT_DR::operator()() {\n if (RST) {\n CNT = 0;\n } else if (SET) {\n CNT = LIMIT(static_cast(0), IN, MX);\n } else if ((UP) & (!LAST_UP)) {\n if (STEP > MX - CNT) {\n CNT = CNT - MX + STEP - 1;\n } else {\n CNT = CNT + STEP;\n }\n } else if ((DN) & (!LAST_DN)) {\n if (STEP > CNT) {\n CNT = CNT - STEP + MX + 1;\n } else {\n CNT = CNT - STEP;\n }\n }\n LAST_UP = UP;\n LAST_DN = DN;\n}\n\n\nCTRL_OUT::CTRL_OUT() {\n // Initialize variables\n}\n\nvoid CTRL_OUT::operator()() {\n Y = SEL(MANUAL, CI, MAN_IN) + OFFSET;\n if ((Y > LIM_L) & (Y < LIM_H)) {\n LIM = false;\n } else {\n Y = LIMIT(LIM_L, Y, LIM_H);\n LIM = true;\n }\n}\n\n\nCYCLE_4::CYCLE_4()\n : E(true)\n{\n // Initialize variables\n}\n\nvoid CYCLE_4::operator()() {\n TX = TO_TIME(T_PLC_MS());\n if (!INIT) {\n INIT = true;\n LAST = TX;\n }\n if (E) {\n if (SL) {\n STATE = LIMIT(0, SX, 3);\n LAST = TX;\n SL = false;\n } else {\n switch (STATE) {\n case 0:\n if (TX - LAST >= T0) {\n STATE = 1;\n LAST = TX;\n }\n break;\n case 1:\n if (TX - LAST >= T1) {\n STATE = 2;\n LAST = TX;\n }\n break;\n case 2:\n if (TX - LAST >= T2) {\n STATE = 3;\n LAST = TX;\n }\n break;\n case 3:\n if (TX - LAST >= T3) {\n if (S0) {\n STATE = 0;\n }\n LAST = TX;\n }\n break;\n }\n }\n } else {\n STATE = 0;\n LAST = TX;\n }\n}\n\n\nCYCLE_TIME::CYCLE_TIME() {\n // Initialize variables\n}\n\nvoid CYCLE_TIME::operator()() {\n TX = TO_TIME(T_PLC_MS()) - LAST_CYCLE;\n if (RST) {\n CT_MIN = 36000000000000LL;\n CT_MAX = 0LL;\n CYCLES = 0;\n } else if (LAST_CYCLE > 0LL) {\n if (TX < CT_MIN) {\n CT_MIN = TX;\n } else if (TX > CT_MAX) {\n CT_MAX = TX;\n }\n CT_LAST = TX;\n } else if (CT_MIN == 0LL) {\n CT_MIN = 0LL - 1000000LL;\n }\n if (INIT) {\n SYSTIME = SYSTIME + TX;\n if (SYSTIME >= 86400000000000LL) {\n SYSTIME = SYSTIME - 86400000000000LL;\n SYSDAYS = SYSDAYS + 1;\n }\n }\n INIT = true;\n LAST_CYCLE = LAST_CYCLE + TX;\n CYCLES = CYCLES + 1;\n}\n\n\nDCF77::DCF77()\n : SYNC_TIMEOUT(120000000000LL), TIME_OFFSET(1), DST_EN(true), ERROR(true)\n{\n // Initialize variables\n}\n\nvoid DCF77::operator()() {\n TP = false;\n T1 = TO_TIME(T_PLC_MS());\n TX = T1 - LAST;\n if ((REC) ^ (EDGE)) {\n EDGE = REC;\n if (((!REC) & (TX > 1700000000LL)) & (TX < 2000000000LL)) {\n STATE = 0;\n TP = !ERROR;\n } else if (((!REC) & (TX > 700000000LL)) & (TX < 1000000000LL)) {\n if (STATE < 58) {\n STATE = STATE + 1;\n } else {\n STATE = 0;\n }\n } else if ((REC) & (TX < 120000000LL)) {\n BITS[STATE] = 0;\n } else if (((REC) & (TX > 120000000LL)) & (TX < 250000000LL)) {\n BITS[STATE] = 1;\n } else {\n ERROR = true;\n STATE = 0;\n }\n LAST = LAST + TX;\n if ((REC) & (STATE == 58)) {\n ERROR = false;\n if (((BITS[0]) | (NOT((BITS[17]) ^ (BITS[18])))) | (!BITS[20])) {\n ERROR = true;\n }\n MINUTE = 0;\n MINUTE = (MINUTE & ~(1ULL << 0)) | ((BITS[21] ? 1ULL : 0ULL) << 0);\n MINUTE = (MINUTE & ~(1ULL << 1)) | ((BITS[22] ? 1ULL : 0ULL) << 1);\n MINUTE = (MINUTE & ~(1ULL << 2)) | ((BITS[23] ? 1ULL : 0ULL) << 2);\n MINUTE = (MINUTE & ~(1ULL << 3)) | ((BITS[24] ? 1ULL : 0ULL) << 3);\n if (BITS[25]) {\n MINUTE = MINUTE + 10;\n }\n if (BITS[26]) {\n MINUTE = MINUTE + 20;\n }\n if (BITS[27]) {\n MINUTE = MINUTE + 40;\n }\n if ((MINUTE > 59) | (((((((((BITS[21]) ^ (BITS[22])) ^ (BITS[23])) ^ (BITS[24])) ^ (BITS[25])) ^ (BITS[26])) ^ (BITS[27])) ^ (BITS[28])))) {\n ERROR = true;\n }\n HOUR = 0;\n HOUR = (HOUR & ~(1ULL << 0)) | ((BITS[29] ? 1ULL : 0ULL) << 0);\n HOUR = (HOUR & ~(1ULL << 1)) | ((BITS[30] ? 1ULL : 0ULL) << 1);\n HOUR = (HOUR & ~(1ULL << 2)) | ((BITS[31] ? 1ULL : 0ULL) << 2);\n HOUR = (HOUR & ~(1ULL << 3)) | ((BITS[32] ? 1ULL : 0ULL) << 3);\n if (BITS[33]) {\n HOUR = HOUR + 10;\n }\n if (BITS[34]) {\n HOUR = HOUR + 20;\n }\n if ((HOUR > 23) | ((((((((BITS[29]) ^ (BITS[30])) ^ (BITS[31])) ^ (BITS[32])) ^ (BITS[33])) ^ (BITS[34])) ^ (BITS[35])))) {\n ERROR = true;\n }\n DAY = 0;\n DAY = (DAY & ~(1ULL << 0)) | ((BITS[36] ? 1ULL : 0ULL) << 0);\n DAY = (DAY & ~(1ULL << 1)) | ((BITS[37] ? 1ULL : 0ULL) << 1);\n DAY = (DAY & ~(1ULL << 2)) | ((BITS[38] ? 1ULL : 0ULL) << 2);\n DAY = (DAY & ~(1ULL << 3)) | ((BITS[39] ? 1ULL : 0ULL) << 3);\n if (BITS[40]) {\n DAY = DAY + 10;\n }\n if (BITS[41]) {\n DAY = DAY + 20;\n }\n if (DAY > 31) {\n ERROR = true;\n }\n WDAY = 0;\n WDAY = (WDAY & ~(1ULL << 0)) | ((BITS[42] ? 1ULL : 0ULL) << 0);\n WDAY = (WDAY & ~(1ULL << 1)) | ((BITS[43] ? 1ULL : 0ULL) << 1);\n WDAY = (WDAY & ~(1ULL << 2)) | ((BITS[44] ? 1ULL : 0ULL) << 2);\n if ((WDAY > 7) | (WDAY < 1)) {\n ERROR = true;\n }\n MONTH = 0;\n MONTH = (MONTH & ~(1ULL << 0)) | ((BITS[45] ? 1ULL : 0ULL) << 0);\n MONTH = (MONTH & ~(1ULL << 1)) | ((BITS[46] ? 1ULL : 0ULL) << 1);\n MONTH = (MONTH & ~(1ULL << 2)) | ((BITS[47] ? 1ULL : 0ULL) << 2);\n MONTH = (MONTH & ~(1ULL << 3)) | ((BITS[48] ? 1ULL : 0ULL) << 3);\n if (BITS[49]) {\n MONTH = MONTH + 10;\n }\n if (MONTH > 12) {\n ERROR = true;\n }\n YEAR = 0;\n YEAR = (YEAR & ~(1ULL << 0)) | ((BITS[50] ? 1ULL : 0ULL) << 0);\n YEAR = (YEAR & ~(1ULL << 1)) | ((BITS[51] ? 1ULL : 0ULL) << 1);\n YEAR = (YEAR & ~(1ULL << 2)) | ((BITS[52] ? 1ULL : 0ULL) << 2);\n YEAR = (YEAR & ~(1ULL << 3)) | ((BITS[53] ? 1ULL : 0ULL) << 3);\n if (BITS[54]) {\n YEAR = YEAR + 10;\n }\n if (BITS[55]) {\n YEAR = YEAR + 20;\n }\n if (BITS[56]) {\n YEAR = YEAR + 40;\n }\n if (BITS[57]) {\n YEAR = YEAR + 80;\n }\n CNT = 0;\n for (I = 36; I <= 58; I++) {\n if (BITS[I]) {\n CNT = CNT + 1;\n }\n }\n if (!EVEN(static_cast(CNT))) {\n ERROR = true;\n }\n if (!ERROR) {\n OLD_TIME = MEZ;\n if (YEAR >= 70) {\n YEAR = YEAR + 1900;\n } else {\n YEAR = YEAR + 2000;\n }\n MEZ = SET_DT(YEAR, MONTH, DAY, HOUR, MINUTE, 0);\n DS = BITS[17];\n if (DS) {\n UTC = TO_DT(TO_DWORD(MEZ) - 7200);\n } else {\n UTC = TO_DT(TO_DWORD(MEZ) - 3600);\n }\n if (MEZ != OLD_TIME + 60000000000LL) {\n ERROR = true;\n }\n }\n }\n }\n TZ = TO_TIME(TO_DWORD(ABS(TIME_OFFSET)) * 3600000);\n if ((!INIT) | (SET)) {\n INIT = true;\n UTC = SDT;\n TP = true;\n DS = DSI;\n }\n if (TP) {\n RTC = UTC;\n if ((DS) & (DST_EN)) {\n if (TIME_OFFSET < 0) {\n RTC1 = RTC - TZ + 3600000000000LL;\n } else {\n RTC1 = RTC + TZ + 3600000000000LL;\n }\n } else {\n if (TIME_OFFSET < 0) {\n RTC1 = RTC - TZ;\n } else {\n RTC1 = RTC + TZ;\n }\n }\n SYNC = true;\n LAST_SYNC = LAST;\n TY = LAST;\n } else if ((RTC > TO_DT(0)) & (T1 - TY >= 1000000000LL)) {\n RTC = RTC + 1000000000LL;\n RTC1 = RTC1 + 1000000000LL;\n TY = TY + 1000000000LL;\n SYNC = (TY - LAST_SYNC < SYNC_TIMEOUT) & (LAST_SYNC > TO_TIME(0));\n WDAY = DAY_OF_WEEK(TO_DATE(RTC1));\n DS = (DST_EN) & (DST(UTC));\n }\n MSEC = TO_INT(T1 - TY);\n}\n\n\nDEAD_ZONE2::DEAD_ZONE2() {\n // Initialize variables\n}\n\nvoid DEAD_ZONE2::operator()() {\n if (ABS(X) > L) {\n Y = X;\n } else if (Y > 0.0) {\n Y = L;\n } else {\n Y = -L;\n }\n}\n\n\nDEC_2::DEC_2() {\n // Initialize variables\n}\n\nvoid DEC_2::operator()() {\n Q0 = (D) & (!A);\n Q1 = (D) & (A);\n}\n\n\nDEC_4::DEC_4() {\n // Initialize variables\n}\n\nvoid DEC_4::operator()() {\n Q0 = ((D) & (!A0)) & (!A1);\n Q1 = ((D) & (A0)) & (!A1);\n Q2 = ((D) & (!A0)) & (A1);\n Q3 = ((D) & (A0)) & (A1);\n}\n\n\nDEC_8::DEC_8() {\n // Initialize variables\n}\n\nvoid DEC_8::operator()() {\n X = (X & ~(1ULL << 0)) | ((A0 ? 1ULL : 0ULL) << 0);\n X = (X & ~(1ULL << 1)) | ((A1 ? 1ULL : 0ULL) << 1);\n X = (X & ~(1ULL << 2)) | ((A2 ? 1ULL : 0ULL) << 2);\n Q0 = false;\n Q1 = false;\n Q2 = false;\n Q3 = false;\n Q4 = false;\n Q5 = false;\n Q6 = false;\n Q7 = false;\n switch (X) {\n case 0:\n Q0 = D;\n break;\n case 1:\n Q1 = D;\n break;\n case 2:\n Q2 = D;\n break;\n case 3:\n Q3 = D;\n break;\n case 4:\n Q4 = D;\n break;\n case 5:\n Q5 = D;\n break;\n case 6:\n Q6 = D;\n break;\n case 7:\n Q7 = D;\n break;\n }\n}\n\n\nDELAY::DELAY() {\n // Initialize variables\n}\n\nvoid DELAY::operator()() {\n STOP = LIMIT(0, N, 32) - 1;\n if ((RST) | (!INIT)) {\n INIT = true;\n for (I = 0; I <= STOP; I++) {\n BUF[I] = IN;\n }\n OUT = IN;\n I = 0;\n } else if (STOP < 0) {\n OUT = IN;\n } else {\n OUT = BUF[I];\n BUF[I] = IN;\n I = INC1(I, N);\n }\n}\n\n\nDELAY_4::DELAY_4() {\n // Initialize variables\n}\n\nvoid DELAY_4::operator()() {\n OUT4 = OUT3;\n OUT3 = OUT2;\n OUT2 = OUT1;\n OUT1 = TEMP;\n TEMP = IN;\n}\n\n\nDRIVER_1::DRIVER_1() {\n // Initialize variables\n}\n\nvoid DRIVER_1::operator()() {\n if (OFF.Q) {\n Q = false;\n }\n if (RST) {\n Q = false;\n } else if (SET) {\n Q = true;\n } else if ((IN) & (!EDGE)) {\n if (TOGGLE_MODE) {\n Q = !Q;\n } else {\n Q = true;\n }\n }\n EDGE = IN;\n if (TIMEOUT > 0LL) {\n OFF.IN = Q;\n OFF.PT = TIMEOUT;\n OFF();\n OFF.ENO = true;\n }\n}\n\n\nDRIVER_4C::DRIVER_4C()\n : SX({1, 3, 7, 15})\n{\n // Initialize variables\n}\n\nvoid DRIVER_4C::operator()() {\n if ((RST) | (OFF.Q)) {\n SN = 0;\n } else if ((IN) & (!EDGE)) {\n SN = SN + 1;\n if ((SN > 7) | (SX[SN] == 0)) {\n SN = 0;\n }\n }\n EDGE = IN;\n if (SN > 0) {\n Q0 = ((static_cast(SX[SN]) >> 0) & 1);\n Q1 = ((static_cast(SX[SN]) >> 1) & 1);\n Q2 = ((static_cast(SX[SN]) >> 2) & 1);\n Q3 = ((static_cast(SX[SN]) >> 3) & 1);\n } else {\n Q0 = false;\n Q1 = false;\n Q2 = false;\n Q3 = false;\n }\n if (TIMEOUT > 0LL) {\n OFF.IN = SN > 0;\n OFF.PT = TIMEOUT;\n OFF();\n OFF.ENO = true;\n }\n}\n\n\nDT_SIMU::DT_SIMU()\n : SPEED(1.0)\n{\n // Initialize variables\n}\n\nvoid DT_SIMU::operator()() {\n TX = T_PLC_MS();\n TC = TO_DWORD(TO_REAL(TX - LAST) * SPEED);\n if (!INIT) {\n INIT = true;\n DTS = START;\n TC = 0;\n LAST = TX;\n } else if (SPEED == 0.0) {\n DTS = TO_DT(TO_DWORD(DTS) + 1);\n } else if (TC >= 1000) {\n TD = (TC / 1000) * 1000;\n DTS = DTS + TO_TIME(TD);\n LAST = LAST + TO_DWORD(TO_REAL(TD) / SPEED);\n }\n}\n\n\nD_TRIG::D_TRIG() {\n // Initialize variables\n}\n\nvoid D_TRIG::operator()() {\n Q = IN != LAST_IN;\n X = IN - LAST_IN;\n LAST_IN = IN;\n}\n\n\nENERGY::ENERGY() {\n // Initialize variables\n}\n\nvoid ENERGY::operator()() {\n YJ = J + WH * 3600.0 + C * 4.1868;\n YC = YJ * 0.238845896627496;\n YWH = YJ * 0.00027777777778;\n}\n\n\nESR_COLLECT::ESR_COLLECT()\n : MAX_IN(3), MAX_OUT(32), CNT(-1)\n{\n // Initialize variables\n}\n\nvoid ESR_COLLECT::operator()() {\n if ((RST) | (CNT < 0)) {\n POS = -1;\n } else {\n for (CNT = 0; CNT <= MAX_IN; CNT++) {\n if (ESR_0[CNT].TYP > 0) {\n POS = INC1(POS, MAX_OUT);\n ESR_OUT[POS] = ESR_0[CNT];\n }\n if (ESR_1[CNT].TYP > 0) {\n POS = INC1(POS, MAX_OUT);\n ESR_OUT[POS] = ESR_1[CNT];\n }\n if (ESR_2[CNT].TYP > 0) {\n POS = INC1(POS, MAX_OUT);\n ESR_OUT[POS] = ESR_2[CNT];\n }\n if (ESR_3[CNT].TYP > 0) {\n POS = INC1(POS, MAX_OUT);\n ESR_OUT[POS] = ESR_3[CNT];\n }\n if (ESR_4[CNT].TYP > 0) {\n POS = INC1(POS, MAX_OUT);\n ESR_OUT[POS] = ESR_4[CNT];\n }\n if (ESR_5[CNT].TYP > 0) {\n POS = INC1(POS, MAX_OUT);\n ESR_OUT[POS] = ESR_5[CNT];\n }\n if (ESR_6[CNT].TYP > 0) {\n POS = INC1(POS, MAX_OUT);\n ESR_OUT[POS] = ESR_6[CNT];\n }\n if (ESR_7[CNT].TYP > 0) {\n POS = INC1(POS, MAX_OUT);\n ESR_OUT[POS] = ESR_7[CNT];\n }\n }\n }\n}\n\n\nESR_MON_B8::ESR_MON_B8() {\n // Initialize variables\n}\n\nvoid ESR_MON_B8::operator()() {\n TX = TO_TIME(T_PLC_MS());\n ESR_FLAG = false;\n ESR_OUT[3].TYP = 0;\n ESR_OUT[2].TYP = 0;\n ESR_OUT[1].TYP = 0;\n ESR_OUT[0].TYP = 0;\n CNT = 0;\n if (S0 != X0) {\n ESR_OUT[CNT].TYP = 10 + TO_BYTE(S0);\n ESR_OUT[CNT].ADRESS = A0;\n ESR_OUT[CNT].DS = DT_IN;\n ESR_OUT[CNT].TS = TX;\n X0 = S0;\n CNT = CNT + 1;\n ESR_FLAG = true;\n }\n if (S1 != X1) {\n ESR_OUT[CNT].TYP = 10 + TO_BYTE(S1);\n ESR_OUT[CNT].ADRESS = A1;\n ESR_OUT[CNT].DS = DT_IN;\n ESR_OUT[CNT].TS = TX;\n X1 = S1;\n CNT = CNT + 1;\n ESR_FLAG = true;\n }\n if (S2 != X2) {\n ESR_OUT[CNT].TYP = 10 + TO_BYTE(S2);\n ESR_OUT[CNT].ADRESS = A2;\n ESR_OUT[CNT].DS = DT_IN;\n ESR_OUT[CNT].TS = TX;\n X2 = S2;\n CNT = CNT + 1;\n ESR_FLAG = true;\n }\n if (S3 != X3) {\n ESR_OUT[CNT].TYP = 10 + TO_BYTE(S3);\n ESR_OUT[CNT].ADRESS = A3;\n ESR_OUT[CNT].DS = DT_IN;\n ESR_OUT[CNT].TS = TX;\n X3 = S3;\n CNT = CNT + 1;\n ESR_FLAG = true;\n }\n if ((S4 != X4) & (CNT < 4)) {\n ESR_OUT[CNT].TYP = 10 + TO_BYTE(S4);\n ESR_OUT[CNT].ADRESS = A4;\n ESR_OUT[CNT].DS = DT_IN;\n ESR_OUT[CNT].TS = TX;\n X4 = S4;\n CNT = CNT + 1;\n ESR_FLAG = true;\n }\n if ((S5 != X5) & (CNT < 4)) {\n ESR_OUT[CNT].TYP = 10 + TO_BYTE(S5);\n ESR_OUT[CNT].ADRESS = A5;\n ESR_OUT[CNT].DS = DT_IN;\n ESR_OUT[CNT].TS = TX;\n X5 = S5;\n CNT = CNT + 1;\n ESR_FLAG = true;\n }\n if ((S6 != X6) & (CNT < 4)) {\n ESR_OUT[CNT].TYP = 10 + TO_BYTE(S6);\n ESR_OUT[CNT].ADRESS = A6;\n ESR_OUT[CNT].DS = DT_IN;\n ESR_OUT[CNT].TS = TX;\n X6 = S6;\n CNT = CNT + 1;\n ESR_FLAG = true;\n }\n if ((S7 != X7) & (CNT < 4)) {\n ESR_OUT[CNT].TYP = 10 + TO_BYTE(S7);\n ESR_OUT[CNT].ADRESS = A7;\n ESR_OUT[CNT].DS = DT_IN;\n ESR_OUT[CNT].TS = TX;\n X7 = S7;\n CNT = CNT + 1;\n ESR_FLAG = true;\n }\n}\n\n\nESR_MON_R4::ESR_MON_R4() {\n // Initialize variables\n}\n\nvoid ESR_MON_R4::operator()() {\n TX = TO_TIME(T_PLC_MS());\n P0 = &(R0);\n P1 = &(R1);\n P2 = &(R2);\n P3 = &(R3);\n ESR_FLAG = false;\n ESR_OUT[3].TYP = 0;\n ESR_OUT[2].TYP = 0;\n ESR_OUT[1].TYP = 0;\n ESR_OUT[0].TYP = 0;\n CNT = 0;\n if (DIFFER(R0, X0, S0)) {\n ESR_OUT[CNT].TYP = 20;\n ESR_OUT[CNT].ADRESS = A0;\n ESR_OUT[CNT].DS = DT_IN;\n ESR_OUT[CNT].TS = TX;\n ESR_OUT[CNT].DATA[0] = BYTE_OF_DWORD((*P0), static_cast(0));\n ESR_OUT[CNT].DATA[1] = BYTE_OF_DWORD((*P0), static_cast(1));\n ESR_OUT[CNT].DATA[2] = BYTE_OF_DWORD((*P0), static_cast(2));\n ESR_OUT[CNT].DATA[3] = BYTE_OF_DWORD((*P0), static_cast(3));\n X0 = R0;\n CNT = CNT + 1;\n ESR_FLAG = true;\n }\n if (DIFFER(R1, X1, S1)) {\n ESR_OUT[CNT].TYP = 20;\n ESR_OUT[CNT].ADRESS = A1;\n ESR_OUT[CNT].DS = DT_IN;\n ESR_OUT[CNT].TS = TX;\n ESR_OUT[CNT].DATA[0] = BYTE_OF_DWORD((*P1), static_cast(0));\n ESR_OUT[CNT].DATA[1] = BYTE_OF_DWORD((*P1), static_cast(1));\n ESR_OUT[CNT].DATA[2] = BYTE_OF_DWORD((*P1), static_cast(2));\n ESR_OUT[CNT].DATA[3] = BYTE_OF_DWORD((*P1), static_cast(3));\n X1 = R1;\n CNT = CNT + 1;\n ESR_FLAG = true;\n }\n if (DIFFER(R2, X2, S2)) {\n ESR_OUT[CNT].TYP = 20;\n ESR_OUT[CNT].ADRESS = A2;\n ESR_OUT[CNT].DS = DT_IN;\n ESR_OUT[CNT].TS = TX;\n ESR_OUT[CNT].DATA[0] = BYTE_OF_DWORD((*P2), static_cast(0));\n ESR_OUT[CNT].DATA[1] = BYTE_OF_DWORD((*P2), static_cast(1));\n ESR_OUT[CNT].DATA[2] = BYTE_OF_DWORD((*P2), static_cast(2));\n ESR_OUT[CNT].DATA[3] = BYTE_OF_DWORD((*P2), static_cast(3));\n X2 = R2;\n CNT = CNT + 1;\n ESR_FLAG = true;\n }\n if (DIFFER(R3, X3, S3)) {\n ESR_OUT[CNT].TYP = 20;\n ESR_OUT[CNT].ADRESS = A3;\n ESR_OUT[CNT].DS = DT_IN;\n ESR_OUT[CNT].TS = TX;\n ESR_OUT[CNT].DATA[0] = BYTE_OF_DWORD((*P3), static_cast(0));\n ESR_OUT[CNT].DATA[1] = BYTE_OF_DWORD((*P3), static_cast(1));\n ESR_OUT[CNT].DATA[2] = BYTE_OF_DWORD((*P3), static_cast(2));\n ESR_OUT[CNT].DATA[3] = BYTE_OF_DWORD((*P3), static_cast(3));\n X3 = R3;\n CNT = CNT + 1;\n ESR_FLAG = true;\n }\n}\n\n\nESR_MON_X8::ESR_MON_X8()\n : MODE(3)\n{\n // Initialize variables\n}\n\nvoid ESR_MON_X8::operator()() {\n TX = TO_TIME(T_PLC_MS());\n ESR_FLAG = false;\n ESR_OUT[3].TYP = 0;\n ESR_OUT[2].TYP = 0;\n ESR_OUT[1].TYP = 0;\n ESR_OUT[0].TYP = 0;\n CNT = 0;\n if ((S0 != X0) & (((((S0 < 100)) | ((((S0 > 99) & (S0 < 200)) & (MODE >= 2)))) | (((S0 > 199) & (MODE == 3)))))) {\n ESR_OUT[CNT] = STATUS_TO_ESR(S0, A0, DT_IN, TX);\n X0 = S0;\n CNT = CNT + 1;\n ESR_FLAG = true;\n }\n if ((S1 != X1) & (((((S1 < 100)) | ((((S1 > 99) & (S1 < 200)) & (MODE >= 2)))) | (((S1 > 199) & (MODE == 3)))))) {\n ESR_OUT[CNT] = STATUS_TO_ESR(S1, A1, DT_IN, TX);\n X1 = S1;\n CNT = CNT + 1;\n ESR_FLAG = true;\n }\n if ((S2 != X2) & (((((S2 < 100)) | ((((S2 > 99) & (S2 < 200)) & (MODE >= 2)))) | (((S2 > 199) & (MODE == 3)))))) {\n ESR_OUT[CNT] = STATUS_TO_ESR(S2, A2, DT_IN, TX);\n X2 = S2;\n CNT = CNT + 1;\n ESR_FLAG = true;\n }\n if ((S3 != X3) & (((((S3 < 100)) | ((((S3 > 99) & (S3 < 200)) & (MODE >= 2)))) | (((S3 > 199) & (MODE == 3)))))) {\n ESR_OUT[CNT] = STATUS_TO_ESR(S3, A3, DT_IN, TX);\n X3 = S3;\n CNT = CNT + 1;\n ESR_FLAG = true;\n }\n if (((CNT < 4) & (S4 != X4)) & (((((S4 < 100)) | ((((S4 > 99) & (S4 < 200)) & (MODE >= 2)))) | (((S4 > 199) & (MODE == 3)))))) {\n ESR_OUT[CNT] = STATUS_TO_ESR(S4, A4, DT_IN, TX);\n X4 = S4;\n CNT = CNT + 1;\n ESR_FLAG = true;\n }\n if (((CNT < 4) & (S5 != X5)) & (((((S5 < 100)) | ((((S5 > 99) & (S5 < 200)) & (MODE >= 2)))) | (((S5 > 199) & (MODE == 3)))))) {\n ESR_OUT[CNT] = STATUS_TO_ESR(S5, A5, DT_IN, TX);\n X5 = S5;\n CNT = CNT + 1;\n ESR_FLAG = true;\n }\n if (((CNT < 4) & (S6 != X6)) & (((((S6 < 100)) | ((((S6 > 99) & (S6 < 200)) & (MODE >= 2)))) | (((S6 > 199) & (MODE == 3)))))) {\n ESR_OUT[CNT] = STATUS_TO_ESR(S6, A6, DT_IN, TX);\n X6 = S6;\n CNT = CNT + 1;\n ESR_FLAG = true;\n }\n if (((CNT < 4) & (S7 != X7)) & (((((S7 < 100)) | ((((S7 > 99) & (S7 < 200)) & (MODE >= 2)))) | (((S7 > 199) & (MODE == 3)))))) {\n ESR_OUT[CNT] = STATUS_TO_ESR(S7, A7, DT_IN, TX);\n X7 = S7;\n CNT = CNT + 1;\n ESR_FLAG = true;\n }\n}\n\n\nEVENTS::EVENTS()\n : SIZE(49)\n{\n // Initialize variables\n}\n\nvoid EVENTS::operator()() {\n if (LAST_ACTIVE != DATE_IN) {\n LAST_ACTIVE = DATE_IN;\n Y_INT = false;\n NAME_INT = \"\";\n DAY_IN = DAY_OF_DATE(DATE_IN);\n CYR = YEAR_OF_DATE(DATE_IN);\n for (I = 0; I <= SIZE; I++) {\n CHECK = ELIST[I];\n LDAY = DAY_OF_DATE(SET_DATE(CYR, static_cast(CHECK.MONTH), static_cast(CHECK.DAY)));\n if ((DAY_IN >= LDAY) & (DAY_IN <= LDAY + CHECK.USE - 1)) {\n Y_INT = true;\n NAME_INT = CHECK.NAME;\n goto __strucpp_loop_exit_3;\n }\n }\n __strucpp_loop_exit_3: ;\n }\n if (ENA) {\n Y = Y_INT;\n NAME = NAME_INT;\n } else {\n Y = false;\n NAME = \"\";\n }\n}\n\n\nFF_D2E::FF_D2E() {\n // Initialize variables\n}\n\nvoid FF_D2E::operator()() {\n if (RST) {\n Q0 = false;\n Q1 = false;\n } else if ((CLK) & (!EDGE)) {\n Q0 = D0;\n Q1 = D1;\n }\n EDGE = CLK;\n}\n\n\nFF_D4E::FF_D4E() {\n // Initialize variables\n}\n\nvoid FF_D4E::operator()() {\n if (RST) {\n Q0 = false;\n Q1 = false;\n Q2 = false;\n Q3 = false;\n } else if ((CLK) & (!EDGE)) {\n Q0 = D0;\n Q1 = D1;\n Q2 = D2;\n Q3 = D3;\n }\n EDGE = CLK;\n}\n\n\nFF_DRE::FF_DRE() {\n // Initialize variables\n}\n\nvoid FF_DRE::operator()() {\n if ((RST) | (SET)) {\n Q = !RST;\n } else if ((CLK) & (!EDGE)) {\n Q = D;\n }\n EDGE = CLK;\n}\n\n\nFF_JKE::FF_JKE() {\n // Initialize variables\n}\n\nvoid FF_JKE::operator()() {\n if ((RST) | (SET)) {\n Q = !RST;\n } else if ((CLK) & (!EDGE)) {\n if ((J) ^ (K)) {\n Q = J;\n } else {\n Q = (K) ^ (Q);\n }\n }\n EDGE = CLK;\n}\n\n\nFF_RSE::FF_RSE() {\n // Initialize variables\n}\n\nvoid FF_RSE::operator()() {\n if (RST) {\n Q = false;\n } else if ((CR) & (!ER)) {\n Q = false;\n } else if ((CS) & (!ES)) {\n Q = true;\n }\n ES = CS;\n ER = CR;\n}\n\n\nFIFO_16::FIFO_16()\n : E(true), EMPTY(true), N(16)\n{\n // Initialize variables\n}\n\nvoid FIFO_16::operator()() {\n if (RST) {\n PW = PR;\n FULL = false;\n EMPTY = true;\n DOUT = 0;\n } else if (E) {\n if ((!EMPTY) & (RD)) {\n DOUT = FIFO[PR];\n PR = INC1(PR, N);\n EMPTY = PR == PW;\n FULL = false;\n }\n if ((!FULL) & (WD)) {\n FIFO[PW] = DIN;\n PW = INC1(PW, N);\n FULL = PW == PR;\n EMPTY = false;\n }\n }\n}\n\n\nFIFO_32::FIFO_32()\n : E(true), EMPTY(true), N(32)\n{\n // Initialize variables\n}\n\nvoid FIFO_32::operator()() {\n if (RST) {\n PW = PR;\n FULL = false;\n EMPTY = true;\n DOUT = 0;\n } else if (E) {\n if ((!EMPTY) & (RD)) {\n DOUT = FIFO[PR];\n PR = INC1(PR, N);\n EMPTY = PR == PW;\n FULL = false;\n }\n if ((!FULL) & (WD)) {\n FIFO[PW] = DIN;\n PW = INC1(PW, N);\n FULL = PW == PR;\n EMPTY = false;\n }\n }\n}\n\n\nFILTER_DW::FILTER_DW() {\n // Initialize variables\n}\n\nvoid FILTER_DW::operator()() {\n TX = T_PLC_MS();\n if ((!INIT) | (T == 0LL)) {\n INIT = true;\n YI = TO_REAL(X);\n } else {\n YI = YI + (TO_REAL(X) - TO_REAL(Y)) * TO_REAL(TX - LAST) / TO_REAL(T);\n }\n LAST = TX;\n Y = TO_DWORD(YI);\n}\n\n\nFILTER_I::FILTER_I() {\n // Initialize variables\n}\n\nvoid FILTER_I::operator()() {\n TX = T_PLC_MS();\n if ((!INIT) | (T == 0LL)) {\n INIT = true;\n YI = TO_DINT(X) * 1000;\n } else {\n YI = YI + TO_DINT(X - Y) * TO_DINT(TX - LAST) * 1000 / TO_DINT(T);\n }\n LAST = TX;\n Y = TO_INT(YI / 1000);\n}\n\n\nFILTER_MAV_DW::FILTER_MAV_DW() {\n // Initialize variables\n}\n\nvoid FILTER_MAV_DW::operator()() {\n N = MIN(N, static_cast(32));\n if (((!INIT) | (RST)) | (N == 0)) {\n INIT = true;\n TMP = TO_INT(N) - 1;\n for (I = 0; I <= TMP; I++) {\n BUFFER[I] = X;\n }\n Y = X;\n } else {\n TMP = TO_INT(N);\n I = INC1(I, TMP);\n Y = Y + (X - BUFFER[I]) / N;\n BUFFER[I] = X;\n }\n}\n\n\nFILTER_MAV_W::FILTER_MAV_W() {\n // Initialize variables\n}\n\nvoid FILTER_MAV_W::operator()() {\n N = MIN(N, static_cast(32));\n if (((!INIT) | (RST)) | (N == 0)) {\n INIT = true;\n TMP = TO_INT(N) - 1;\n for (I = 1; I <= TMP; I++) {\n BUFFER[I] = X;\n }\n SUM = Y * N;\n Y = X;\n } else {\n TMP = TO_INT(N);\n I = INC1(I, TMP);\n SUM = SUM + X - BUFFER[I];\n Y = TO_WORD(SUM / N);\n BUFFER[I] = X;\n }\n}\n\n\nFILTER_W::FILTER_W() {\n // Initialize variables\n}\n\nvoid FILTER_W::operator()() {\n TX = T_PLC_MS();\n if ((!INIT) | (T == 0LL)) {\n INIT = true;\n LAST = TX;\n Y = X;\n } else if (Y == X) {\n LAST = TX;\n } else {\n TMP = TO_DWORD(X - Y) * (TX - LAST) / TO_DWORD(T);\n if (TMP != 0) {\n Y = TO_WORD(TO_DINT(Y) + TO_DINT(TMP));\n LAST = TX;\n }\n }\n}\n\n\nFILTER_WAV::FILTER_WAV() {\n // Initialize variables\n}\n\nvoid FILTER_WAV::operator()() {\n if ((!INIT) | (RST)) {\n INIT = true;\n for (I = 0; I <= 15; I++) {\n BUFFER[I] = X;\n }\n I = 15;\n Y = X;\n } else {\n I = INC1(I, 16);\n BUFFER[I] = X;\n }\n Y = 0.0;\n for (N = 0; N <= 15; N++) {\n Y = BUFFER[I] * W[N] + Y;\n I = DEC1(I, 16);\n }\n}\n\n\nFT_DERIV::FT_DERIV()\n : K(1.0), RUN(true)\n{\n // Initialize variables\n}\n\nvoid FT_DERIV::operator()() {\n TX = T_PLC_US();\n TC = TO_REAL(TX - LAST);\n LAST = TX;\n if (!INIT) {\n INIT = true;\n OLD = IN;\n } else if ((RUN) & (TC > 0.0)) {\n OUT = (IN - OLD) / TC * 1000000.0 * K;\n OLD = IN;\n } else {\n OUT = 0.0;\n }\n}\n\n\nFT_MIN_MAX::FT_MIN_MAX() {\n // Initialize variables\n}\n\nvoid FT_MIN_MAX::operator()() {\n if ((RST) | (!INIT)) {\n MN = IN;\n MX = IN;\n INIT = true;\n } else if (IN < MN) {\n MN = IN;\n } else if (IN > MX) {\n MX = IN;\n }\n}\n\n\nFT_PIWL::FT_PIWL()\n : KP(1.0), KI(1.0), LIM_L(-1e+38), LIM_H(1e+38)\n{\n // Initialize variables\n}\n\nvoid FT_PIWL::operator()() {\n if ((!INIT) | (RST)) {\n INIT = true;\n IN_LAST = IN;\n T_LAST = T_PLC_US();\n I = 0.0;\n TC = 0.0;\n } else {\n TX = T_PLC_US();\n TC = TO_REAL(TX - T_LAST);\n T_LAST = TX;\n P = KP * IN;\n I = (IN + IN_LAST) * 5e-7 * KI * TC + I;\n IN_LAST = IN;\n Y = P + I;\n if (Y >= LIM_H) {\n Y = LIM_H;\n if (KI != 0.0) {\n I = LIM_H - P;\n } else {\n I = 0.0;\n }\n LIM = true;\n } else if (Y <= LIM_L) {\n Y = LIM_L;\n if (KI != 0.0) {\n I = LIM_L - P;\n } else {\n I = 0.0;\n }\n LIM = true;\n } else {\n LIM = false;\n }\n }\n}\n\n\nFT_PT1::FT_PT1()\n : K(1.0)\n{\n // Initialize variables\n}\n\nvoid FT_PT1::operator()() {\n TX = T_PLC_US();\n if ((!INIT) | (T == 0LL)) {\n INIT = true;\n OUT = K * IN;\n } else {\n OUT = OUT + (IN * K - OUT) * TO_REAL(TX - LAST) / TO_REAL(T) * 0.001;\n if (ABS(OUT) < 1e-20) {\n OUT = 0.0;\n }\n }\n LAST = TX;\n}\n\n\nFT_PROFILE::FT_PROFILE()\n : K(1.0), M(1.0)\n{\n // Initialize variables\n}\n\nvoid FT_PROFILE::operator()() {\n TX = TO_TIME(T_PLC_MS());\n if ((E) & (!EDGE)) {\n RUN = true;\n ET = 0LL;\n T0 = TX;\n TA = TX;\n TB = MULTIME(TIME_1, M);\n VA = VALUE_0;\n VB = VALUE_1;\n TEMP = VALUE_0;\n STATE = 1;\n }\n EDGE = E;\n if (RUN) {\n switch (STATE) {\n case 1:\n if (TX - TA >= TB) {\n TA = TA + TB;\n TB = MULTIME(TIME_2 - TIME_1, M);\n VA = VALUE_1;\n VB = VALUE_2;\n TEMP = VALUE_1;\n STATE = 2;\n } else {\n TEMP = ((VB - VA) * TO_REAL(TX - TA) / TO_REAL(TB) + VA);\n }\n break;\n case 2:\n if (TX - TA >= TB) {\n TA = TA + TB;\n TB = MULTIME(TIME_3 - TIME_2, M);\n VA = VALUE_2;\n VB = VALUE_3;\n TEMP = VALUE_2;\n STATE = 3;\n } else {\n TEMP = ((VB - VA) * TO_REAL(TX - TA) / TO_REAL(TB) + VA);\n }\n break;\n case 3:\n if (TX - TA >= TB) {\n TA = TA + TB;\n TB = MULTIME(TIME_10 - TIME_3, M);\n VA = VALUE_3;\n VB = VALUE_10;\n TEMP = VALUE_3;\n STATE = 4;\n } else {\n TEMP = ((VB - VA) * TO_REAL(TX - TA) / TO_REAL(TB) + VA);\n }\n break;\n case 4:\n if (TX - TA >= TB) {\n TA = TA + TB;\n TB = MULTIME(TIME_11 - TIME_10, M);\n VA = VALUE_10;\n VB = VALUE_11;\n TEMP = VALUE_10;\n if (E) {\n STATE = 5;\n } else {\n STATE = 6;\n }\n } else {\n TEMP = ((VB - VA) * TO_REAL(TX - TA) / TO_REAL(TB) + VA);\n }\n break;\n case 5:\n if (E) {\n TA = TX;\n } else {\n STATE = 6;\n }\n break;\n case 6:\n if (TX - TA >= TB) {\n TA = TA + TB;\n TB = MULTIME(TIME_12 - TIME_11, M);\n VA = VALUE_11;\n VB = VALUE_12;\n TEMP = VALUE_11;\n STATE = 7;\n } else {\n TEMP = ((VB - VA) * TO_REAL(TX - TA) / TO_REAL(TB) + VA);\n }\n break;\n case 7:\n if (TX - TA >= TB) {\n TA = TA + TB;\n TB = MULTIME(TIME_13 - TIME_12, M);\n VA = VALUE_12;\n VB = VALUE_13;\n TEMP = VALUE_12;\n STATE = 8;\n } else {\n TEMP = ((VB - VA) * TO_REAL(TX - TA) / TO_REAL(TB) + VA);\n }\n break;\n case 8:\n if (TX - TA >= TB) {\n TEMP = VALUE_13;\n RUN = false;\n } else {\n TEMP = ((VB - VA) * TO_REAL(TX - TA) / TO_REAL(TB) + VA);\n }\n break;\n }\n Y = TEMP * K + O;\n ET = TX - T0;\n }\n}\n\n\nFT_RMP::FT_RMP()\n : RMP(true)\n{\n // Initialize variables\n}\n\nvoid FT_RMP::operator()() {\n TX = TO_TIME(T_PLC_MS()) - LAST;\n if (!INIT) {\n INIT = true;\n LAST = TX;\n TX = 0LL;\n OUT = IN;\n }\n if (!RMP) {\n OUT = IN;\n BUSY = false;\n } else if (OUT > IN) {\n OUT = OUT - TO_REAL(TX) * 0.001 * KF;\n OUT = MAX(IN, OUT);\n } else if (OUT < IN) {\n OUT = OUT + TO_REAL(TX) * 0.001 * KR;\n OUT = MIN(IN, OUT);\n }\n if (OUT < IN) {\n BUSY = true;\n UD = true;\n } else if (OUT > IN) {\n BUSY = true;\n UD = false;\n } else {\n BUSY = false;\n }\n LAST = LAST + TX;\n}\n\n\nFT_TN16::FT_TN16()\n : LENGTH(16)\n{\n // Initialize variables\n}\n\nvoid FT_TN16::operator()() {\n TX = TO_TIME(T_PLC_MS());\n TRIG = false;\n if (!INIT) {\n X[CNT] = IN;\n INIT = true;\n LAST = TX;\n } else if (TX - LAST >= T / LENGTH) {\n if (CNT == LENGTH - 1) {\n CNT = 0;\n } else {\n CNT = CNT + 1;\n }\n OUT = X[CNT];\n X[CNT] = IN;\n LAST = TX;\n TRIG = true;\n }\n}\n\n\nFT_TN64::FT_TN64()\n : LENGTH(64)\n{\n // Initialize variables\n}\n\nvoid FT_TN64::operator()() {\n TX = TO_TIME(T_PLC_MS());\n TRIG = false;\n if (!INIT) {\n X[CNT] = IN;\n INIT = true;\n LAST = TX;\n } else if (TX - LAST >= T / LENGTH) {\n if (CNT == LENGTH - 1) {\n CNT = 0;\n } else {\n CNT = CNT + 1;\n }\n OUT = X[CNT];\n X[CNT] = IN;\n LAST = TX;\n TRIG = true;\n }\n}\n\n\nFT_TN8::FT_TN8()\n : LENGTH(8)\n{\n // Initialize variables\n}\n\nvoid FT_TN8::operator()() {\n TX = TO_TIME(T_PLC_MS());\n TRIG = false;\n if (!INIT) {\n X[CNT] = IN;\n INIT = true;\n LAST = TX;\n } else if (TX - LAST >= T / LENGTH) {\n if (CNT == LENGTH - 1) {\n CNT = 0;\n } else {\n CNT = CNT + 1;\n }\n OUT = X[CNT];\n X[CNT] = IN;\n LAST = TX;\n TRIG = true;\n }\n}\n\n\nGEN_BIT::GEN_BIT()\n : RX(1)\n{\n // Initialize variables\n}\n\nvoid GEN_BIT::operator()() {\n if ((CLK) & (!RST)) {\n RUN = ((REP == 0)) | ((RX <= REP));\n if (RUN) {\n if (CNT == STEPS) {\n CNT = 0;\n }\n if (CNT == 0) {\n R0 = IN0;\n R1 = IN1;\n R2 = IN2;\n R3 = IN3;\n }\n if ((CNT < STEPS)) {\n Q0 = ((static_cast(R0) >> 0) & 1);\n Q1 = ((static_cast(R1) >> 0) & 1);\n Q2 = ((static_cast(R2) >> 0) & 1);\n Q3 = ((static_cast(R3) >> 0) & 1);\n R0 = SHR(R0, 1);\n R1 = SHR(R1, 1);\n R2 = SHR(R2, 1);\n R3 = SHR(R3, 1);\n }\n CNT = CNT + 1;\n if (((CNT == STEPS)) & ((REP != 0))) {\n RX = RX + 1;\n }\n if (((RX > REP)) & ((REP != 0))) {\n RUN = false;\n }\n }\n } else {\n if (RST) {\n RUN = false;\n Q0 = false;\n Q1 = false;\n Q2 = false;\n Q3 = false;\n R0 = 0;\n R1 = 0;\n R2 = 0;\n R3 = 0;\n CNT = 0;\n RX = 1;\n }\n }\n}\n\n\nGEN_PULSE::GEN_PULSE()\n : ENQ(true)\n{\n // Initialize variables\n}\n\nvoid GEN_PULSE::operator()() {\n if (ENQ) {\n TX = TO_TIME(T_PLC_MS());\n if (!INIT) {\n INIT = true;\n TN = TX;\n }\n if (TX - TN >= SEL(Q, PTL, PTH)) {\n TN = TN + SEL(Q, PTL, PTH);\n Q = !Q;\n }\n } else {\n Q = false;\n INIT = false;\n }\n}\n\n\nGEN_PW2::GEN_PW2() {\n // Initialize variables\n}\n\nvoid GEN_PW2::operator()() {\n TX = TO_TIME(T_PLC_MS());\n if (!INIT) {\n START = TX;\n INIT = true;\n TH = 0LL;\n TL = 0LL;\n }\n if (TS) {\n T_HIGH = TH2;\n T_LOW = TL2;\n } else {\n T_HIGH = TH1;\n T_LOW = TL1;\n }\n if (ENQ) {\n ET = TX - START;\n if (!Q) {\n if (ET >= T_LOW) {\n Q = true;\n START = TX;\n TL = 0LL;\n } else {\n TL = ET;\n }\n } else {\n if (ET >= T_HIGH) {\n Q = false;\n START = TX;\n TH = 0LL;\n } else {\n TH = ET;\n }\n }\n } else {\n Q = false;\n TH = 0LL;\n TL = 0LL;\n START = TX;\n }\n}\n\n\nGEN_RDM::GEN_RDM()\n : AM(1)\n{\n // Initialize variables\n}\n\nvoid GEN_RDM::operator()() {\n TX = TO_TIME(T_PLC_MS()) - LAST;\n if (!INIT) {\n INIT = true;\n LAST = TX;\n TX = 0LL;\n }\n if (TX >= PT) {\n LAST = LAST + PT;\n TX = TX - PT;\n OUT = AM * (RDM(static_cast(0)) - 0.5) + OS;\n Q = true;\n } else {\n Q = false;\n }\n}\n\n\nGEN_RDT::GEN_RDT()\n : ENABLE(true), MIN_TIME_MS(1000000000LL), MAX_TIME_MS(1200000000LL), TP_Q(100000000LL)\n{\n // Initialize variables\n}\n\nvoid GEN_RDT::operator()() {\n TONRDMTIMER.IN = ENABLE;\n TONRDMTIMER.PT = TRDMTIME;\n TONRDMTIMER();\n TONRDMTIMER.ENO = true;\n TOF_XQ.IN = TONRDMTIMER.Q;\n TOF_XQ.PT = TP_Q;\n TOF_XQ();\n TOF_XQ.ENO = true;\n XQ = TOF_XQ.Q;\n if (TONRDMTIMER.Q) {\n XQ = true;\n RRDMTIME = RDM(RRDMTIME);\n TRDMTIME = TO_TIME(RRDMTIME * TO_REAL(TO_DINT(MAX_TIME_MS - MIN_TIME_MS) + TO_DINT(MIN_TIME_MS)));\n TONRDMTIMER.IN = false;\n TONRDMTIMER();\n TONRDMTIMER.ENO = true;\n }\n}\n\n\nGEN_RMP::GEN_RMP()\n : PT(1000000000LL), AM(1.0)\n{\n // Initialize variables\n}\n\nvoid GEN_RMP::operator()() {\n TX = TO_TIME(T_PLC_MS()) - LAST;\n DL = MODR(DL, 1.0);\n if (DL < 0.0) {\n DL = 1.0 - DL;\n }\n if (!INIT) {\n INIT = true;\n LAST = TX;\n TX = 0LL;\n }\n if (TX >= PT) {\n LAST = LAST + PT;\n TX = TX - PT;\n }\n LTEMP = TEMP;\n if (PT > 0LL) {\n TEMP = FRACT(TO_REAL(TX + MULTIME(PT, DL)) / TO_REAL(PT));\n }\n OUT = AM * TEMP + OS;\n Q = TEMP < LTEMP;\n}\n\n\nGEN_SIN::GEN_SIN()\n : AM(1.0)\n{\n // Initialize variables\n}\n\nvoid GEN_SIN::operator()() {\n TX = TO_TIME(T_PLC_MS()) - LAST;\n DL = MODR(DL, 1.0);\n if (DL < 0.0) {\n DL = 1.0 - DL;\n }\n if (!INIT) {\n INIT = true;\n LAST = TX;\n TX = 0LL;\n }\n if (TX >= PT) {\n LAST = LAST + PT;\n TX = TX - PT;\n }\n if (PT > 0LL) {\n TEMP = SIN(MATH.PI2 * TO_REAL(TO_DWORD(TX + MULTIME(PT, DL))) / TO_REAL(TO_DWORD(PT)));\n }\n OUT = AM * 0.5 * TEMP + OS;\n Q = !SIGN_R(TEMP);\n}\n\n\nGEN_SQ::GEN_SQ() {\n // Initialize variables\n}\n\nvoid GEN_SQ::operator()() {\n TX = T_PLC_MS();\n if (!INIT) {\n INIT = true;\n TN = TX;\n Q = true;\n } else if (TX - TN >= SHR(TO_DWORD(PT), 1)) {\n Q = !Q;\n TN = TN + SHR(TO_DWORD(PT), 1);\n }\n}\n\n\nGEN_SQR::GEN_SQR()\n : AM(1.0), DC(0.5)\n{\n // Initialize variables\n}\n\nvoid GEN_SQR::operator()() {\n if (DC == 0.0) {\n OUT = -AM * 0.5 + OS;\n Q = false;\n return;\n } else if (DC == 1.0) {\n OUT = AM * 0.5 + OS;\n Q = true;\n return;\n }\n TX = TO_TIME(T_PLC_MS()) - LAST;\n DL = MODR(DL, 1.0);\n if (DL < 0.0) {\n DL = 1.0 - DL;\n }\n DC = MODR(DC, 1.0);\n if (DC < 0.0) {\n DC = 1.0 - DC;\n }\n if (!INIT) {\n INIT = true;\n LAST = TX;\n TX = 0LL;\n }\n if (TX >= PT) {\n LAST = LAST + PT;\n TX = TX - PT;\n }\n if (MULTIME(PT, DL + DC) >= PT) {\n if (TX >= MULTIME(PT, DL + DC - 1)) {\n OUT = -AM * 0.5 + OS;\n Q = false;\n }\n if (TX >= MULTIME(PT, DL)) {\n OUT = AM * 0.5 + OS;\n Q = true;\n }\n } else {\n if (TX >= MULTIME(PT, DL)) {\n OUT = AM * 0.5 + OS;\n Q = true;\n }\n if (TX >= MULTIME(PT, DL + DC)) {\n OUT = -AM * 0.5 + OS;\n Q = false;\n }\n }\n}\n\n\nHOLIDAY::HOLIDAY()\n : SIZE(29)\n{\n // Initialize variables\n}\n\nvoid HOLIDAY::operator()() {\n if (LAST_ACTIVE == DATE_IN) {\n return;\n }\n LAST_ACTIVE = DATE_IN;\n if (LANGU == 0) {\n LX = LANGUAGE.DEFAULT;\n } else {\n LX = MIN(LANGUAGE.LMAX, LANGU);\n }\n JAHR = YEAR_OF_DATE(DATE_IN);\n OSTERN = EASTER(JAHR);\n WDX = DAY_OF_WEEK(DATE_IN);\n Y = false;\n for (I = 0; I <= SIZE; I++) {\n X_DATE = SET_DATE(JAHR, static_cast(HOLIDAYS[I].MONTH), static_cast(HOLIDAYS[I].DAY));\n if ((HOLIDAYS[I].USE == 1) & (HOLIDAYS[I].MONTH > 0)) {\n if (X_DATE == DATE_IN) {\n Y = true;\n NAME = HOLIDAYS[I].NAME;\n return;\n }\n } else if ((HOLIDAYS[I].USE == 1) & (HOLIDAYS[I].MONTH == 0)) {\n if (DATE_ADD(OSTERN, static_cast(HOLIDAYS[I].DAY), 0, 0, 0) == DATE_IN) {\n Y = true;\n NAME = HOLIDAYS[I].NAME;\n return;\n }\n } else if (HOLIDAYS[I].USE < 0) {\n if (((DAY_OF_WEEK(DATE_IN) == ABS(HOLIDAYS[I].USE)) & (DATE_IN < X_DATE)) & (DATE_IN >= DATE_ADD(X_DATE, -7, 0, 0, 0))) {\n Y = true;\n NAME = HOLIDAYS[I].NAME;\n return;\n }\n }\n }\n if ((!Y) & (((((WDX == 5) & (FRIDAY)) | ((WDX == 6) & (SATURDAY))) | ((WDX == 7) & (SUNDAY))))) {\n Y = true;\n NAME = LANGUAGE.WEEKDAYS(LOCATION.LANGUAGE[LX], WDX);\n } else {\n NAME = \"\";\n }\n}\n\n\nHYST::HYST() {\n // Initialize variables\n}\n\nvoid HYST::operator()() {\n if (ON >= OFF) {\n if (IN < OFF) {\n Q = false;\n WIN = false;\n } else if (IN > ON) {\n Q = true;\n WIN = false;\n } else {\n WIN = true;\n }\n } else {\n if (IN > OFF) {\n Q = false;\n WIN = false;\n } else if (IN < ON) {\n Q = true;\n WIN = false;\n } else {\n WIN = true;\n }\n }\n}\n\n\nHYST_1::HYST_1() {\n // Initialize variables\n}\n\nvoid HYST_1::operator()() {\n if (IN < LOW) {\n Q = false;\n WIN = false;\n } else if (IN > HIGH) {\n Q = true;\n WIN = false;\n } else {\n WIN = true;\n }\n}\n\n\nHYST_2::HYST_2() {\n // Initialize variables\n}\n\nvoid HYST_2::operator()() {\n TMP = VAL - HYS * 0.5;\n if (IN < TMP) {\n Q = false;\n WIN = false;\n } else if (IN > TMP + HYS) {\n Q = true;\n WIN = false;\n } else {\n WIN = true;\n }\n}\n\n\nHYST_3::HYST_3() {\n // Initialize variables\n}\n\nvoid HYST_3::operator()() {\n X = HYST * 0.5;\n if (IN < VAL1 - X) {\n Q1 = true;\n } else if (IN > VAL1 + X) {\n Q1 = false;\n }\n if (IN < VAL2 - X) {\n Q2 = false;\n } else if (IN > VAL2 + X) {\n Q2 = true;\n }\n}\n\n\nINC_DEC::INC_DEC() {\n // Initialize variables\n}\n\nvoid INC_DEC::operator()() {\n AXB = (CHA) ^ (CHB);\n CLKA = (CHA) ^ (EDGEA);\n EDGEA = CHA;\n CLKB = (CHB) ^ (EDGEB);\n EDGEB = CHB;\n CLK = (CLKA) | (CLKB);\n if ((AXB) & (CLKA)) {\n DIR = true;\n }\n if ((AXB) & (CLKB)) {\n DIR = false;\n }\n if ((CLK) & (DIR)) {\n CNT = CNT + 1;\n }\n if ((CLK) & (!DIR)) {\n CNT = CNT - 1;\n }\n if (RST) {\n CNT = 0;\n }\n}\n\n\nINTEGRATE::INTEGRATE()\n : E(true), K(1.0)\n{\n // Initialize variables\n}\n\nvoid INTEGRATE::operator()() {\n TX = T_PLC_MS();\n if (!INIT) {\n INIT = true;\n X_LAST = X;\n } else if (E) {\n Y = (X + X_LAST) * 0.0005 * TO_REAL(TX - LAST) * K + Y;\n X_LAST = X;\n }\n LAST = TX;\n}\n\n\nINTERLOCK::INTERLOCK() {\n // Initialize variables\n}\n\nvoid INTERLOCK::operator()() {\n T1.IN = I1;\n T1.PT = TL;\n T1();\n T1.ENO = true;\n T2.IN = I2;\n T2.PT = TL;\n T2();\n T2.ENO = true;\n Q1 = (I1) & (!T2.Q);\n Q2 = (I2) & (!T1.Q);\n}\n\n\nINTERLOCK_4::INTERLOCK_4() {\n // Initialize variables\n}\n\nvoid INTERLOCK_4::operator()() {\n if (E) {\n if (MODE != LMODE) {\n OUT = 0;\n LAST = 0;\n OLD = 0;\n LMODE = MODE;\n }\n IN = (IN & ~(1ULL << 0)) | ((I0 ? 1ULL : 0ULL) << 0);\n IN = (IN & ~(1ULL << 1)) | ((I1 ? 1ULL : 0ULL) << 1);\n IN = (IN & ~(1ULL << 2)) | ((I2 ? 1ULL : 0ULL) << 2);\n IN = (IN & ~(1ULL << 3)) | ((I3 ? 1ULL : 0ULL) << 3);\n if (IN != LAST) {\n switch (MODE) {\n case 0:\n OUT = IN;\n break;\n case 1:\n if (((static_cast(IN) >> 3) & 1)) {\n OUT = 8;\n } else if (((static_cast(IN) >> 2) & 1)) {\n OUT = 4;\n } else if (((static_cast(IN) >> 1) & 1)) {\n OUT = 2;\n } else {\n OUT = IN;\n }\n break;\n case 2:\n LAST = ((((IN) ^ (LAST))) & (IN));\n if (((static_cast(LAST) >> 3) & 1)) {\n OUT = 8;\n } else if (((static_cast(LAST) >> 2) & 1)) {\n OUT = 4;\n } else if (((static_cast(LAST) >> 1) & 1)) {\n OUT = 2;\n } else {\n OUT = LAST;\n }\n break;\n case 3:\n if (((OUT) & (IN)) == 0) {\n if (((static_cast(IN) >> 3) & 1)) {\n OUT = 8;\n } else if (((static_cast(IN) >> 2) & 1)) {\n OUT = 4;\n } else if (((static_cast(IN) >> 1) & 1)) {\n OUT = 2;\n } else {\n OUT = IN;\n }\n }\n break;\n }\n LAST = IN;\n }\n TP = OUT != OLD;\n OLD = OUT;\n } else {\n OUT = 0;\n LAST = 0;\n OLD = 0;\n LMODE = 0;\n TP = false;\n }\n}\n\n\nLENGTH::LENGTH() {\n // Initialize variables\n}\n\nvoid LENGTH::operator()() {\n YM = M + P * 0.000376065 + IN * 0.0254 + FT * 0.3048 + YD * 0.9144 + MILE * 1609.344 + SM * 1852.0 + FM * 1.829;\n YP = YM * 2659.11478068951;\n YIN = YM * 39.37007874016;\n YFT = YM * 3.28083989501;\n YYD = YM * 1.09361329834;\n YMILE = YM * 0.00062137119;\n YSM = YM * 0.0005399568;\n YFM = YM * 0.54674685621;\n}\n\n\nLIST_NEXT::LIST_NEXT()\n : POS(1)\n{\n // Initialize variables\n}\n\nvoid LIST_NEXT::operator()() {\n PT = &(LIST);\n PO = &(LEL);\n if (RST) {\n POS = 1;\n }\n if (((*PT)[POS] == 0) | (POS == LIST_LENGTH)) {\n LEL = \"\";\n NUL = true;\n } else {\n NUL = false;\n WRITE = 1;\n for (POS = POS + 1; POS <= LIST_LENGTH; POS++) {\n C = (*PT)[POS];\n if ((C == 0) | (C == SEP)) {\n (*PO)[WRITE] = 0;\n return;\n } else {\n (*PO)[WRITE] = (*PT)[POS];\n WRITE = WRITE + 1;\n }\n }\n }\n}\n\n\nLTCH::LTCH() {\n // Initialize variables\n}\n\nvoid LTCH::operator()() {\n if (RST) {\n Q = false;\n } else if (L) {\n Q = D;\n }\n}\n\n\nLTCH_4::LTCH_4() {\n // Initialize variables\n}\n\nvoid LTCH_4::operator()() {\n if (RST) {\n Q0 = false;\n Q1 = false;\n Q2 = false;\n Q3 = false;\n } else if (L) {\n Q0 = D0;\n Q1 = D1;\n Q2 = D2;\n Q3 = D3;\n }\n}\n\n\nMANUAL_1::MANUAL_1() {\n // Initialize variables\n}\n\nvoid MANUAL_1::operator()() {\n if (!MAN) {\n Q = IN;\n STATUS = 100;\n EDGE = false;\n } else if ((!S_EDGE) & (SET)) {\n Q = true;\n EDGE = true;\n STATUS = 101;\n } else if ((!R_EDGE) & (RST)) {\n Q = false;\n EDGE = true;\n STATUS = 102;\n } else if (!EDGE) {\n Q = M_I;\n STATUS = 103;\n }\n S_EDGE = SET;\n R_EDGE = RST;\n}\n\n\nMANUAL_2::MANUAL_2() {\n // Initialize variables\n}\n\nvoid MANUAL_2::operator()() {\n if (ENA) {\n if ((!ON) & (!OFF)) {\n Q = IN;\n STATUS = 100;\n } else if ((ON) & (!OFF)) {\n Q = true;\n STATUS = 101;\n } else if ((!ON) & (OFF)) {\n Q = false;\n STATUS = 102;\n } else {\n Q = MAN;\n STATUS = 103;\n }\n } else {\n Q = false;\n STATUS = 104;\n }\n}\n\n\nMANUAL_4::MANUAL_4() {\n // Initialize variables\n}\n\nvoid MANUAL_4::operator()() {\n if (MAN) {\n if (!TOG) {\n Q0 = M0;\n Q1 = M1;\n Q2 = M2;\n Q3 = M3;\n STATUS = 101;\n }\n if ((STP) & (!EDGE)) {\n TOG = true;\n switch (POS) {\n case 0:\n Q0 = true;\n Q1 = false;\n Q2 = false;\n Q3 = false;\n STATUS = 110;\n break;\n case 1:\n Q0 = false;\n Q1 = true;\n Q2 = false;\n Q3 = false;\n STATUS = 111;\n break;\n case 2:\n Q0 = false;\n Q1 = false;\n Q2 = true;\n Q3 = false;\n STATUS = 112;\n break;\n case 3:\n Q0 = false;\n Q1 = false;\n Q2 = false;\n Q3 = true;\n STATUS = 113;\n break;\n }\n POS = INC(POS, 1, 3);\n }\n } else {\n Q0 = I0;\n Q1 = I1;\n Q2 = I2;\n Q3 = I3;\n STATUS = 100;\n TOG = false;\n POS = 0;\n }\n EDGE = STP;\n}\n\n\nMATRIX::MATRIX()\n : Y1(true)\n{\n // Initialize variables\n}\n\nvoid MATRIX::operator()() {\n TP = false;\n CODE = 0;\n X[LINE] = (X[LINE] & ~(1ULL << 0)) | ((X1 ? 1ULL : 0ULL) << 0);\n X[LINE] = (X[LINE] & ~(1ULL << 1)) | ((X2 ? 1ULL : 0ULL) << 1);\n X[LINE] = (X[LINE] & ~(1ULL << 2)) | ((X3 ? 1ULL : 0ULL) << 2);\n X[LINE] = (X[LINE] & ~(1ULL << 3)) | ((X4 ? 1ULL : 0ULL) << 3);\n X[LINE] = (X[LINE] & ~(1ULL << 4)) | ((X5 ? 1ULL : 0ULL) << 4);\n for (I = 0; I <= 3; I++) {\n if (X[I] != L[I]) {\n TEMP = (X[I]) ^ (L[I]);\n if (((static_cast(TEMP) >> 0) & 1)) {\n CODE = 1;\n CODE = (CODE & ~(1ULL << 7)) | ((((static_cast(X[I]) >> 0) & 1) ? 1ULL : 0ULL) << 7);\n L[I] = (L[I] & ~(1ULL << 0)) | ((((static_cast(X[I]) >> 0) & 1) ? 1ULL : 0ULL) << 0);\n } else if (((static_cast(TEMP) >> 1) & 1)) {\n CODE = 2;\n CODE = (CODE & ~(1ULL << 7)) | ((((static_cast(X[I]) >> 1) & 1) ? 1ULL : 0ULL) << 7);\n L[I] = (L[I] & ~(1ULL << 1)) | ((((static_cast(X[I]) >> 1) & 1) ? 1ULL : 0ULL) << 1);\n } else if (((static_cast(TEMP) >> 2) & 1)) {\n CODE = 3;\n CODE = (CODE & ~(1ULL << 7)) | ((((static_cast(X[I]) >> 2) & 1) ? 1ULL : 0ULL) << 7);\n L[I] = (L[I] & ~(1ULL << 2)) | ((((static_cast(X[I]) >> 2) & 1) ? 1ULL : 0ULL) << 2);\n } else if (((static_cast(TEMP) >> 3) & 1)) {\n CODE = 4;\n CODE = (CODE & ~(1ULL << 7)) | ((((static_cast(X[I]) >> 3) & 1) ? 1ULL : 0ULL) << 7);\n L[I] = (L[I] & ~(1ULL << 3)) | ((((static_cast(X[I]) >> 3) & 1) ? 1ULL : 0ULL) << 3);\n } else if (((static_cast(TEMP) >> 4) & 1)) {\n CODE = 5;\n CODE = (CODE & ~(1ULL << 7)) | ((((static_cast(X[I]) >> 4) & 1) ? 1ULL : 0ULL) << 7);\n L[I] = (L[I] & ~(1ULL << 4)) | ((((static_cast(X[I]) >> 4) & 1) ? 1ULL : 0ULL) << 4);\n }\n TP = true;\n CODE = (CODE & ~(1ULL << 4)) | ((((static_cast(LINE) >> 0) & 1) ? 1ULL : 0ULL) << 4);\n CODE = (CODE & ~(1ULL << 5)) | ((((static_cast(LINE) >> 1) & 1) ? 1ULL : 0ULL) << 5);\n CODE = (CODE & ~(1ULL << 6)) | ((((static_cast(LINE) >> 2) & 1) ? 1ULL : 0ULL) << 6);\n if ((!RELEASE) & (CODE < 127)) {\n CODE = 0;\n TP = false;\n }\n goto __strucpp_loop_exit_10;\n }\n }\n __strucpp_loop_exit_10: ;\n LINE = ((LINE + 1)) & (0b00000011);\n TEMP = SHL(static_cast(1), LINE);\n Y1 = ((static_cast(TEMP) >> 0) & 1);\n Y2 = ((static_cast(TEMP) >> 1) & 1);\n Y3 = ((static_cast(TEMP) >> 2) & 1);\n Y4 = ((static_cast(TEMP) >> 3) & 1);\n}\n\n\nMESSAGE_4R::MESSAGE_4R()\n : MM(3), ENQ(true), CLK(true), T1(3000000000LL)\n{\n // Initialize variables\n}\n\nvoid MESSAGE_4R::operator()() {\n TR = false;\n if (ENQ) {\n if ((((!EDGE) & (CLK))) | (TIMER.Q)) {\n MN = INC1(MN, MM);\n TR = true;\n TIMER.IN = false;\n TIMER();\n TIMER.ENO = true;\n switch (MN) {\n case 0:\n MX = M0;\n break;\n case 1:\n MX = M1;\n break;\n case 2:\n MX = M2;\n break;\n case 3:\n MX = M3;\n break;\n }\n }\n EDGE = CLK;\n TIMER.IN = CLK;\n TIMER.PT = T1;\n TIMER();\n TIMER.ENO = true;\n } else {\n MX = \"\";\n MN = 0;\n }\n}\n\n\nMESSAGE_8::MESSAGE_8() {\n // Initialize variables\n}\n\nvoid MESSAGE_8::operator()() {\n if (IN1) {\n M = S1;\n } else if (IN2) {\n M = S2;\n } else if (IN3) {\n M = S3;\n } else if (IN4) {\n M = S4;\n } else if (IN5) {\n M = S5;\n } else if (IN6) {\n M = S6;\n } else if (IN7) {\n M = S7;\n } else if (IN8) {\n M = S8;\n } else {\n M = \"\";\n }\n}\n\n\nMETER::METER()\n : D(1.0)\n{\n // Initialize variables\n}\n\nvoid METER::operator()() {\n TX = T_PLC_MS();\n if (!INIT) {\n INIT = true;\n LAST = TX;\n MR.RX = MX;\n MR.R1 = 0.0;\n } else if (TX == LAST) {\n return;\n } else {\n TC = TO_REAL(TX - LAST) * 0.001;\n }\n LAST = TX;\n if (RST) {\n MR.R1 = 0.0;\n MR.RX = 0.0;\n } else {\n if (I1) {\n MX1 = M1;\n } else {\n MX1 = 0.0;\n }\n if (I2) {\n MX2 = M2;\n } else {\n MX2 = 0.0;\n }\n MR = R2_ADD(MR, (SEL(I1, 0.0, MX1) + SEL(I2, 0.0, MX2)) / D * TC);\n MX = MR.RX;\n }\n}\n\n\nMETER_STAT::METER_STAT() {\n // Initialize variables\n}\n\nvoid METER_STAT::operator()() {\n if (RST) {\n LAST_DAY = 0.0;\n CURRENT_DAY = 0.0;\n DAY_START = IN;\n LAST_WEEK = 0.0;\n CURRENT_WEEK = 0.0;\n WEEK_START = IN;\n LAST_MONTH = 0.0;\n CURRENT_MONTH = 0.0;\n MONTH_START = IN;\n LAST_YEAR = 0.0;\n CURRENT_YEAR = 0.0;\n YEAR_START = IN;\n } else {\n CURRENT_DAY = IN - DAY_START;\n CURRENT_WEEK = IN - WEEK_START;\n CURRENT_MONTH = IN - MONTH_START;\n CURRENT_YEAR = IN - YEAR_START;\n }\n if (YEAR_OF_DATE(DI) > YEAR_OF_DATE(LAST_RUN)) {\n LAST_YEAR = CURRENT_YEAR;\n CURRENT_YEAR = 0.0;\n YEAR_START = IN;\n LAST_MONTH = CURRENT_MONTH;\n CURRENT_MONTH = 0.0;\n MONTH_START = IN;\n LAST_DAY = CURRENT_DAY;\n CURRENT_DAY = 0.0;\n DAY_START = IN;\n } else if (MONTH_OF_DATE(DI) > MONTH_OF_DATE(LAST_RUN)) {\n LAST_MONTH = CURRENT_MONTH;\n CURRENT_MONTH = 0.0;\n MONTH_START = IN;\n LAST_DAY = CURRENT_DAY;\n CURRENT_DAY = 0.0;\n DAY_START = IN;\n } else if (DAY_OF_YEAR(DI) > DAY_OF_YEAR(LAST_RUN)) {\n LAST_DAY = CURRENT_DAY;\n CURRENT_DAY = 0.0;\n DAY_START = IN;\n }\n if (DAY_OF_WEEK(DI) < DAY_OF_WEEK(LAST_RUN)) {\n LAST_WEEK = CURRENT_WEEK;\n CURRENT_WEEK = 0.0;\n WEEK_START = IN;\n }\n LAST_RUN = DI;\n}\n\n\nM_D::M_D()\n : TMAX(864000000000000LL)\n{\n // Initialize variables\n}\n\nvoid M_D::operator()() {\n if ((RST) | (ET >= TMAX)) {\n PT = 0LL;\n ET = 0LL;\n STARTUP = false;\n RUN = false;\n }\n if (!STARTUP) {\n EDGE = START;\n STARTUP = true;\n }\n TX = TO_TIME(T_PLC_MS());\n if (((START) & (!EDGE)) & (!STOP)) {\n T0 = TX;\n RUN = true;\n PT = 0LL;\n } else if ((STOP) & (RUN)) {\n PT = ET;\n RUN = false;\n }\n EDGE = START;\n if (RUN) {\n ET = TX - T0;\n }\n}\n\n\nM_T::M_T()\n : TMAX(864000000000000LL)\n{\n // Initialize variables\n}\n\nvoid M_T::operator()() {\n TX = TO_TIME(T_PLC_MS());\n if ((RST) | (ET >= TMAX)) {\n PT = 0LL;\n ET = 0LL;\n } else if (IN) {\n if (!EDGE) {\n START = TX;\n }\n ET = TX - START;\n } else {\n PT = ET;\n }\n EDGE = IN;\n}\n\n\nM_TX::M_TX()\n : TMAX(864000000000000LL)\n{\n // Initialize variables\n}\n\nvoid M_TX::operator()() {\n if ((RST) | ((ET >= TMAX))) {\n RISE = false;\n FALL = false;\n STARTUP = false;\n TH = 0LL;\n TL = 0LL;\n DC = 0.0;\n F = 0.0;\n ET = 0LL;\n }\n if (!STARTUP) {\n EDGE = IN;\n STARTUP = true;\n }\n TX = TO_TIME(T_PLC_MS());\n if ((IN) ^ (EDGE)) {\n EDGE = IN;\n if (IN) {\n START = TX;\n RISE = true;\n if (FALL) {\n TL = START - STOP;\n }\n if ((TH > 0LL) & (TL > 0LL)) {\n DC = TO_REAL(TH) / TO_REAL(TH + TL);\n F = 1000.0 / TO_REAL(TH + TL);\n }\n } else {\n STOP = TX;\n FALL = true;\n if (RISE) {\n TH = STOP - START;\n }\n if ((TH > 0LL) & (TL > 0LL)) {\n DC = TO_REAL(TH) / TO_REAL(TH + TL);\n F = 1000.0 / TO_REAL(TH + TL);\n }\n }\n }\n if (RISE) {\n ET = TX - START;\n }\n}\n\n\nONTIME::ONTIME() {\n // Initialize variables\n}\n\nvoid ONTIME::operator()() {\n TX = T_PLC_MS();\n if (!INIT) {\n INIT = true;\n LAST = TX;\n MS = 0;\n }\n if (RST) {\n SECONDS = 0;\n CYCLES = 0;\n LAST = TX;\n MS = 0;\n } else if (IN) {\n MS = (TX - LAST) + MS;\n if (MS >= 1000) {\n SECONDS = SECONDS + 1;\n MS = MS - 1000;\n }\n CYCLES = CYCLES + TO_UINT(!EDGE);\n }\n LAST = TX;\n EDGE = IN;\n}\n\n\nPARSET::PARSET() {\n // Initialize variables\n}\n\nvoid PARSET::operator()() {\n TX = T_PLC_MS();\n if (!INIT) {\n SET = (SET & ~(1ULL << 0)) | ((!A0 ? 1ULL : 0ULL) << 0);\n INIT = true;\n X(0, 1) = X01;\n X(0, 2) = X02;\n X(0, 3) = X03;\n X(0, 4) = X04;\n X(1, 1) = X11;\n X(1, 2) = X12;\n X(1, 3) = X13;\n X(1, 4) = X14;\n X(2, 1) = X21;\n X(2, 2) = X22;\n X(2, 3) = X23;\n X(2, 4) = X24;\n X(3, 1) = X31;\n X(3, 2) = X32;\n X(3, 3) = X33;\n X(3, 4) = X34;\n P1 = X01;\n P2 = X02;\n P3 = X03;\n P4 = X04;\n }\n if ((((A0) ^ (((static_cast(SET) >> 0) & 1)))) | (((A1) ^ (((static_cast(SET) >> 1) & 1))))) {\n SET = (SET & ~(1ULL << 0)) | ((A0 ? 1ULL : 0ULL) << 0);\n SET = (SET & ~(1ULL << 1)) | ((A1 ? 1ULL : 0ULL) << 1);\n if (TC > 0LL) {\n START = true;\n LAST = TX;\n S1 = (X(SET, 1) - P1) / TO_REAL(TO_DWORD(TC));\n S2 = (X(SET, 2) - P2) / TO_REAL(TO_DWORD(TC));\n S3 = (X(SET, 3) - P3) / TO_REAL(TO_DWORD(TC));\n S4 = (X(SET, 4) - P4) / TO_REAL(TO_DWORD(TC));\n }\n } else if ((START) & (TX - LAST < TO_DWORD(TC))) {\n P1 = X(SET, 1) - S1 * TO_REAL(TO_DWORD(TC) - TX + LAST);\n P2 = X(SET, 2) - S2 * TO_REAL(TO_DWORD(TC) - TX + LAST);\n P3 = X(SET, 3) - S3 * TO_REAL(TO_DWORD(TC) - TX + LAST);\n P4 = X(SET, 4) - S4 * TO_REAL(TO_DWORD(TC) - TX + LAST);\n } else {\n START = false;\n P1 = X(SET, 1);\n P2 = X(SET, 2);\n P3 = X(SET, 3);\n P4 = X(SET, 4);\n }\n}\n\n\nPIN_CODE::PIN_CODE()\n : POS(1)\n{\n // Initialize variables\n}\n\nvoid PIN_CODE::operator()() {\n TP = false;\n if (E) {\n if (CB == CODE(PIN, POS)) {\n POS = POS + 1;\n if (POS > LEN(PIN)) {\n TP = true;\n POS = 1;\n }\n } else {\n POS = 1;\n }\n }\n}\n\n\nPRESSURE::PRESSURE() {\n // Initialize variables\n}\n\nvoid PRESSURE::operator()() {\n YBAR = BAR + PA * 0.00001 + 0.980665 * ATT + 1.01325 * ATM + 0.001333224 * TORR + 0.0980665 * MWS;\n YMWS = YBAR * 10.1971621297793;\n YTORR = YBAR * 750.061505043414;\n YATT = YBAR * 1.0197162129779;\n YATM = YBAR * 0.986923266716;\n YPA = YBAR * 100000.0;\n}\n\n\nRTC_MS::RTC_MS() {\n // Initialize variables\n}\n\nvoid RTC_MS::operator()() {\n TX = T_PLC_MS();\n if ((SET) | (!INIT)) {\n INIT = true;\n XDT = SDT;\n XMS = SMS;\n } else {\n XMS = XMS + TO_INT(TX - LAST);\n if (XMS > 999) {\n XDT = XDT + 1000000000LL;\n XMS = XMS - 1000;\n }\n }\n LAST = TX;\n}\n\n\nSCHEDULER::SCHEDULER() {\n // Initialize variables\n}\n\nvoid SCHEDULER::operator()() {\n TX = TO_TIME(T_PLC_MS());\n if (!INIT) {\n INIT = true;\n S0 = TX - T0;\n S1 = TX - T1;\n S2 = TX - T2;\n S3 = TX - T3;\n }\n Q0 = false;\n Q1 = false;\n Q2 = false;\n Q3 = false;\n switch (C) {\n case 0:\n if (TX - S0 >= T0) {\n Q0 = E0;\n S0 = TX;\n }\n C = 1;\n break;\n case 1:\n if (TX - S1 >= T1) {\n Q1 = E1;\n S1 = TX;\n }\n C = 2;\n break;\n case 2:\n if (TX - S2 >= T2) {\n Q2 = E2;\n S2 = TX;\n }\n C = 3;\n break;\n case 3:\n if (TX - S3 >= T3) {\n Q3 = E3;\n S3 = TX;\n }\n C = 0;\n break;\n }\n}\n\n\nSCHEDULER_2::SCHEDULER_2() {\n // Initialize variables\n}\n\nvoid SCHEDULER_2::operator()() {\n Q0 = (E0) & ((SX % C0 - O0 == 0));\n Q1 = (E1) & ((SX % C1 - O1 == 0));\n Q2 = (E2) & ((SX % C2 - O2 == 0));\n Q3 = (E3) & ((SX % C3 - O3 == 0));\n SX = SX + 1;\n}\n\n\nSEL2_OF_3::SEL2_OF_3() {\n // Initialize variables\n}\n\nvoid SEL2_OF_3::operator()() {\n D12 = ABS(IN1 - IN2) <= D;\n D23 = ABS(IN2 - IN3) <= D;\n D31 = ABS(IN3 - IN1) <= D;\n if (((((D12) & (D23))) | (((D12) & (D31)))) | (((D23) & (D31)))) {\n Y = (IN1 + IN2 + IN3) * 0.333333333333;\n E = false;\n W = 0;\n } else if (D12) {\n Y = (IN1 + IN2) * 0.5;\n E = false;\n W = 3;\n } else if (D23) {\n Y = (IN2 + IN3) * 0.5;\n E = false;\n W = 1;\n } else if (D31) {\n Y = (IN3 + IN1) * 0.5;\n E = false;\n W = 2;\n } else {\n E = true;\n W = 4;\n }\n}\n\n\nSEL2_OF_3B::SEL2_OF_3B() {\n // Initialize variables\n}\n\nvoid SEL2_OF_3B::operator()() {\n Q = ((((IN1) & (IN2))) | (((IN1) & (IN3)))) | (((IN2) & (IN3)));\n TDEL.IN = ((((IN1) ^ (IN2))) | (((IN1) ^ (IN3)))) | (((IN2) ^ (IN3)));\n TDEL.PT = TD;\n TDEL();\n TDEL.ENO = true;\n W = TDEL.Q;\n}\n\n\nSELECT_8::SELECT_8() {\n // Initialize variables\n}\n\nvoid SELECT_8::operator()() {\n if (RST) {\n STATE = 0;\n } else if (SET) {\n STATE = IN;\n } else if ((UP) & (!LAST_UP)) {\n STATE = INC(STATE, 1, 7);\n } else if ((DN) & (!LAST_DN)) {\n STATE = INC(STATE, -1, 7);\n }\n LAST_UP = UP;\n LAST_DN = DN;\n Q0 = false;\n Q1 = false;\n Q2 = false;\n Q3 = false;\n Q4 = false;\n Q5 = false;\n Q6 = false;\n Q7 = false;\n if (E) {\n switch (STATE) {\n case 0:\n Q0 = true;\n break;\n case 1:\n Q1 = true;\n break;\n case 2:\n Q2 = true;\n break;\n case 3:\n Q3 = true;\n break;\n case 4:\n Q4 = true;\n break;\n case 5:\n Q5 = true;\n break;\n case 6:\n Q6 = true;\n break;\n case 7:\n Q7 = true;\n break;\n }\n }\n}\n\n\nSEQUENCE_4::SEQUENCE_4()\n : IN0(true), IN1(true), IN2(true), IN3(true), STEP(-1)\n{\n // Initialize variables\n}\n\nvoid SEQUENCE_4::operator()() {\n TX = TO_TIME(T_PLC_MS());\n if (!INIT) {\n LAST = TX;\n INIT = true;\n STATUS = 110;\n }\n if (RST) {\n STEP = -1;\n Q0 = 0;\n Q1 = 0;\n Q2 = 0;\n Q3 = 0;\n STATUS = 110;\n RUN = 0;\n } else if ((START) & (!EDGE)) {\n STEP = 0;\n LAST = TX;\n STATUS = 111;\n Q0 = 0;\n Q1 = 0;\n Q2 = 0;\n Q3 = 0;\n RUN = 1;\n }\n EDGE = START;\n if (((STATUS > 0) & (STATUS < 100)) & (STOP_ON_ERROR)) {\n return;\n }\n if ((RUN) & (STEP == 0)) {\n if (((!Q0) & (IN0)) & (TX - LAST <= WAIT0)) {\n Q0 = true;\n LAST = TX;\n } else if ((!Q0) & (TX - LAST > WAIT0)) {\n STATUS = 1;\n RUN = false;\n } else if ((Q0) & (TX - LAST >= DELAY0)) {\n STEP = 1;\n LAST = TX;\n }\n }\n if ((RUN) & (STEP == 1)) {\n if (((!Q1) & (IN1)) & (TX - LAST <= WAIT1)) {\n Q0 = false;\n Q1 = true;\n LAST = TX;\n } else if ((!Q1) & (TX - LAST > WAIT1)) {\n STATUS = 2;\n Q0 = false;\n RUN = false;\n } else if ((Q1) & (TX - LAST >= DELAY1)) {\n STEP = 2;\n LAST = TX;\n }\n }\n if ((RUN) & (STEP == 2)) {\n if (((!Q2) & (IN2)) & (TX - LAST <= WAIT2)) {\n Q1 = false;\n Q2 = true;\n LAST = TX;\n } else if ((!Q2) & (TX - LAST > WAIT2)) {\n STATUS = 3;\n Q1 = false;\n RUN = false;\n } else if ((Q2) & (TX - LAST >= DELAY2)) {\n STEP = 3;\n LAST = TX;\n }\n }\n if ((RUN) & (STEP == 3)) {\n if (((!Q3) & (IN3)) & (TX - LAST <= WAIT3)) {\n Q2 = false;\n Q3 = true;\n LAST = TX;\n } else if ((!Q3) & (TX - LAST > WAIT3)) {\n STATUS = 4;\n Q2 = false;\n RUN = false;\n } else if ((Q3) & (TX - LAST >= DELAY3)) {\n STEP = -1;\n Q3 = false;\n RUN = false;\n STATUS = 110;\n }\n }\n QX = (((Q0) | (Q1)) | (Q2)) | (Q3);\n}\n\n\nSEQUENCE_8::SEQUENCE_8()\n : IN0(true), IN1(true), IN2(true), IN3(true), IN4(true), IN5(true), IN6(true), IN7(true), STEP(-1)\n{\n // Initialize variables\n}\n\nvoid SEQUENCE_8::operator()() {\n TX = TO_TIME(T_PLC_MS());\n if (!INIT) {\n LAST = TX;\n INIT = true;\n STATUS = 110;\n }\n if (RST) {\n STEP = -1;\n Q0 = 0;\n Q1 = 0;\n Q2 = 0;\n Q3 = 0;\n Q4 = 0;\n Q5 = 0;\n Q6 = 0;\n Q7 = 0;\n STATUS = 110;\n RUN = 0;\n } else if ((START) & (!EDGE)) {\n STEP = 0;\n LAST = TX;\n STATUS = 111;\n Q0 = 0;\n Q1 = 0;\n Q2 = 0;\n Q3 = 0;\n Q4 = 0;\n Q5 = 0;\n Q6 = 0;\n Q7 = 0;\n RUN = 1;\n }\n EDGE = START;\n if (((STATUS > 0) & (STATUS < 100)) & (STOP_ON_ERROR)) {\n return;\n }\n if ((RUN) & (STEP == 0)) {\n if (((!Q0) & (IN0)) & (TX - LAST <= WAIT0)) {\n Q0 = true;\n LAST = TX;\n } else if ((!Q0) & (TX - LAST > WAIT0)) {\n STATUS = 1;\n RUN = false;\n } else if ((Q0) & (TX - LAST >= DELAY0)) {\n STEP = 1;\n LAST = TX;\n }\n }\n if ((RUN) & (STEP == 1)) {\n if (((!Q1) & (IN1)) & (TX - LAST <= WAIT1)) {\n Q0 = false;\n Q1 = true;\n LAST = TX;\n } else if ((!Q1) & (TX - LAST > WAIT1)) {\n STATUS = 2;\n Q0 = false;\n RUN = false;\n } else if ((Q1) & (TX - LAST >= DELAY1)) {\n STEP = 2;\n LAST = TX;\n }\n }\n if ((RUN) & (STEP == 2)) {\n if (((!Q2) & (IN2)) & (TX - LAST <= WAIT2)) {\n Q1 = false;\n Q2 = true;\n LAST = TX;\n } else if ((!Q2) & (TX - LAST > WAIT2)) {\n STATUS = 3;\n Q1 = false;\n RUN = false;\n } else if ((Q2) & (TX - LAST >= DELAY2)) {\n STEP = 3;\n LAST = TX;\n }\n }\n if ((RUN) & (STEP == 3)) {\n if (((!Q3) & (IN3)) & (TX - LAST <= WAIT3)) {\n Q2 = false;\n Q3 = true;\n LAST = TX;\n } else if ((!Q3) & (TX - LAST > WAIT3)) {\n STATUS = 4;\n Q2 = false;\n RUN = false;\n } else if ((Q3) & (TX - LAST >= DELAY3)) {\n STEP = 4;\n LAST = TX;\n }\n }\n if ((RUN) & (STEP == 4)) {\n if (((!Q4) & (IN4)) & (TX - LAST <= WAIT4)) {\n Q3 = false;\n Q4 = true;\n LAST = TX;\n } else if ((!Q4) & (TX - LAST > WAIT4)) {\n STATUS = 5;\n Q3 = false;\n RUN = false;\n } else if ((Q4) & (TX - LAST >= DELAY4)) {\n STEP = 5;\n LAST = TX;\n }\n }\n if ((RUN) & (STEP == 5)) {\n if (((!Q5) & (IN5)) & (TX - LAST <= WAIT5)) {\n Q4 = false;\n Q5 = true;\n LAST = TX;\n } else if ((!Q5) & (TX - LAST > WAIT5)) {\n STATUS = 6;\n Q4 = false;\n RUN = false;\n } else if ((Q5) & (TX - LAST >= DELAY5)) {\n STEP = 6;\n LAST = TX;\n }\n }\n if ((RUN) & (STEP == 6)) {\n if (((!Q6) & (IN6)) & (TX - LAST <= WAIT6)) {\n Q5 = false;\n Q6 = true;\n LAST = TX;\n } else if ((!Q6) & (TX - LAST > WAIT6)) {\n STATUS = 7;\n Q5 = false;\n RUN = false;\n } else if ((Q6) & (TX - LAST >= DELAY6)) {\n STEP = 7;\n LAST = TX;\n }\n }\n if ((RUN) & (STEP == 7)) {\n if (((!Q7) & (IN7)) & (TX - LAST <= WAIT7)) {\n Q6 = false;\n Q7 = true;\n LAST = TX;\n } else if ((!Q7) & (TX - LAST > WAIT7)) {\n STATUS = 8;\n Q6 = false;\n RUN = false;\n } else if ((Q7) & (TX - LAST >= DELAY7)) {\n STEP = -1;\n Q7 = false;\n RUN = false;\n STATUS = 110;\n }\n }\n QX = (((((((Q0) | (Q1)) | (Q2)) | (Q3)) | (Q4)) | (Q5)) | (Q6)) | (Q7);\n}\n\n\nSH::SH() {\n // Initialize variables\n}\n\nvoid SH::operator()() {\n if ((CLK) & (!EDGE)) {\n OUT = IN;\n TRIG = true;\n } else {\n TRIG = false;\n }\n EDGE = CLK;\n}\n\n\nSHR_4E::SHR_4E() {\n // Initialize variables\n}\n\nvoid SHR_4E::operator()() {\n TRIG.CLK = CLK;\n TRIG();\n TRIG.ENO = true;\n if ((SET) | (RST)) {\n Q0 = !RST;\n Q1 = Q0;\n Q2 = Q0;\n Q3 = Q0;\n } else if (TRIG.Q) {\n Q3 = Q2;\n Q2 = Q1;\n Q1 = Q0;\n Q0 = D0;\n }\n}\n\n\nSHR_4UDE::SHR_4UDE() {\n // Initialize variables\n}\n\nvoid SHR_4UDE::operator()() {\n TRIG.CLK = CLK;\n TRIG();\n TRIG.ENO = true;\n if ((SET) | (RST)) {\n Q0 = !RST;\n Q1 = Q0;\n Q2 = Q0;\n Q3 = Q0;\n } else if (TRIG.Q) {\n if (DN) {\n Q0 = Q1;\n Q1 = Q2;\n Q2 = Q3;\n Q3 = D3;\n } else {\n Q3 = Q2;\n Q2 = Q1;\n Q1 = Q0;\n Q0 = D0;\n }\n }\n}\n\n\nSHR_8PLE::SHR_8PLE()\n : UP(1), EDGE(1)\n{\n // Initialize variables\n}\n\nvoid SHR_8PLE::operator()() {\n if (((CLK) & (EDGE)) & (!RST)) {\n EDGE = false;\n if (UP) {\n REGISTER = SHL(REGISTER, 1);\n REGISTER = (REGISTER & ~(1ULL << 0)) | ((DIN ? 1ULL : 0ULL) << 0);\n DOUT = ((static_cast(REGISTER) >> 7) & 1);\n } else {\n REGISTER = SHR(REGISTER, 1);\n REGISTER = (REGISTER & ~(1ULL << 7)) | ((DIN ? 1ULL : 0ULL) << 7);\n DOUT = ((static_cast(REGISTER) >> 0) & 1);\n }\n if (LOAD) {\n REGISTER = DLOAD;\n if (UP) {\n DOUT = ((static_cast(REGISTER) >> 7) & 1);\n } else {\n DOUT = ((static_cast(REGISTER) >> 0) & 1);\n }\n }\n }\n if (!CLK) {\n EDGE = true;\n }\n if (RST) {\n REGISTER = 0;\n DOUT = false;\n }\n}\n\n\nSHR_8UDE::SHR_8UDE() {\n // Initialize variables\n}\n\nvoid SHR_8UDE::operator()() {\n TRIG.CLK = CLK;\n TRIG();\n TRIG.ENO = true;\n if ((SET) | (RST)) {\n Q0 = !RST;\n Q1 = Q0;\n Q2 = Q0;\n Q3 = Q0;\n Q4 = Q0;\n Q5 = Q0;\n Q6 = Q0;\n Q7 = Q0;\n } else if (TRIG.Q) {\n if (DN) {\n Q0 = Q1;\n Q1 = Q2;\n Q2 = Q3;\n Q3 = Q4;\n Q4 = Q5;\n Q5 = Q6;\n Q6 = Q7;\n Q7 = D7;\n } else {\n Q7 = Q6;\n Q6 = Q5;\n Q5 = Q4;\n Q4 = Q3;\n Q3 = Q2;\n Q2 = Q1;\n Q1 = Q0;\n Q0 = D0;\n }\n }\n}\n\n\nSH_1::SH_1() {\n // Initialize variables\n}\n\nvoid SH_1::operator()() {\n TX = TO_TIME(T_PLC_MS());\n if (TX - LAST >= PT) {\n LAST = TX;\n OUT = IN;\n TRIG = true;\n } else {\n TRIG = false;\n }\n}\n\n\nSH_2::SH_2()\n : N(16)\n{\n // Initialize variables\n}\n\nvoid SH_2::operator()() {\n TX = TO_TIME(T_PLC_MS());\n D2 = SHR(DISC, 1);\n if (TX - LAST >= PT) {\n LAST = TX;\n TRIG = true;\n M = LIMIT(1, N, 16);\n for (I = M - 1; I >= 1; I += -1) {\n BUF2[I] = BUF2[I - 1];\n }\n BUF2[0] = IN;\n OUT = IN;\n BUF = BUF2;\n for (START = 0; START <= M - 2; START++) {\n for (I = START + 1; I <= M - 1; I++) {\n if (BUF[START] > BUF[I]) {\n TEMP = BUF[START];\n BUF[START] = BUF[I];\n BUF[I] = TEMP;\n }\n }\n }\n STOP = M - 1 - D2;\n START = D2;\n if (!EVEN(static_cast(DISC))) {\n START = START + 1;\n }\n AVG = 0;\n for (I = START; I <= STOP; I++) {\n AVG = AVG + BUF[I];\n }\n AVG = AVG / TO_REAL(STOP - START + 1);\n LOW = BUF[START];\n HIGH = BUF[STOP];\n } else {\n TRIG = false;\n }\n}\n\n\nSH_T::SH_T() {\n // Initialize variables\n}\n\nvoid SH_T::operator()() {\n if (E) {\n OUT = IN;\n }\n}\n\n\nSIGNAL::SIGNAL()\n : ONE(1)\n{\n // Initialize variables\n}\n\nvoid SIGNAL::operator()() {\n if (IN) {\n TX = T_PLC_MS();\n if (TS > 0LL) {\n STEP = TO_BYTE((TX / TO_DWORD(TS)) & (0x00000007));\n } else {\n STEP = TO_BYTE((SHR(TX, 7)) & (0x00000007));\n }\n STEP = SHL(ONE, STEP);\n Q = ((STEP) & (SIG)) > 0;\n } else {\n Q = false;\n }\n}\n\n\nSPEED::SPEED() {\n // Initialize variables\n}\n\nvoid SPEED::operator()() {\n YMS = MS + KMH * 0.27777777777778 + KN * 0.5144444 + MH * 0.44704;\n YKMH = YMS * 3.6;\n YKN = YMS * 1.94384466037535;\n YMH = YMS * 2.2369362920544;\n}\n\n\nSTACK_16::STACK_16()\n : E(true), EMPTY(true), N(15)\n{\n // Initialize variables\n}\n\nvoid STACK_16::operator()() {\n if (RST) {\n PT = 0;\n EMPTY = true;\n FULL = false;\n DOUT = 0;\n } else if (E) {\n if ((!EMPTY) & (RD)) {\n PT = PT - 1;\n DOUT = STACK[PT];\n EMPTY = PT == 0;\n FULL = false;\n }\n if ((!FULL) & (WD)) {\n STACK[PT] = DIN;\n PT = PT + 1;\n FULL = PT > N;\n EMPTY = false;\n }\n }\n}\n\n\nSTACK_32::STACK_32()\n : E(true), EMPTY(true), N(31)\n{\n // Initialize variables\n}\n\nvoid STACK_32::operator()() {\n if (RST) {\n PT = 0;\n EMPTY = true;\n FULL = false;\n DOUT = 0;\n } else if (E) {\n if ((!EMPTY) & (RD)) {\n PT = PT - 1;\n DOUT = STACK[PT];\n EMPTY = PT == 0;\n FULL = false;\n }\n if ((!FULL) & (WD)) {\n STACK[PT] = DIN;\n PT = PT + 1;\n FULL = PT > N;\n EMPTY = false;\n }\n }\n}\n\n\nSTAIR2::STAIR2() {\n // Initialize variables\n}\n\nvoid STAIR2::operator()() {\n if (D > 0.0) {\n if ((X >= Y + D) | (X <= Y - D)) {\n Y = FLOOR(X / D) * D;\n }\n } else {\n Y = X;\n }\n}\n\n\nSTORE_8::STORE_8() {\n // Initialize variables\n}\n\nvoid STORE_8::operator()() {\n if ((RST) | (SET)) {\n Q0 = !RST;\n Q1 = Q0;\n Q2 = Q0;\n Q3 = Q0;\n Q4 = Q0;\n Q5 = Q0;\n Q6 = Q0;\n Q7 = Q0;\n } else {\n if (D0) {\n Q0 = true;\n }\n if (D1) {\n Q1 = true;\n }\n if (D2) {\n Q2 = true;\n }\n if (D3) {\n Q3 = true;\n }\n if (D4) {\n Q4 = true;\n }\n if (D5) {\n Q5 = true;\n }\n if (D6) {\n Q6 = true;\n }\n if (D7) {\n Q7 = true;\n }\n if ((CLR) & (!EDGE)) {\n if (Q0) {\n Q0 = false;\n } else if (Q1) {\n Q1 = false;\n } else if (Q2) {\n Q2 = false;\n } else if (Q3) {\n Q3 = false;\n } else if (Q4) {\n Q4 = false;\n } else if (Q5) {\n Q5 = false;\n } else if (Q6) {\n Q6 = false;\n } else {\n Q7 = false;\n }\n }\n EDGE = CLR;\n }\n}\n\n\nSUN_POS::SUN_POS() {\n // Initialize variables\n}\n\nvoid SUN_POS::operator()() {\n N = TO_REAL(TO_DWORD(UTC) - 946728000) * 0.000011574074074074;\n G = MODR(6.240040768 + 0.01720197 * N, MATH.PI2);\n D = MODR(4.89495042 + 0.017202792 * N, MATH.PI2) + 0.033423055 * SIN(G) + 0.000349066 * SIN(2.0 * G);\n E = 0.409087723 - 6.981317008e-9 * N;\n COS_D = COS(D);\n SIN_D = SIN(D);\n A = ATAN(COS(E) * SIN_D / COS_D);\n if (COS_D < 0.0) {\n A = A + MATH.PI;\n }\n C = ASIN(SIN(E) * SIN_D);\n TAU = RAD(MODR(6.697376 + (N - 0.25) * 0.0657098245037645 + TO_REAL(TO_DWORD(TO_TOD(UTC))) * 2.785383333e-7, 24.0) * 15.0 + LONGITUDE) - A;\n RLAT = RAD(LATITUDE);\n SIN_LAT = SIN(RLAT);\n COS_LAT = COS(RLAT);\n COS_TAU = COS(TAU);\n T1 = COS_TAU * SIN_LAT - TAN(C) * COS_LAT;\n B = ATAN(SIN(TAU) / T1);\n if (T1 < 0.0) {\n B = B + MATH.PI2;\n } else {\n B = B + MATH.PI;\n }\n B = DEG(MODR(B, MATH.PI2));\n H = DEG(ASIN(COS(C) * COS_TAU * COS_LAT + SIN(C) * SIN_LAT));\n if (H > 180.0) {\n H = H - 360.0;\n }\n HR = H + REFRACTION(H);\n}\n\n\nSUN_TIME::SUN_TIME()\n : H(-0.83333333333)\n{\n // Initialize variables\n}\n\nvoid SUN_TIME::operator()() {\n B = LATITUDE * 0.0174532925199433;\n MIDDAY = SUN_MIDDAY(LONGITUDE, UTC);\n DK = 0.40954 * SIN(0.0172 * (TO_REAL(DAY_OF_YEAR(UTC)) - 79.35));\n SUN_DECLINATION = DEG(DK);\n if (SUN_DECLINATION > 180.0) {\n SUN_DECLINATION = SUN_DECLINATION - 360.0;\n }\n SUN_DECLINATION = 90.0 - LATITUDE + SUN_DECLINATION;\n DELTA = HOUR_TO_TIME(ACOS((SIN(RAD(H)) - SIN(B) * SIN(DK)) / (COS(B) * COS(DK))) * 3.819718632);\n SUN_RISE = MIDDAY - DELTA;\n SUN_SET = MIDDAY + DELTA;\n}\n\n\nTC_MS::TC_MS() {\n // Initialize variables\n}\n\nvoid TC_MS::operator()() {\n TX = T_PLC_MS();\n if (!INIT) {\n INIT = true;\n TC = 0;\n } else {\n TC = TX - LAST;\n }\n LAST = TX;\n}\n\n\nTC_S::TC_S() {\n // Initialize variables\n}\n\nvoid TC_S::operator()() {\n TX = T_PLC_US();\n if (!INIT) {\n INIT = true;\n TC = 0.0;\n } else {\n TC = TO_REAL(TX - LAST) * 0.000001;\n }\n LAST = TX;\n}\n\n\nTC_US::TC_US() {\n // Initialize variables\n}\n\nvoid TC_US::operator()() {\n TX = T_PLC_US();\n if (!INIT) {\n INIT = true;\n TC = 0;\n } else {\n TC = TX - LAST;\n }\n LAST = TX;\n}\n\n\nTEMPERATURE::TEMPERATURE()\n : C(-273.15), F(-459.67), RE(-218.52)\n{\n // Initialize variables\n}\n\nvoid TEMPERATURE::operator()() {\n YK = K + (C + 273.15) + (F + 459.67) * 0.555555555555 + (RE * 1.25 + 273.15) + (RA * 0.555555555555);\n YC = YK - 273.15;\n YF = YK * 1.8 - 459.67;\n YRE = (YK - 273.15) * 0.8;\n YRA = YK * 1.8;\n}\n\n\nTICKER::TICKER() {\n // Initialize variables\n}\n\nvoid TICKER::operator()() {\n if (N < LEN(TEXT)) {\n if (!DELAY.Q) {\n STEP = STEP + 1;\n if (STEP > LEN(TEXT)) {\n STEP = 1;\n }\n DISPLAY = MID(TEXT, N, STEP);\n DELAY.IN = true;\n DELAY.PT = PT;\n DELAY();\n DELAY.ENO = true;\n } else {\n DELAY.IN = false;\n DELAY();\n DELAY.ENO = true;\n }\n } else {\n DISPLAY = TEXT;\n }\n}\n\n\nTOGGLE::TOGGLE() {\n // Initialize variables\n}\n\nvoid TOGGLE::operator()() {\n if (RST) {\n Q = 0;\n } else if ((CLK) & (!EDGE)) {\n Q = !Q;\n }\n EDGE = CLK;\n}\n\n\nTONOF::TONOF() {\n // Initialize variables\n}\n\nvoid TONOF::operator()() {\n if ((IN) ^ (OLD)) {\n X.IN = false;\n X.PT = SEL(IN, T_OFF, T_ON);\n X();\n X.ENO = true;\n MODE = IN;\n OLD = IN;\n }\n X.IN = true;\n X();\n X.ENO = true;\n if (X.Q) {\n Q = MODE;\n }\n}\n\n\nTP_X::TP_X() {\n // Initialize variables\n}\n\nvoid TP_X::operator()() {\n TX = TO_TIME(T_PLC_MS());\n if ((IN) & (!EDGE)) {\n START = TX;\n Q = PT > 0LL;\n } else if (Q) {\n ET = TX - START;\n if (ET >= PT) {\n Q = false;\n ET = 0LL;\n }\n }\n EDGE = IN;\n}\n\n\nTREND::TREND() {\n // Initialize variables\n}\n\nvoid TREND::operator()() {\n TU = X > LAST_X;\n TD = X < LAST_X;\n Q = (TU) | (TD);\n D = X - LAST_X;\n LAST_X = X;\n}\n\n\nTREND_DW::TREND_DW() {\n // Initialize variables\n}\n\nvoid TREND_DW::operator()() {\n if (X > LAST_X) {\n TU = true;\n TD = false;\n D = X - LAST_X;\n Q = true;\n } else if (X < LAST_X) {\n TD = true;\n TU = false;\n D = LAST_X - X;\n Q = false;\n } else {\n TU = false;\n TD = false;\n D = 0;\n }\n LAST_X = X;\n}\n\n\nTUNE::TUNE()\n : SS(0.1), LIMIT_H(100.0), SET_VAL(100.0), T1(500000000LL), T2(2000000000LL), S1(2.0), S2(10.0)\n{\n // Initialize variables\n}\n\nvoid TUNE::operator()() {\n TX = T_PLC_MS();\n if (RST) {\n Y = RST_VAL;\n STATE = 0;\n } else if (SET) {\n Y = SET_VAL;\n STATE = 0;\n } else if (STATE > 0) {\n if (STATE == 1) {\n IN = SU;\n } else {\n IN = SD;\n }\n if ((!IN) & (TX - START <= TO_DWORD(T1))) {\n Y = Y_START + STEP;\n STATE = 0;\n } else if ((IN) & (TX - START >= TO_DWORD(T2))) {\n Y = Y_START2 + TO_REAL(TX - START2) * S2 / SPEED;\n } else if ((IN) & (TX - START >= TO_DWORD(T1))) {\n Y = Y_START + TO_REAL(TX - START - TO_DWORD(T1)) * S1 / SPEED;\n START2 = TX;\n Y_START2 = Y;\n } else if (!IN) {\n STATE = 0;\n }\n } else if (SU) {\n STATE = 1;\n START = TX;\n STEP = SS;\n SPEED = 1000.0;\n Y_START = Y;\n } else if (SD) {\n STATE = 2;\n START = TX;\n STEP = -SS;\n SPEED = -1000.0;\n Y_START = Y;\n }\n Y = LIMIT(LIMIT_L, Y, LIMIT_H);\n}\n\n\nTUNE2::TUNE2()\n : SS(0.1), FS(5.0), LIMIT_H(100.0), SET_VAL(100.0), TR(500000000LL), S1(2.0), S2(10.0)\n{\n // Initialize variables\n}\n\nvoid TUNE2::operator()() {\n TX = T_PLC_MS();\n if (RST) {\n Y = RST_VAL;\n STATE = 0;\n } else if (SET) {\n Y = SET_VAL;\n STATE = 0;\n } else if (STATE > 0) {\n switch (STATE) {\n case 1:\n IN = SU;\n break;\n case 2:\n IN = SD;\n break;\n case 3:\n IN = FU;\n break;\n case 4:\n IN = FD;\n break;\n }\n if ((!IN) & (TX - START <= TO_DWORD(TR))) {\n Y = Y_START + STEP;\n STATE = 0;\n } else if ((IN) & (TX - START >= TO_DWORD(TR))) {\n Y = Y_START + TO_REAL(TX - START - TO_DWORD(TR)) * SPEED;\n } else if (!IN) {\n STATE = 0;\n }\n } else if (SU) {\n STATE = 1;\n START = TX;\n STEP = SS;\n SPEED = S1 * 0.001;\n Y_START = Y;\n } else if (SD) {\n STATE = 2;\n START = TX;\n STEP = -SS;\n SPEED = -S1 * 0.001;\n Y_START = Y;\n } else if (FU) {\n STATE = 3;\n START = TX;\n STEP = FS;\n SPEED = S2 * 0.001;\n Y_START = Y;\n } else if (FD) {\n STATE = 4;\n START = TX;\n STEP = -FS;\n SPEED = -S2 * 0.001;\n Y_START = Y;\n }\n Y = LIMIT(LIMIT_L, Y, LIMIT_H);\n}\n\n\n_RMP_B::_RMP_B()\n : E(true)\n{\n // Initialize variables\n}\n\nvoid _RMP_B::operator()() {\n TX = TO_TIME(T_PLC_MS());\n if (((((E) & (INIT)) & ((DIR == LAST_DIR))) & ((RMP != SEL(DIR, 0, 255)))) & (TR == TN)) {\n RMP = FRMP_B(START, DIR, TX - TL, TR);\n } else {\n INIT = true;\n TL = TX;\n TN = TR;\n START = RMP;\n }\n LAST_DIR = DIR;\n}\n\n\n_RMP_W::_RMP_W()\n : E(true)\n{\n // Initialize variables\n}\n\nvoid _RMP_W::operator()() {\n TX = T_PLC_MS();\n if ((E) & (INIT)) {\n if ((DIR) ^ (LAST_DIR)) {\n TL = TX;\n LAST_DIR = DIR;\n }\n if (TR > 0LL) {\n STEP = TO_DINT(SHL(TX - TL, 16) / TO_DWORD(TR));\n } else {\n STEP = 65535;\n }\n if (STEP > 0) {\n TL = TX;\n if (!DIR) {\n STEP = -STEP;\n }\n RMP = TO_WORD(LIMIT(static_cast(0), TO_DINT(RMP) + STEP, static_cast(65535)));\n }\n } else {\n TL = TX;\n INIT = true;\n }\n}\n\n\nFT_AVG::FT_AVG()\n : E(true), N(32)\n{\n // Initialize variables\n}\n\nvoid FT_AVG::operator()() {\n BUFF.N = LIMIT(0, N, 32);\n if ((!INIT) | (RST)) {\n for (I = 1; I <= N; I++) {\n BUFF.IN = IN;\n BUFF();\n BUFF.ENO = true;\n }\n AVG = IN;\n INIT = true;\n } else if (E) {\n BUFF.IN = IN;\n BUFF();\n BUFF.ENO = true;\n AVG = AVG + (IN - BUFF.OUT) / TO_REAL(N);\n }\n}\n\n\nDRIVER_4::DRIVER_4() {\n // Initialize variables\n}\n\nvoid DRIVER_4::operator()() {\n D0.SET = SET;\n D0.IN = IN0;\n D0.RST = RST;\n D0.TOGGLE_MODE = TOGGLE_MODE;\n D0.TIMEOUT = TIMEOUT;\n D0();\n D0.ENO = true;\n D1.SET = SET;\n D1.IN = IN1;\n D1.RST = RST;\n D1.TOGGLE_MODE = TOGGLE_MODE;\n D1.TIMEOUT = TIMEOUT;\n D1();\n D1.ENO = true;\n D2.SET = SET;\n D2.IN = IN2;\n D2.RST = RST;\n D2.TOGGLE_MODE = TOGGLE_MODE;\n D2.TIMEOUT = TIMEOUT;\n D2();\n D2.ENO = true;\n D3.SET = SET;\n D3.IN = IN3;\n D3.RST = RST;\n D3.TOGGLE_MODE = TOGGLE_MODE;\n D3.TIMEOUT = TIMEOUT;\n D3();\n D3.ENO = true;\n Q0 = D0.Q;\n Q1 = D1.Q;\n Q2 = D2.Q;\n Q3 = D3.Q;\n}\n\n\nFT_PD::FT_PD()\n : KP(1.0), TV(1.0)\n{\n // Initialize variables\n}\n\nvoid FT_PD::operator()() {\n DIFF.IN = IN;\n DIFF.K = TV;\n DIFF();\n DIFF.ENO = true;\n Y = KP * (DIFF.OUT + IN);\n}\n\n\nCTRL_PI::CTRL_PI()\n : KP(1.0), KI(1.0), LL(-1000.0), LH(1000.0)\n{\n // Initialize variables\n}\n\nvoid CTRL_PI::operator()() {\n DIFF = CTRL_IN(SET, ACT, SUP);\n PI.IN = DIFF;\n PI.KP = KP;\n PI.KI = KI;\n PI.LIM_L = LL;\n PI.LIM_H = LH;\n PI.RST = RST;\n PI();\n PI.ENO = true;\n CO.CI = PI.Y;\n CO.OFFSET = OFS;\n CO.MAN_IN = M_I;\n CO.LIM_L = LL;\n CO.LIM_H = LH;\n CO.MANUAL = MAN;\n CO();\n CO.ENO = true;\n Y = CO.Y;\n LIM = CO.LIM;\n}\n\n\nFT_PIDWL::FT_PIDWL()\n : KP(1.0), TN(1.0), TV(1.0), LIM_L(-1e+38), LIM_H(1e+38)\n{\n // Initialize variables\n}\n\nvoid FT_PIDWL::operator()() {\n if (RST) {\n PIWL.RST = true;\n PIWL();\n PIWL.ENO = true;\n PIWL.RST = false;\n } else {\n if (TN == 0.0) {\n PIWL.IN = IN * KP;\n PIWL.KP = 1.0;\n PIWL.KI = 0.0;\n PIWL.LIM_L = LIM_L;\n PIWL.LIM_H = LIM_H;\n PIWL();\n PIWL.ENO = true;\n } else {\n PIWL.IN = IN * KP;\n PIWL.KP = 1.0;\n PIWL.KI = 1.0 / TN;\n PIWL.LIM_L = LIM_L;\n PIWL.LIM_H = LIM_H;\n PIWL();\n PIWL.ENO = true;\n }\n DIFF.IN = IN;\n DIFF.K = KP * TV;\n DIFF();\n DIFF.ENO = true;\n Y = PIWL.Y + DIFF.OUT;\n if (Y < LIM_L) {\n LIM = true;\n Y = LIM_L;\n } else if (Y > LIM_H) {\n LIM = true;\n Y = LIM_H;\n } else {\n LIM = false;\n }\n }\n}\n\n\nDEAD_BAND_A::DEAD_BAND_A()\n : KL(1.0)\n{\n // Initialize variables\n}\n\nvoid DEAD_BAND_A::operator()() {\n TP1.IN = X;\n TP1.T = T;\n TP1();\n TP1.ENO = true;\n TP2.IN = ABS(TP1.OUT - X);\n TP2.T = MULTIME(T, 4.0);\n TP2();\n TP2.ENO = true;\n L = MIN(KL * TP2.OUT, LM);\n if (X > L) {\n Y = X - L;\n } else if (X < -L) {\n Y = X + L;\n } else {\n Y = 0.0;\n }\n}\n\n\nFT_IMP::FT_IMP()\n : K(1.0)\n{\n // Initialize variables\n}\n\nvoid FT_IMP::operator()() {\n T1.IN = IN;\n T1.T = T;\n T1();\n T1.ENO = true;\n OUT = (IN - T1.OUT) * K;\n}\n\n\nFT_PDT1::FT_PDT1()\n : KP(1.0), TV(1.0), T1(1.0)\n{\n // Initialize variables\n}\n\nvoid FT_PDT1::operator()() {\n DIFF.IN = IN;\n DIFF.K = TV;\n DIFF();\n DIFF.ENO = true;\n TP.IN = DIFF.OUT;\n TP.T = TO_TIME(T1);\n TP();\n TP.ENO = true;\n Y = KP * (TP.OUT + IN);\n}\n\n\nFLOW_METER::FLOW_METER()\n : UPDATE_TIME(1000000000LL)\n{\n // Initialize variables\n}\n\nvoid FLOW_METER::operator()() {\n if (!INIT) {\n INIT = true;\n TL = TX;\n X_LAST = X;\n Y_LAST = Y;\n INT1.K = 0.0002777777777777778;\n }\n INT1.E = (NOT((RST) | (PULSE_MODE))) & (E);\n INT1.X = VX;\n INT1.Y = X;\n INT1();\n INT1.ENO = true;\n if (RST) {\n X = 0.0;\n Y = 0;\n TL = TX;\n X_LAST = 0.0;\n Y_LAST = 0;\n } else if ((E) & (PULSE_MODE)) {\n if (!E_LAST) {\n X = X + VX;\n }\n }\n E_LAST = E;\n if (X > 1.0) {\n TMP = FLOOR(X);\n Y = Y + TO_UDINT(TMP);\n X = X - TO_REAL(TMP);\n }\n TX = TO_TIME(T_PLC_MS());\n if ((TX - TL >= UPDATE_TIME) & (UPDATE_TIME > 0LL)) {\n F = (TO_REAL(Y - Y_LAST) + X - X_LAST) / TO_REAL(TX - TL) * 3600000.0;\n Y_LAST = Y;\n X_LAST = X;\n TL = TX;\n }\n}\n\n\nFT_INT::FT_INT()\n : K(1), RUN(true), OUT_MIN(-1e+37), OUT_MAX(1e+37)\n{\n // Initialize variables\n}\n\nvoid FT_INT::operator()() {\n if (RST) {\n OUT = 0.0;\n } else {\n INTEG.X = IN;\n INTEG.E = RUN;\n INTEG.K = K;\n INTEG.Y = OUT;\n INTEG();\n INTEG.ENO = true;\n }\n if (OUT >= OUT_MAX) {\n OUT = OUT_MAX;\n LIM = true;\n } else if (OUT <= OUT_MIN) {\n OUT = OUT_MIN;\n LIM = true;\n } else {\n LIM = false;\n }\n}\n\n\nFT_INT2::FT_INT2()\n : K(1.0), RUN(true), OUT_MIN(-1e+38), OUT_MAX(1e+38)\n{\n // Initialize variables\n}\n\nvoid FT_INT2::operator()() {\n if (RST) {\n VAL = R2_SET(0.0);\n OUT = 0.0;\n } else {\n INTEG.X = IN;\n INTEG.E = RUN;\n INTEG.K = K;\n INTEG.Y = IX;\n INTEG();\n INTEG.ENO = true;\n VAL = R2_ADD(VAL, IX);\n IX = 0.0;\n OUT = VAL.RX;\n }\n if ((OUT > OUT_MIN) & (OUT < OUT_MAX)) {\n LIM = false;\n } else {\n OUT = LIMIT(OUT_MIN, OUT, OUT_MAX);\n VAL = R2_SET(OUT);\n LIM = true;\n }\n}\n\n\nFT_PIDW::FT_PIDW()\n : KP(1.0), TN(1.0), TV(1.0), LIM_L(-1e+38), LIM_H(1e+38)\n{\n // Initialize variables\n}\n\nvoid FT_PIDW::operator()() {\n if ((TN == 0.0) | (RST)) {\n INTEG.E = false;\n INTEG.Y = YI;\n INTEG();\n INTEG.ENO = true;\n YI = 0.0;\n } else {\n INTEG.X = IN;\n INTEG.K = 1.0 / TN;\n INTEG.E = !LIM;\n INTEG.Y = YI;\n INTEG();\n INTEG.ENO = true;\n }\n Y = KP * (IN + YI);\n DIFF.IN = IN;\n DIFF.K = TV;\n DIFF();\n DIFF.ENO = true;\n if ((Y > LIM_L) & (Y < LIM_H)) {\n LIM = false;\n } else {\n LIM = true;\n }\n Y = LIMIT(LIM_L, Y + KP * DIFF.OUT, LIM_H);\n}\n\n\nFT_PT2::FT_PT2()\n : K(1.0)\n{\n // Initialize variables\n}\n\nvoid FT_PT2::operator()() {\n if ((!INIT) | (T == 0LL)) {\n INIT = true;\n OUT = K * IN;\n I2 = OUT;\n } else {\n TN = TO_REAL(T) * 0.001;\n TN2 = TN * TN;\n INT1.X = IN * K / TN2 - I1 * 0.5 * D / TN - I2 / TN2;\n INT1.Y = I1;\n INT1();\n INT1.ENO = true;\n INT2.X = I1;\n INT2.Y = I2;\n INT2();\n INT2.ENO = true;\n OUT = I2;\n }\n}\n\n\nPARSET2::PARSET2() {\n // Initialize variables\n}\n\nvoid PARSET2::operator()() {\n if (!INIT) {\n INIT = true;\n PSET.TC = TC;\n PSET.X01 = X01;\n PSET.X02 = X02;\n PSET.X03 = X03;\n PSET.X04 = X04;\n PSET.X11 = X11;\n PSET.X12 = X12;\n PSET.X13 = X13;\n PSET.X14 = X14;\n PSET.X21 = X21;\n PSET.X22 = X22;\n PSET.X23 = X23;\n PSET.X24 = X24;\n PSET.X31 = X31;\n PSET.X32 = X32;\n PSET.X33 = X33;\n PSET.X34 = X34;\n PSET();\n PSET.ENO = true;\n }\n if (ABS(X) < L1) {\n PSET.A0 = false;\n PSET.A1 = false;\n PSET();\n PSET.ENO = true;\n } else if (ABS(X) < L2) {\n PSET.A0 = true;\n PSET.A1 = false;\n PSET();\n PSET.ENO = true;\n } else if (ABS(X) < L3) {\n PSET.A0 = false;\n PSET.A1 = true;\n PSET();\n PSET.ENO = true;\n } else {\n PSET.A0 = true;\n PSET.A1 = true;\n PSET();\n PSET.ENO = true;\n }\n P1 = PSET.P1;\n P2 = PSET.P2;\n P3 = PSET.P3;\n P4 = PSET.P4;\n}\n\n\nRTC_2::RTC_2() {\n // Initialize variables\n}\n\nvoid RTC_2::operator()() {\n RT.SET = SET;\n RT.SDT = SDT;\n RT.SMS = SMS;\n RT();\n RT.ENO = true;\n UDT = RT.XDT;\n XMS = RT.XMS;\n DSO = (DST(UDT)) & (DEN);\n LOCAL_DT = TO_DT(TO_DWORD(UDT) + TO_DWORD(OFS + TO_INT(DSO) * 60) * 60);\n}\n\n\nSIGNAL_4::SIGNAL_4()\n : S1(0b11111111), S2(0b11110000), S3(0b10101010), S4(0b10100000)\n{\n // Initialize variables\n}\n\nvoid SIGNAL_4::operator()() {\n if (IN1) {\n SIG.IN = true;\n SIG.SIG = S1;\n SIG.TS = TS;\n SIG();\n SIG.ENO = true;\n } else if (IN2) {\n SIG.IN = true;\n SIG.SIG = S2;\n SIG.TS = TS;\n SIG();\n SIG.ENO = true;\n } else if (IN3) {\n SIG.IN = true;\n SIG.SIG = S3;\n SIG.TS = TS;\n SIG();\n SIG.ENO = true;\n } else if (IN4) {\n SIG.IN = true;\n SIG.SIG = S4;\n SIG.TS = TS;\n SIG();\n SIG.ENO = true;\n } else {\n SIG.IN = false;\n SIG();\n SIG.ENO = true;\n }\n Q = SIG.Q;\n}\n\n\nCALENDAR_CALC::CALENDAR_CALC()\n : H(-0.83333333333)\n{\n // Initialize variables\n}\n\nvoid CALENDAR_CALC::operator()() {\n if (XCAL.UTC != LAST) {\n LAST = XCAL.UTC;\n UTOD = TO_TOD(XCAL.UTC);\n XCAL.LOCAL_DT = UTC_TO_LTIME(XCAL.UTC, XCAL.DST_EN, XCAL.OFFSET);\n XCAL.LOCAL_DATE = TO_DATE(XCAL.LOCAL_DT);\n XCAL.LOCAL_TOD = TO_TOD(XCAL.LOCAL_DT);\n DTEMP = DAY_OF_DATE(XCAL.LOCAL_DATE);\n XCAL.NIGHT = (XCAL.LOCAL_TOD < XCAL.SUN_RISE) | (XCAL.LOCAL_TOD > XCAL.SUN_SET);\n TMP = HOUR(XCAL.LOCAL_TOD);\n if (TMP != LAST_HOUR) {\n XCAL.DST_ON = (DST(XCAL.UTC)) & (XCAL.DST_EN);\n LAST_HOUR = TMP;\n }\n if (DTEMP != LAST_DAY) {\n LAST_DAY = DTEMP;\n XCAL.YEAR = YEAR_OF_DATE(XCAL.LOCAL_DATE);\n XCAL.MONTH = MONTH_OF_DATE(XCAL.LOCAL_DATE);\n XCAL.DAY = DAY_OF_MONTH(XCAL.LOCAL_DATE);\n XCAL.WEEKDAY = DAY_OF_WEEK(XCAL.LOCAL_DATE);\n HOLY.DATE_IN = XCAL.LOCAL_DATE;\n HOLY.LANGU = XCAL.LANGUAGE;\n HOLY.HOLIDAYS = HOLIDAYS;\n HOLY();\n HOLY.ENO = true;\n XCAL.HOLIDAY = HOLY.Y;\n XCAL.HOLY_NAME = HOLY.NAME;\n SUN.LATITUDE = XCAL.LATITUDE;\n SUN.LONGITUDE = XCAL.LONGITUDE;\n SUN.UTC = TO_DATE(XCAL.UTC);\n SUN.H = H;\n SUN();\n SUN.ENO = true;\n XCAL.SUN_RISE = TO_TOD(TO_DINT(SUN.SUN_RISE) + XCAL.OFFSET * 60000 + SEL(XCAL.DST_ON, static_cast(0), 3600000));\n XCAL.SUN_SET = TO_TOD(TO_DINT(SUN.SUN_SET) + XCAL.OFFSET * 60000 + SEL(XCAL.DST_ON, static_cast(0), 3600000));\n XCAL.SUN_MIDDAY = TO_TOD(TO_DINT(SUN.MIDDAY) + XCAL.OFFSET * 60000 + SEL(XCAL.DST_ON, static_cast(0), 3600000));\n XCAL.SUN_HEIGTH = SUN.SUN_DECLINATION;\n XCAL.WORK_WEEK = WORK_WEEK(XCAL.LOCAL_DATE);\n }\n if ((SPE) & (XCAL.UTC - PLAST >= 25000000000LL)) {\n PLAST = LAST;\n POS.LATITUDE = XCAL.LATITUDE;\n POS.LONGITUDE = XCAL.LONGITUDE;\n POS.UTC = XCAL.UTC;\n POS();\n POS.ENO = true;\n XCAL.SUN_HOR = POS.B;\n XCAL.SUN_VER = POS.HR;\n }\n }\n}\n\n\nPWM_DC::PWM_DC() {\n // Initialize variables\n}\n\nvoid PWM_DC::operator()() {\n if (F > 0.0) {\n TMP = 1000.0 / F;\n CLK.PT = TO_TIME(TMP);\n CLK();\n CLK.ENO = true;\n PULSE.IN = CLK.Q;\n PULSE.PT = TO_TIME(TMP * DC);\n PULSE();\n PULSE.ENO = true;\n Q = PULSE.Q;\n }\n}\n\n\nPWM_PW::PWM_PW() {\n // Initialize variables\n}\n\nvoid PWM_PW::operator()() {\n if (F > 0.0) {\n CLK.PT = TO_TIME(1000.0 / F);\n CLK();\n CLK.ENO = true;\n PULSE.IN = CLK.Q;\n PULSE.PT = PW;\n PULSE();\n PULSE.ENO = true;\n Q = PULSE.Q;\n }\n}\n\n\nRMP_B::RMP_B()\n : E(true), UP(true)\n{\n // Initialize variables\n}\n\nvoid RMP_B::operator()() {\n RMP.DIR = UP;\n RMP.E = E;\n RMP.TR = PT;\n RMP.RMP = OUT;\n RMP();\n RMP.ENO = true;\n if (RST) {\n OUT = 0;\n } else if (SET) {\n OUT = 255;\n }\n LOW = OUT == 0;\n HIGH = OUT == 255;\n BUSY = (NOT((LOW) | (HIGH))) & (E);\n}\n\n\nRMP_SOFT::RMP_SOFT() {\n // Initialize variables\n}\n\nvoid RMP_SOFT::operator()() {\n TMP = SEL(IN, 0, VAL);\n if (TMP > OUT) {\n RMP.DIR = true;\n RMP.E = true;\n RMP.TR = PT_ON;\n RMP.RMP = OUT;\n RMP();\n RMP.ENO = true;\n OUT = MIN(OUT, TMP);\n } else if (TMP < OUT) {\n RMP.DIR = false;\n RMP.E = true;\n RMP.TR = PT_OFF;\n RMP.RMP = OUT;\n RMP();\n RMP.ENO = true;\n OUT = MAX(OUT, TMP);\n } else {\n RMP.E = false;\n RMP.RMP = OUT;\n RMP();\n RMP.ENO = true;\n }\n}\n\n\n_RMP_NEXT::_RMP_NEXT()\n : E(true)\n{\n // Initialize variables\n}\n\nvoid _RMP_NEXT::operator()() {\n DIRX.X = IN;\n DIRX();\n DIRX.ENO = true;\n T_LOCK.IN = false;\n T_LOCK.PT = TL;\n T_LOCK();\n T_LOCK.ENO = true;\n if ((DIRX.TU) & ((OUT < IN))) {\n if ((!XDIR) & (XEN)) {\n T_LOCK.IN = true;\n T_LOCK();\n T_LOCK.ENO = true;\n }\n XEN = true;\n XDIR = true;\n } else if ((DIRX.TD) & ((OUT > IN))) {\n if ((XDIR) & (XEN)) {\n T_LOCK.IN = true;\n T_LOCK();\n T_LOCK.ENO = true;\n }\n XEN = true;\n XDIR = false;\n } else if (XEN) {\n if ((((XDIR) & ((OUT >= IN)))) | (((!XDIR) & ((OUT <= IN))))) {\n XEN = false;\n if (TL > 0LL) {\n T_LOCK.IN = true;\n T_LOCK();\n T_LOCK.ENO = true;\n }\n }\n }\n if ((!T_LOCK.Q) & (XEN)) {\n UP = XDIR;\n DIR = XDIR;\n DN = !XDIR;\n } else {\n UP = false;\n DN = false;\n }\n RMX.RMP = OUT;\n RMX.E = (E) & (((UP) | (DN)));\n RMX.DIR = DIR;\n RMX.TR = SEL(DIR, TF, TR);\n RMX();\n RMX.ENO = true;\n}\n\n\nRMP_W::RMP_W()\n : E(true), UP(true)\n{\n // Initialize variables\n}\n\nvoid RMP_W::operator()() {\n RMP.DIR = UP;\n RMP.E = E;\n RMP.TR = PT;\n RMP.RMP = OUT;\n RMP();\n RMP.ENO = true;\n if (RST) {\n OUT = 0;\n } else if (SET) {\n OUT = 65535;\n }\n LOW = OUT == 0;\n HIGH = OUT == 65535;\n BUSY = (NOT((LOW) | (HIGH))) & (E);\n}\n\n\nCTRL_PID::CTRL_PID()\n : KP(1.0), TN(1.0), TV(1.0), LL(-1000.0), LH(1000.0)\n{\n // Initialize variables\n}\n\nvoid CTRL_PID::operator()() {\n DIFF = CTRL_IN(SET, ACT, SUP);\n PID.IN = DIFF;\n PID.KP = KP;\n PID.TN = TN;\n PID.TV = TV;\n PID.LIM_L = LL;\n PID.LIM_H = LH;\n PID.RST = RST;\n PID();\n PID.ENO = true;\n CO.CI = PID.Y;\n CO.OFFSET = OFS;\n CO.MAN_IN = M_I;\n CO.LIM_L = LL;\n CO.LIM_H = LH;\n CO.MANUAL = MAN;\n CO();\n CO.ENO = true;\n Y = CO.Y;\n LIM = CO.LIM;\n}\n\n\nFT_PI::FT_PI()\n : KP(1.0), KI(1.0), ILIM_L(-1e+38), ILIM_H(1e+38), IEN(true)\n{\n // Initialize variables\n}\n\nvoid FT_PI::operator()() {\n INTEG.IN = IN;\n INTEG.K = KI;\n INTEG.RUN = IEN;\n INTEG.RST = RST;\n INTEG.OUT_MIN = ILIM_L;\n INTEG.OUT_MAX = ILIM_H;\n INTEG();\n INTEG.ENO = true;\n LIM = INTEG.LIM;\n Y = KP * IN + INTEG.OUT;\n}\n\n\nFT_PID::FT_PID()\n : KP(1.0), TN(1.0), TV(1.0), ILIM_L(-1e+38), ILIM_H(1e+38), IEN(true)\n{\n // Initialize variables\n}\n\nvoid FT_PID::operator()() {\n if (TN > 0.0) {\n INTEG.IN = IN;\n INTEG.K = 1.0 / TN;\n INTEG.RUN = IEN;\n INTEG.RST = RST;\n INTEG.OUT_MIN = ILIM_L;\n INTEG.OUT_MAX = ILIM_H;\n INTEG();\n INTEG.ENO = true;\n } else {\n INTEG.RST = false;\n INTEG();\n INTEG.ENO = true;\n }\n DIFF.IN = IN;\n DIFF.K = TV;\n DIFF();\n DIFF.ENO = true;\n Y = KP * (INTEG.OUT + DIFF.OUT + IN);\n LIM = INTEG.LIM;\n}\n\n\nFT_PIW::FT_PIW()\n : KP(1.0), KI(1.0), LIM_L(-1e+38), LIM_H(1e+38)\n{\n // Initialize variables\n}\n\nvoid FT_PIW::operator()() {\n INTEG.IN = IN;\n INTEG.K = KI;\n INTEG.RUN = !LIM;\n INTEG.RST = RST;\n INTEG();\n INTEG.ENO = true;\n Y = KP * IN + INTEG.OUT;\n if (Y < LIM_L) {\n Y = LIM_L;\n LIM = true;\n } else if (Y > LIM_H) {\n Y = LIM_H;\n LIM = true;\n } else {\n LIM = false;\n }\n}\n\n\nCTRL_PWM::CTRL_PWM() {\n // Initialize variables\n}\n\nvoid CTRL_PWM::operator()() {\n PW.F = F;\n PW.DC = SEL(MANUAL, CI, MAN_IN);\n PW();\n PW.ENO = true;\n Q = PW.Q;\n}\n\n\nFADE::FADE() {\n // Initialize variables\n}\n\nvoid FADE::operator()() {\n RMX.RST = (RST) & (!F);\n RMX.SET = (RST) & (F);\n RMX.PT = TF;\n RMX.UP = F;\n RMX();\n RMX.ENO = true;\n Y = (IN2 - IN1) / 65535.0 * TO_REAL(RMX.OUT) + IN1;\n}\n\n\nIEC_REAL ACOSH(IEC_REAL X) {\n IEC_REAL ACOSH_result;\n ACOSH_result = LN(SQRT(X * X - 1.0) + X);\n return ACOSH_result;\n}\n\n\nIEC_REAL ACOTH(IEC_REAL X) {\n IEC_REAL ACOTH_result;\n ACOTH_result = LN((X + 1.0) / (X - 1.0)) * 0.5;\n return ACOTH_result;\n}\n\n\nIEC_REAL AGDF(IEC_REAL X) {\n IEC_REAL AGDF_result;\n AGDF_result = LN((1.0 + SIN(X)) / COS(X));\n return AGDF_result;\n}\n\n\nIEC_REAL AIN(IEC_DWORD IN, IEC_BYTE BITS, IEC_BYTE SIGN, IEC_REAL LOW, IEC_REAL HIGH) {\n IEC_REAL AIN_result;\n IEC_DWORD FF = 0xFFFFFFFF;\n IEC_DWORD TEMP1;\n IEC_DWORD TEMP2;\n IEC_BOOL SX;\n if (SIGN < 32) {\n TEMP1 = SHR(IN, SIGN);\n SX = ((static_cast(TEMP1) >> 0) & 1);\n } else {\n SX = false;\n }\n TEMP1 = SHR(FF, 32 - BITS);\n TEMP2 = (IN) & (TEMP1);\n AIN_result = (HIGH - LOW) * TO_REAL(TEMP2) / TO_REAL(TEMP1) + LOW;\n if (SX) {\n AIN_result = -AIN_result;\n }\n return AIN_result;\n}\n\n\nIEC_DWORD AOUT(IEC_REAL IN, IEC_BYTE BITS, IEC_BYTE SIGN, IEC_REAL LOW, IEC_REAL HIGH) {\n IEC_DWORD AOUT_result;\n IEC_DWORD FF = 0b1;\n IEC_REAL IN2;\n IEC_BOOL SX;\n if (SIGN < 32) {\n SX = SIGN_R(IN);\n IN2 = ABS(IN);\n } else {\n IN2 = IN;\n }\n IN2 = LIMIT(LOW, IN2, HIGH);\n AOUT_result = TO_DWORD((IN2 - LOW) / (HIGH - LOW) * TO_REAL(SHL(FF, BITS) - 1));\n if (SX) {\n AOUT_result = (SHL(FF, SIGN)) | (AOUT_result);\n }\n return AOUT_result;\n}\n\n\nIEC_DWORD AOUT1(IEC_REAL IN, IEC_INT BIT_0, IEC_INT BIT_N, IEC_INT SIGN, IEC_REAL LOW, IEC_REAL HIGH) {\n IEC_DWORD AOUT1_result;\n IEC_DWORD FF = 0b1;\n IEC_BOOL SX;\n IEC_REAL IN2;\n if (SIGN < 32) {\n SX = SIGN_R(IN);\n IN2 = ABS(IN);\n } else {\n IN2 = IN;\n }\n IN2 = LIMIT(LOW, IN2, HIGH);\n AOUT1_result = SHL(TO_DWORD((IN2 - LOW) / (HIGH - LOW) * TO_REAL(SHL(FF, BIT_N - BIT_0 + 1) - 1)), BIT_0);\n if (SX) {\n AOUT1_result = (SHL(FF, SIGN)) | (AOUT1_result);\n }\n return AOUT1_result;\n}\n\n\nIEC_REAL ARRAY_AVG(IEC_Ptr> PT, IEC_UINT SIZE) {\n IEC_REAL ARRAY_AVG_result;\n IEC_UINT I;\n IEC_UINT STOP;\n STOP = SHR(SIZE, 2) - 1;\n ARRAY_AVG_result = (*PT)[0];\n for (I = 1; I <= STOP; I++) {\n ARRAY_AVG_result = ARRAY_AVG_result + (*PT)[I];\n }\n ARRAY_AVG_result = ARRAY_AVG_result / TO_REAL(STOP + 1);\n return ARRAY_AVG_result;\n}\n\n\nIEC_REAL ARRAY_GAV(IEC_Ptr> PT, IEC_UINT SIZE) {\n IEC_REAL ARRAY_GAV_result;\n IEC_UINT I;\n IEC_UINT STOP;\n STOP = SHR(SIZE, 2) - 1;\n ARRAY_GAV_result = 1.0;\n for (I = 0; I <= STOP; I++) {\n if ((*PT)[I] > 0.0) {\n ARRAY_GAV_result = ARRAY_GAV_result * (*PT)[I];\n } else {\n ARRAY_GAV_result = 0.0;\n return ARRAY_GAV_result;\n }\n }\n ARRAY_GAV_result = SQRTN(ARRAY_GAV_result, TO_INT(STOP) + 1);\n return ARRAY_GAV_result;\n}\n\n\nIEC_REAL ARRAY_HAV(IEC_Ptr> PT, IEC_UINT SIZE) {\n IEC_REAL ARRAY_HAV_result;\n IEC_UINT I;\n IEC_UINT STOP;\n STOP = SHR(SIZE, 2) - 1;\n for (I = 0; I <= STOP; I++) {\n if ((*PT)[I] != 0.0) {\n ARRAY_HAV_result = ARRAY_HAV_result + 1.0 / (*PT)[I];\n } else {\n ARRAY_HAV_result = 0.0;\n return ARRAY_HAV_result;\n }\n }\n ARRAY_HAV_result = TO_REAL(STOP + 1) / ARRAY_HAV_result;\n return ARRAY_HAV_result;\n}\n\n\nIEC_REAL ARRAY_MAX(IEC_Ptr> PT, IEC_UINT SIZE) {\n IEC_REAL ARRAY_MAX_result;\n IEC_UINT I;\n IEC_UINT STOP;\n STOP = (SIZE - IEC_SIZEOF(PT)) / IEC_SIZEOF(PT);\n ARRAY_MAX_result = (*PT)[0];\n for (I = 1; I <= STOP; I++) {\n if ((*PT)[I] > ARRAY_MAX_result) {\n ARRAY_MAX_result = (*PT)[I];\n }\n }\n return ARRAY_MAX_result;\n}\n\n\nIEC_REAL ARRAY_MIN(IEC_Ptr> PT, IEC_UINT SIZE) {\n IEC_REAL ARRAY_MIN_result;\n IEC_UINT I;\n IEC_UINT STOP;\n STOP = (SIZE - IEC_SIZEOF(PT)) / IEC_SIZEOF(PT);\n ARRAY_MIN_result = (*PT)[0];\n for (I = 1; I <= STOP; I++) {\n if ((*PT)[I] < ARRAY_MIN_result) {\n ARRAY_MIN_result = (*PT)[I];\n }\n }\n return ARRAY_MIN_result;\n}\n\n\nIEC_REAL ARRAY_SDV(IEC_Ptr> PT, IEC_UINT SIZE) {\n IEC_REAL ARRAY_SDV_result;\n ARRAY_SDV_result = SQRT(ARRAY_VAR(PT, SIZE));\n return ARRAY_SDV_result;\n}\n\n\nIEC_REAL ARRAY_SPR(IEC_Ptr> PT, IEC_UINT SIZE) {\n IEC_REAL ARRAY_SPR_result;\n IEC_UINT I;\n IEC_UINT STOP;\n IEC_REAL ARRAY_MAX;\n IEC_REAL ARRAY_MIN;\n STOP = (SIZE - IEC_SIZEOF(PT)) / IEC_SIZEOF(PT);\n ARRAY_MIN = (*PT)[0];\n ARRAY_MAX = (*PT)[0];\n for (I = 1; I <= STOP; I++) {\n if ((*PT)[I] > ARRAY_MAX) {\n ARRAY_MAX = (*PT)[I];\n } else if ((*PT)[I] < ARRAY_MIN) {\n ARRAY_MIN = (*PT)[I];\n }\n }\n ARRAY_SPR_result = ARRAY_MAX - ARRAY_MIN;\n return ARRAY_SPR_result;\n}\n\n\nIEC_REAL ARRAY_SUM(IEC_Ptr> PT, IEC_UINT SIZE) {\n IEC_REAL ARRAY_SUM_result;\n IEC_UINT I;\n IEC_UINT STOP;\n STOP = (SIZE - IEC_SIZEOF(PT)) / IEC_SIZEOF(PT);\n ARRAY_SUM_result = (*PT)[0];\n for (I = 1; I <= STOP; I++) {\n ARRAY_SUM_result = ARRAY_SUM_result + (*PT)[I];\n }\n return ARRAY_SUM_result;\n}\n\n\nIEC_REAL ARRAY_TREND(IEC_Ptr> PT, IEC_UINT SIZE) {\n IEC_REAL ARRAY_TREND_result;\n IEC_UINT I;\n IEC_UINT STOP;\n IEC_REAL X;\n IEC_UINT STOP2;\n STOP = SHR(SIZE, 2) - 1;\n STOP2 = SHR(STOP, 1);\n for (I = 0; I <= STOP2; I++) {\n X = X - (*PT)[I];\n }\n if (EVEN(static_cast(TO_INT(STOP)))) {\n for (I = STOP2; I <= STOP; I++) {\n X = X + (*PT)[I];\n }\n } else {\n for (I = STOP2 + 1; I <= STOP; I++) {\n X = X + (*PT)[I];\n }\n }\n ARRAY_TREND_result = X / TO_REAL(STOP2 + 1);\n return ARRAY_TREND_result;\n}\n\n\nIEC_REAL ARRAY_VAR(IEC_Ptr> PT, IEC_UINT SIZE) {\n IEC_REAL ARRAY_VAR_result;\n IEC_REAL AVG;\n IEC_UINT I;\n IEC_UINT STOP;\n STOP = SHR(SIZE, 2) - 1;\n AVG = (*PT)[0];\n for (I = 1; I <= STOP; I++) {\n AVG = AVG + (*PT)[I];\n }\n AVG = AVG / TO_REAL(STOP + 1);\n ARRAY_VAR_result = ((*PT)[0] - AVG) * ((*PT)[0] - AVG);\n for (I = 1; I <= STOP; I++) {\n ARRAY_VAR_result = ARRAY_VAR_result + ((*PT)[I] - AVG) * ((*PT)[I] - AVG);\n }\n ARRAY_VAR_result = ARRAY_VAR_result / TO_REAL(STOP);\n return ARRAY_VAR_result;\n}\n\n\nIEC_REAL ASINH(IEC_REAL X) {\n IEC_REAL ASINH_result;\n ASINH_result = LN(SQRT(X * X + 1.0) + X);\n return ASINH_result;\n}\n\n\nIEC_REAL ATAN2(IEC_REAL Y, IEC_REAL X) {\n IEC_REAL ATAN2_result;\n if (X > 0.0) {\n ATAN2_result = ATAN(Y / X);\n } else if (X < 0.0) {\n if (Y >= 0.0) {\n ATAN2_result = ATAN(Y / X) + MATH.PI;\n } else {\n ATAN2_result = ATAN(Y / X) - MATH.PI;\n }\n } else if (Y > 0.0) {\n ATAN2_result = MATH.PI05;\n } else if (Y < 0.0) {\n ATAN2_result = -MATH.PI05;\n } else {\n ATAN2_result = 0.0;\n }\n return ATAN2_result;\n}\n\n\nIEC_REAL ATANH(IEC_REAL X) {\n IEC_REAL ATANH_result;\n ATANH_result = LN((1.0 + X) / (1.0 - X)) * 0.5;\n return ATANH_result;\n}\n\n\nIEC_BYTE BAND_B(IEC_BYTE X, IEC_BYTE B) {\n IEC_BYTE BAND_B_result;\n if (X < B) {\n BAND_B_result = 0;\n } else if (X > static_cast(255) - B) {\n BAND_B_result = 255;\n } else {\n BAND_B_result = X;\n }\n return BAND_B_result;\n}\n\n\nIEC_INT BCDC_TO_INT(IEC_BYTE IN) {\n IEC_INT BCDC_TO_INT_result;\n BCDC_TO_INT_result = ((IN) & (0x0F)) + (SHR(IN, 4) * 10);\n return BCDC_TO_INT_result;\n}\n\n\nIEC_REAL BETA(IEC_REAL X, IEC_REAL Y) {\n IEC_REAL BETA_result;\n BETA_result = GAMMA(X) * GAMMA(Y) / GAMMA(X + Y);\n return BETA_result;\n}\n\n\nIEC_REAL BFT_TO_MS(IEC_INT BFT) {\n IEC_REAL BFT_TO_MS_result;\n BFT_TO_MS_result = EXPT(BFT, 1.5) * 0.836;\n return BFT_TO_MS_result;\n}\n\n\nIEC_DINT BINOM(IEC_INT N, IEC_INT K) {\n IEC_DINT BINOM_result;\n IEC_INT I;\n if (2 * K > N) {\n K = N - K;\n }\n if (K > N) {\n return BINOM_result;\n } else if ((K == 0) | (K == N)) {\n BINOM_result = 1;\n } else if (K == 1) {\n BINOM_result = N;\n } else {\n BINOM_result = N;\n N = N + 1;\n for (I = 2; I <= K; I++) {\n BINOM_result = BINOM_result * (N - I) / I;\n }\n }\n return BINOM_result;\n}\n\n\nIEC_BYTE BIN_TO_BYTE(IECStringVar<12> BIN) {\n IEC_BYTE BIN_TO_BYTE_result;\n IEC_Ptr PT;\n IEC_INT I;\n IEC_BYTE X;\n IEC_INT STOP;\n PT = &(BIN);\n STOP = LEN(BIN);\n for (I = 1; I <= STOP; I++) {\n X = (*PT);\n if (X == 48) {\n BIN_TO_BYTE_result = SHL(BIN_TO_BYTE_result, 1);\n } else if (X == 49) {\n BIN_TO_BYTE_result = (SHL(BIN_TO_BYTE_result, 1)) | (1);\n }\n PT = PT + 1;\n }\n return BIN_TO_BYTE_result;\n}\n\n\nIEC_DWORD BIN_TO_DWORD(IECStringVar<40> BIN) {\n IEC_DWORD BIN_TO_DWORD_result;\n IEC_Ptr PT;\n IEC_INT I;\n IEC_BYTE X;\n IEC_INT STOP;\n PT = &(BIN);\n STOP = LEN(BIN);\n for (I = 1; I <= STOP; I++) {\n X = (*PT);\n if (X == 48) {\n BIN_TO_DWORD_result = SHL(BIN_TO_DWORD_result, 1);\n } else if (X == 49) {\n BIN_TO_DWORD_result = (SHL(BIN_TO_DWORD_result, 1)) | (1);\n }\n PT = PT + 1;\n }\n return BIN_TO_DWORD_result;\n}\n\n\nIEC_INT BIT_COUNT(IEC_DWORD IN) {\n IEC_INT BIT_COUNT_result;\n while (IN > 0) {\n if (((static_cast(IN) >> 0) & 1)) {\n BIT_COUNT_result = BIT_COUNT_result + 1;\n }\n IN = SHR(IN, 1);\n }\n return BIT_COUNT_result;\n}\n\n\nIEC_BYTE BIT_LOAD_B(IEC_BYTE IN, IEC_BOOL VAL, IEC_INT POS) {\n IEC_BYTE BIT_LOAD_B_result;\n IEC_BYTE DAT = 1;\n if (VAL) {\n BIT_LOAD_B_result = (IN) | (SHL(DAT, POS));\n } else {\n BIT_LOAD_B_result = (IN) & ((~SHL(DAT, POS)));\n }\n return BIT_LOAD_B_result;\n}\n\n\nIEC_BYTE BIT_LOAD_B2(IEC_BYTE I, IEC_BOOL D, IEC_INT P, IEC_INT N) {\n IEC_BYTE BIT_LOAD_B2_result;\n if (D) {\n BIT_LOAD_B2_result = ROL((SHR(static_cast(255), 8 - N)) | (ROR(I, P)), P);\n } else {\n BIT_LOAD_B2_result = ROL((SHL(static_cast(255), N)) & (ROR(I, P)), P);\n }\n return BIT_LOAD_B2_result;\n}\n\n\nIEC_DWORD BIT_LOAD_DW(IEC_DWORD IN, IEC_BOOL VAL, IEC_INT POS) {\n IEC_DWORD BIT_LOAD_DW_result;\n IEC_DWORD DAT = 1;\n if (VAL) {\n BIT_LOAD_DW_result = (IN) | (SHL(DAT, POS));\n } else {\n BIT_LOAD_DW_result = (IN) & ((~SHL(DAT, POS)));\n }\n return BIT_LOAD_DW_result;\n}\n\n\nIEC_DWORD BIT_LOAD_DW2(IEC_DWORD I, IEC_BOOL D, IEC_INT P, IEC_INT N) {\n IEC_DWORD BIT_LOAD_DW2_result;\n if (D) {\n BIT_LOAD_DW2_result = ROL((SHR(static_cast(4294967295), 32 - N)) | (ROR(I, P)), P);\n } else {\n BIT_LOAD_DW2_result = ROL((SHL(static_cast(4294967295), N)) & (ROR(I, P)), P);\n }\n return BIT_LOAD_DW2_result;\n}\n\n\nIEC_WORD BIT_LOAD_W(IEC_WORD IN, IEC_BOOL VAL, IEC_INT POS) {\n IEC_WORD BIT_LOAD_W_result;\n IEC_WORD DAT = 1;\n if (VAL) {\n BIT_LOAD_W_result = (IN) | (SHL(DAT, POS));\n } else {\n BIT_LOAD_W_result = (IN) & ((~SHL(DAT, POS)));\n }\n return BIT_LOAD_W_result;\n}\n\n\nIEC_WORD BIT_LOAD_W2(IEC_WORD I, IEC_BOOL D, IEC_INT P, IEC_INT N) {\n IEC_WORD BIT_LOAD_W2_result;\n if (D) {\n BIT_LOAD_W2_result = ROL((SHR(static_cast(65535), 16 - N)) | (ROR(I, P)), P);\n } else {\n BIT_LOAD_W2_result = ROL((SHL(static_cast(65535), N)) & (ROR(I, P)), P);\n }\n return BIT_LOAD_W2_result;\n}\n\n\nIEC_BOOL BIT_OF_DWORD(IEC_DWORD IN, IEC_INT N) {\n IEC_BOOL BIT_OF_DWORD_result;\n BIT_OF_DWORD_result = ((SHR(IN, N)) & (0x00000001)) > 0;\n return BIT_OF_DWORD_result;\n}\n\n\nIEC_BYTE BIT_TOGGLE_B(IEC_BYTE IN, IEC_INT POS) {\n IEC_BYTE BIT_TOGGLE_B_result;\n BIT_TOGGLE_B_result = (SHL(static_cast(1), POS)) ^ (IN);\n return BIT_TOGGLE_B_result;\n}\n\n\nIEC_DWORD BIT_TOGGLE_DW(IEC_DWORD IN, IEC_INT POS) {\n IEC_DWORD BIT_TOGGLE_DW_result;\n BIT_TOGGLE_DW_result = (SHL(static_cast(1), POS)) ^ (IN);\n return BIT_TOGGLE_DW_result;\n}\n\n\nIEC_WORD BIT_TOGGLE_W(IEC_WORD IN, IEC_INT POS) {\n IEC_WORD BIT_TOGGLE_W_result;\n BIT_TOGGLE_W_result = (SHL(static_cast(1), POS)) ^ (IN);\n return BIT_TOGGLE_W_result;\n}\n\n\nIEC_INT BUFFER_COMP(IEC_Ptr> PT1, IEC_INT SIZE1, IEC_Ptr> PT2, IEC_INT SIZE2, IEC_INT START) {\n IEC_INT BUFFER_COMP_result;\n IEC_INT I;\n IEC_INT J;\n IEC_INT END;\n IEC_BYTE FIRSTBYTE;\n if (SIZE2 <= SIZE1) {\n END = SIZE1 - SIZE2;\n FIRSTBYTE = (*PT2)[0];\n for (I = START; I <= END; I++) {\n if ((*PT1)[I] == FIRSTBYTE) {\n J = 1;\n while (J < SIZE2) {\n if ((*PT2)[J] != (*PT1)[J + I]) {\n goto __strucpp_loop_exit_33;\n }\n J = J + 1;\n }\n __strucpp_loop_exit_33: ;\n if (J == SIZE2) {\n BUFFER_COMP_result = I;\n return BUFFER_COMP_result;\n }\n }\n }\n }\n BUFFER_COMP_result = -1;\n return BUFFER_COMP_result;\n}\n\n\nIEC_INT BUFFER_SEARCH(IEC_Ptr> PT, IEC_INT SIZE, IECStringVar STR, IEC_INT POS, IEC_BOOL IGN) {\n IEC_INT BUFFER_SEARCH_result;\n IEC_Ptr> PS;\n IEC_BYTE CHX;\n IEC_INT I;\n IEC_INT END;\n IEC_INT K;\n IEC_INT LX;\n PS = &(STR);\n LX = LEN(STR);\n END = MIN(SIZE - LX, SIZE - 1);\n LX = LX - 1;\n for (I = POS; I <= END; I++) {\n for (K = 0; K <= LX; K++) {\n if (IGN) {\n CHX = TO_UPPER((*PT)[I + K]);\n } else {\n CHX = (*PT)[I + K];\n }\n if ((*PS)[K] != CHX) {\n goto __strucpp_loop_exit_35;\n }\n }\n __strucpp_loop_exit_35: ;\n if (K > LX) {\n BUFFER_SEARCH_result = I;\n return BUFFER_SEARCH_result;\n }\n }\n BUFFER_SEARCH_result = -1;\n return BUFFER_SEARCH_result;\n}\n\n\nIECStringVar BUFFER_TO_STRING(IEC_Ptr> PT, IEC_UINT SIZE, IEC_UINT START, IEC_UINT STOP) {\n IECStringVar BUFFER_TO_STRING_result;\n IEC_Ptr PS;\n IEC_UINT I;\n IEC_UINT STP;\n IEC_UINT STA;\n PS = &(BUFFER_TO_STRING_result);\n if (SIZE == 0) {\n return BUFFER_TO_STRING_result;\n }\n STA = MIN(START, SIZE - 1);\n STP = MIN(STOP, SIZE - 1);\n if (TO_INT(STP - STA + 1) >= STRING_LENGTH) {\n STP = STA + TO_UINT(STRING_LENGTH) - 1;\n }\n for (I = STA; I <= STP; I++) {\n (*PS) = (*PT)[I];\n PS = PS + 1;\n }\n (*PS) = 0;\n return BUFFER_TO_STRING_result;\n}\n\n\nIEC_BYTE BYTE_OF_BIT(IEC_BOOL B0, IEC_BOOL B1, IEC_BOOL B2, IEC_BOOL B3, IEC_BOOL B4, IEC_BOOL B5, IEC_BOOL B6, IEC_BOOL B7) {\n IEC_BYTE BYTE_OF_BIT_result;\n BYTE_OF_BIT_result = (SHL((SHL((SHL((SHL((SHL((SHL((SHL(TO_BYTE(B7), 1)) | (TO_BYTE(B6)), 1)) | (TO_BYTE(B5)), 1)) | (TO_BYTE(B4)), 1)) | (TO_BYTE(B3)), 1)) | (TO_BYTE(B2)), 1)) | (TO_BYTE(B1)), 1)) | (TO_BYTE(B0));\n return BYTE_OF_BIT_result;\n}\n\n\nIEC_BYTE BYTE_OF_DWORD(IEC_DWORD IN, IEC_BYTE N) {\n IEC_BYTE BYTE_OF_DWORD_result;\n BYTE_OF_DWORD_result = TO_BYTE(SHR(IN, SHL(N, 3)));\n return BYTE_OF_DWORD_result;\n}\n\n\nIEC_BYTE BYTE_TO_GRAY(IEC_BYTE IN) {\n IEC_BYTE BYTE_TO_GRAY_result;\n BYTE_TO_GRAY_result = (IN) ^ (SHR(IN, 1));\n return BYTE_TO_GRAY_result;\n}\n\n\nIEC_REAL BYTE_TO_RANGE(IEC_BYTE X, IEC_REAL LOW, IEC_REAL HIGH) {\n IEC_REAL BYTE_TO_RANGE_result;\n BYTE_TO_RANGE_result = (HIGH - LOW) * X / 255.0 + LOW;\n return BYTE_TO_RANGE_result;\n}\n\n\nIECStringVar<8> BYTE_TO_STRB(IEC_BYTE IN) {\n IECStringVar<8> BYTE_TO_STRB_result;\n IEC_INT I;\n IEC_Ptr PT;\n PT = &(BYTE_TO_STRB_result);\n for (I = 1; I <= 8; I++) {\n (*PT) = TO_BYTE(((static_cast(IN) >> 7) & 1)) + 48;\n IN = SHL(IN, 1);\n PT = PT + 1;\n }\n (*PT) = 0;\n return BYTE_TO_STRB_result;\n}\n\n\nIECStringVar<2> BYTE_TO_STRH(IEC_BYTE IN) {\n IECStringVar<2> BYTE_TO_STRH_result;\n IEC_BYTE TEMP;\n IEC_Ptr PT;\n PT = &(BYTE_TO_STRH_result);\n TEMP = SHR(IN, 4);\n if (TEMP <= 9) {\n TEMP = TEMP + 48;\n } else {\n TEMP = TEMP + 55;\n }\n (*PT) = TEMP;\n TEMP = (IN) & (0b00001111);\n if (TEMP <= 9) {\n TEMP = TEMP + 48;\n } else {\n TEMP = TEMP + 55;\n }\n PT = PT + 1;\n (*PT) = TEMP;\n PT = PT + 1;\n (*PT) = 0;\n return BYTE_TO_STRH_result;\n}\n\n\nIEC_REAL CABS(COMPLEX X) {\n IEC_REAL CABS_result;\n CABS_result = HYPOT(X.RE, X.IM);\n return CABS_result;\n}\n\n\nCOMPLEX CACOS(COMPLEX X) {\n COMPLEX CACOS_result;\n COMPLEX Y;\n Y = CACOSH(X);\n CACOS_result.RE = Y.IM;\n CACOS_result.IM = -Y.RE;\n return CACOS_result;\n}\n\n\nCOMPLEX CACOSH(COMPLEX X) {\n COMPLEX CACOSH_result;\n COMPLEX Y;\n Y.RE = (X.RE - X.IM) * (X.RE + X.IM) - 1.0;\n Y.IM = 2.0 * X.RE * X.IM;\n Y = CSQRT(Y);\n Y.RE = Y.RE + X.RE;\n Y.IM = Y.IM + X.IM;\n CACOSH_result = CLOG(Y);\n return CACOSH_result;\n}\n\n\nCOMPLEX CADD(COMPLEX X, COMPLEX Y) {\n COMPLEX CADD_result;\n CADD_result.RE = X.RE + Y.RE;\n CADD_result.IM = X.IM + Y.IM;\n return CADD_result;\n}\n\n\nIECStringVar CAPITALIZE(IECStringVar STR) {\n IECStringVar CAPITALIZE_result;\n IEC_Ptr PT;\n IEC_INT POS;\n IEC_INT L;\n IEC_BOOL FIRST = true;\n PT = &(CAPITALIZE_result);\n CAPITALIZE_result = STR;\n L = LEN(STR);\n for (POS = 1; POS <= L; POS++) {\n if (FIRST) {\n (*PT) = TO_UPPER((*PT));\n }\n FIRST = (*PT) == 32;\n PT = PT + 1;\n }\n return CAPITALIZE_result;\n}\n\n\nIEC_REAL CARG(COMPLEX X) {\n IEC_REAL CARG_result;\n CARG_result = ATAN2(X.IM, X.RE);\n return CARG_result;\n}\n\n\nCOMPLEX CASIN(COMPLEX X) {\n COMPLEX CASIN_result;\n COMPLEX Y;\n Y.RE = -X.IM;\n Y.IM = X.RE;\n Y = CASINH(Y);\n CASIN_result.RE = Y.IM;\n CASIN_result.IM = -Y.RE;\n return CASIN_result;\n}\n\n\nCOMPLEX CASINH(COMPLEX X) {\n COMPLEX CASINH_result;\n COMPLEX Y;\n Y.RE = (X.RE - X.IM) * (X.RE + X.IM) + 1.0;\n Y.IM = 2.0 * X.RE * X.IM;\n Y = CSQRT(Y);\n Y.RE = Y.RE + X.RE;\n Y.IM = Y.IM + X.IM;\n CASINH_result = CLOG(Y);\n return CASINH_result;\n}\n\n\nCOMPLEX CATAN(COMPLEX X) {\n COMPLEX CATAN_result;\n IEC_REAL R2;\n IEC_REAL NUM;\n IEC_REAL DEN;\n R2 = X.RE * X.RE;\n DEN = 1.0 - R2 - X.IM * X.IM;\n CATAN_result.RE = 0.5 * ATAN(2.0 * X.RE / DEN);\n NUM = X.IM + 1.0;\n NUM = R2 + NUM * NUM;\n DEN = X.IM - 1.0;\n DEN = R2 + DEN * DEN;\n CATAN_result.IM = 0.25 * (LN(NUM) - LN(DEN));\n return CATAN_result;\n}\n\n\nCOMPLEX CATANH(COMPLEX X) {\n COMPLEX CATANH_result;\n IEC_REAL I2;\n IEC_REAL NUM;\n IEC_REAL DEN;\n I2 = X.IM * X.IM;\n NUM = 1.0 + X.RE;\n NUM = I2 + NUM * NUM;\n DEN = 1.0 - X.RE;\n DEN = I2 + DEN * DEN;\n CATANH_result.RE = 0.25 * (LN(NUM) - LN(DEN));\n DEN = 1 - X.RE * X.RE - I2;\n CATANH_result.IM = 0.5 * ATAN(2.0 * X.IM / DEN);\n return CATANH_result;\n}\n\n\nIEC_REAL CAUCHY(IEC_REAL X, IEC_REAL T, IEC_REAL U) {\n IEC_REAL CAUCHY_result;\n IEC_REAL TMP;\n TMP = X - T;\n CAUCHY_result = MATH.PI_INV * U / (U * U + TMP * TMP);\n return CAUCHY_result;\n}\n\n\nIEC_REAL CAUCHYCD(IEC_REAL X, IEC_REAL T, IEC_REAL U) {\n IEC_REAL CAUCHYCD_result;\n CAUCHYCD_result = 0.5 + MATH.PI_INV * ATAN((X - T) / U);\n return CAUCHYCD_result;\n}\n\n\nCOMPLEX CCON(COMPLEX X) {\n COMPLEX CCON_result;\n CCON_result.RE = X.RE;\n CCON_result.IM = -X.IM;\n return CCON_result;\n}\n\n\nCOMPLEX CCOS(COMPLEX X) {\n COMPLEX CCOS_result;\n CCOS_result = CCOSH(CSET(-X.IM, X.RE));\n return CCOS_result;\n}\n\n\nCOMPLEX CCOSH(COMPLEX X) {\n COMPLEX CCOSH_result;\n CCOSH_result.RE = COSH(X.RE) * COS(X.IM);\n CCOSH_result.IM = SINH(X.RE) * SIN(X.IM);\n return CCOSH_result;\n}\n\n\nCOMPLEX CDIV(COMPLEX X, COMPLEX Y) {\n COMPLEX CDIV_result;\n IEC_REAL TEMP;\n TEMP = Y.RE * Y.RE + Y.IM * Y.IM;\n CDIV_result.RE = (X.RE * Y.RE + X.IM * Y.IM) / TEMP;\n CDIV_result.IM = (X.IM * Y.RE - X.RE * Y.IM) / TEMP;\n return CDIV_result;\n}\n\n\nIEC_INT CEIL(IEC_REAL X) {\n IEC_INT CEIL_result;\n CEIL_result = TO_INT(X);\n if (CEIL_result < X) {\n CEIL_result = CEIL_result + 1;\n }\n return CEIL_result;\n}\n\n\nIEC_DINT CEIL2(IEC_REAL X) {\n IEC_DINT CEIL2_result;\n CEIL2_result = TO_DINT(X);\n if (TO_REAL(CEIL2_result) < X) {\n CEIL2_result = CEIL2_result + 1;\n }\n return CEIL2_result;\n}\n\n\nCOMPLEX CEXP(COMPLEX X) {\n COMPLEX CEXP_result;\n IEC_REAL TEMP;\n TEMP = EXP(X.RE);\n CEXP_result.RE = TEMP * COS(X.IM);\n CEXP_result.IM = TEMP * SIN(X.IM);\n return CEXP_result;\n}\n\n\nIEC_BYTE CHARCODE(IECStringVar<10> STR) {\n IEC_BYTE CHARCODE_result;\n IECStringVar<1> FOUND;\n IECStringVar<10> SEARCH;\n IEC_INT POS;\n IEC_INT I;\n if (LEN(STR) == 1) {\n CHARCODE_result = CODE(STR, 1);\n } else if (STR != \"\") {\n SEARCH = CONCAT(\"&\", STR);\n SEARCH = CONCAT(SEARCH, \";\");\n while ((POS == 0) & ((I < 4))) {\n I = I + 1;\n POS = FIND(SETUP.CHARNAMES[I], SEARCH);\n }\n FOUND = MID(SETUP.CHARNAMES[I], 1, POS - 1);\n CHARCODE_result = CODE(FOUND, 1);\n }\n return CHARCODE_result;\n}\n\n\nIECStringVar<10> CHARNAME(IEC_BYTE C) {\n IECStringVar<10> CHARNAME_result;\n IEC_INT POS;\n IEC_INT I;\n if (C != 0) {\n CHARNAME_result = CHR_TO_STRING(C);\n CHARNAME_result = CONCAT(CHARNAME_result, \"&\");\n CHARNAME_result = CONCAT(\";\", CHARNAME_result);\n while ((POS == 0) & ((I < 4))) {\n I = I + 1;\n POS = FIND(SETUP.CHARNAMES[I], CHARNAME_result);\n }\n if (POS > 0) {\n CHARNAME_result = MID(SETUP.CHARNAMES[I], 10, POS + 3);\n POS = FIND(CHARNAME_result, \";\");\n CHARNAME_result = LEFT(CHARNAME_result, POS - 1);\n } else {\n CHARNAME_result = CHR_TO_STRING(C);\n }\n } else {\n CHARNAME_result = \"\";\n }\n return CHARNAME_result;\n}\n\n\nIEC_BOOL CHECK_PARITY(IEC_DWORD IN, IEC_BOOL P) {\n IEC_BOOL CHECK_PARITY_result;\n CHECK_PARITY_result = !P;\n while (IN > 0) {\n CHECK_PARITY_result = ((((CHECK_PARITY_result) ^ (((static_cast(IN) >> 0) & 1))) ^ (((static_cast(IN) >> 1) & 1))) ^ (((static_cast(IN) >> 2) & 1))) ^ (((static_cast(IN) >> 3) & 1));\n IN = SHR(IN, 4);\n }\n return CHECK_PARITY_result;\n}\n\n\nIEC_BYTE CHK_REAL(IEC_REAL X) {\n IEC_BYTE CHK_REAL_result;\n IEC_Ptr PT;\n IEC_DWORD TMP;\n PT = &(X);\n TMP = ROL((*PT), 1);\n if (TMP < 0xFF000000) {\n CHK_REAL_result = 0x00;\n } else if (TMP == 0xFF000000) {\n CHK_REAL_result = 0x20;\n } else if (TMP == 0xFF000001) {\n CHK_REAL_result = 0x40;\n } else {\n CHK_REAL_result = 0x80;\n }\n return CHK_REAL_result;\n}\n\n\nIECStringVar<1> CHR_TO_STRING(IEC_BYTE C) {\n IECStringVar<1> CHR_TO_STRING_result;\n IEC_Ptr PT;\n PT = &(CHR_TO_STRING_result);\n (*PT) = C;\n PT = PT + 1;\n (*PT) = 0;\n return CHR_TO_STRING_result;\n}\n\n\nCOMPLEX CINV(COMPLEX X) {\n COMPLEX CINV_result;\n IEC_REAL TEMP;\n TEMP = X.RE * X.RE + X.IM * X.IM;\n CINV_result.RE = X.RE / TEMP;\n CINV_result.IM = -X.IM / TEMP;\n return CINV_result;\n}\n\n\nIEC_REAL CIRCLE_A(IEC_REAL RX, IEC_REAL AX) {\n IEC_REAL CIRCLE_A_result;\n CIRCLE_A_result = RX * RX * 0.008726646 * AX;\n return CIRCLE_A_result;\n}\n\n\nIEC_REAL CIRCLE_C(IEC_REAL RX, IEC_REAL AX) {\n IEC_REAL CIRCLE_C_result;\n CIRCLE_C_result = 0.017453293 * RX * AX;\n return CIRCLE_C_result;\n}\n\n\nIEC_REAL CIRCLE_SEG(IEC_REAL RX, IEC_REAL HX) {\n IEC_REAL CIRCLE_SEG_result;\n if (RX > 0.0) {\n CIRCLE_SEG_result = 2.0 * ACOS(1.0 - LIMIT(0.0, HX / RX, 2.0));\n CIRCLE_SEG_result = (CIRCLE_SEG_result - SIN(CIRCLE_SEG_result)) * RX * RX / 2.0;\n }\n return CIRCLE_SEG_result;\n}\n\n\nIECStringVar CLEAN(IECStringVar IN, IECStringVar<80> CX) {\n IECStringVar CLEAN_result;\n IEC_INT POS = 1;\n IEC_INT STOP;\n CLEAN_result = IN;\n STOP = LEN(IN);\n while (POS <= STOP) {\n if (FIND(CX, MID(CLEAN_result, 1, POS)) > 0) {\n POS = POS + 1;\n } else {\n CLEAN_result = DELETE_STR(CLEAN_result, 1, POS);\n STOP = STOP - 1;\n }\n }\n return CLEAN_result;\n}\n\n\nCOMPLEX CLOG(COMPLEX X) {\n COMPLEX CLOG_result;\n CLOG_result.RE = LN(HYPOT(X.RE, X.IM));\n CLOG_result.IM = ATAN2(X.IM, X.RE);\n return CLOG_result;\n}\n\n\nIEC_BOOL CMP(IEC_REAL X, IEC_REAL Y, IEC_INT N) {\n IEC_BOOL CMP_result;\n IEC_REAL TMP;\n TMP = ABS(X);\n if (TMP > 0.0) {\n TMP = EXP10(TO_REAL(FLOOR(LOG(TMP)) - N + 1));\n } else {\n TMP = EXP10(TMP);\n }\n CMP_result = ABS(X - Y) < TMP;\n return CMP_result;\n}\n\n\nCOMPLEX CMUL(COMPLEX X, COMPLEX Y) {\n COMPLEX CMUL_result;\n CMUL_result.RE = X.RE * Y.RE - X.IM * Y.IM;\n CMUL_result.IM = X.RE * Y.IM + X.IM * Y.RE;\n return CMUL_result;\n}\n\n\nIEC_BYTE CODE(IECStringVar STR, IEC_INT POS) {\n IEC_BYTE CODE_result;\n IEC_Ptr PT;\n if ((POS < 1) | (POS > LEN(STR))) {\n CODE_result = 0;\n return CODE_result;\n } else {\n PT = &(STR) + TO_DWORD(POS - 1);\n CODE_result = (*PT);\n }\n return CODE_result;\n}\n\n\nIEC_REAL CONE_V(IEC_REAL RX, IEC_REAL HX) {\n IEC_REAL CONE_V_result;\n CONE_V_result = 1.047197551 * RX * RX * HX;\n return CONE_V_result;\n}\n\n\nIEC_REAL COSH(IEC_REAL X) {\n IEC_REAL COSH_result;\n IEC_REAL T;\n T = EXP(X);\n COSH_result = (1.0 / T + T) * 0.5;\n return COSH_result;\n}\n\n\nIEC_REAL COTH(IEC_REAL X) {\n IEC_REAL COTH_result;\n if (X > 20.0) {\n COTH_result = 1.0;\n } else if (X < -20.0) {\n COTH_result = -1.0;\n } else {\n COTH_result = 1.0 + 2.0 / (EXP(X * 2.0) - 1.0);\n }\n return COTH_result;\n}\n\n\nIEC_INT COUNT_CHAR(IECStringVar STR, IEC_BYTE CHR) {\n IEC_INT COUNT_CHAR_result;\n IEC_INT L;\n IEC_Ptr PT;\n IEC_INT POS;\n PT = &(STR);\n L = LEN(STR);\n COUNT_CHAR_result = 0;\n for (POS = 1; POS <= L; POS++) {\n if ((*PT) == CHR) {\n COUNT_CHAR_result = COUNT_CHAR_result + 1;\n }\n PT = PT + 1;\n }\n return COUNT_CHAR_result;\n}\n\n\nIEC_INT COUNT_SUBSTRING(IEC_STRING SEARCH, IEC_STRING STR) {\n IEC_INT COUNT_SUBSTRING_result;\n IEC_INT POS;\n IEC_INT SIZE;\n COUNT_SUBSTRING_result = 0;\n SIZE = LEN(SEARCH);\n do {\n POS = FIND(STR, SEARCH);\n if (POS > 0) {\n STR = REPLACE(STR, \"\", SIZE, POS);\n COUNT_SUBSTRING_result = COUNT_SUBSTRING_result + 1;\n }\n } while (!(POS == 0));\n return COUNT_SUBSTRING_result;\n}\n\n\nCOMPLEX CPOL(IEC_REAL L, IEC_REAL A) {\n COMPLEX CPOL_result;\n CPOL_result.RE = L * COS(A);\n CPOL_result.IM = L * SIN(A);\n return CPOL_result;\n}\n\n\nCOMPLEX CPOW(COMPLEX X, COMPLEX Y) {\n COMPLEX CPOW_result;\n CPOW_result = CEXP(CMUL(Y, CLOG(X)));\n return CPOW_result;\n}\n\n\nIEC_DWORD CRC_GEN(IEC_Ptr> PT, IEC_INT SIZE, IEC_INT PL, IEC_DWORD PN, IEC_DWORD INIT, IEC_BOOL REV_IN, IEC_BOOL REV_OUT, IEC_DWORD XOR_OUT) {\n IEC_DWORD CRC_GEN_result;\n IEC_INT POS;\n IEC_INT SHIFT;\n IEC_BYTE DX;\n IEC_INT BITS;\n SHIFT = 32 - PL;\n PN = SHL(PN, SHIFT);\n for (POS = 0; POS <= 3; POS++) {\n if (REV_IN) {\n CRC_GEN_result = (SHL(CRC_GEN_result, 8)) | (REVERSE((*PT)[POS]));\n } else {\n CRC_GEN_result = (SHL(CRC_GEN_result, 8)) | ((*PT)[POS]);\n }\n }\n POS = 4;\n CRC_GEN_result = (CRC_GEN_result) ^ (SHL(INIT, SHIFT));\n while (POS < SIZE) {\n if (REV_IN) {\n DX = REVERSE((*PT)[POS]);\n } else {\n DX = (*PT)[POS];\n }\n POS = POS + 1;\n for (BITS = 0; BITS <= 7; BITS++) {\n if (((static_cast(CRC_GEN_result) >> 31) & 1)) {\n CRC_GEN_result = (((SHL(CRC_GEN_result, 1)) | (TO_DWORD(((static_cast(DX) >> 7) & 1))))) ^ (PN);\n } else {\n CRC_GEN_result = (SHL(CRC_GEN_result, 1)) | (TO_DWORD(((static_cast(DX) >> 7) & 1)));\n }\n DX = SHL(DX, 1);\n }\n }\n for (BITS = 0; BITS <= 31; BITS++) {\n if (((static_cast(CRC_GEN_result) >> 31) & 1)) {\n CRC_GEN_result = ((SHL(CRC_GEN_result, 1))) ^ (PN);\n } else {\n CRC_GEN_result = SHL(CRC_GEN_result, 1);\n }\n }\n CRC_GEN_result = (SHR(CRC_GEN_result, SHIFT)) ^ (XOR_OUT);\n if (REV_OUT) {\n CRC_GEN_result = REFLECT(CRC_GEN_result, PL);\n }\n return CRC_GEN_result;\n}\n\n\nCOMPLEX CSET(IEC_REAL RE, IEC_REAL IM) {\n COMPLEX CSET_result;\n CSET_result.RE = RE;\n CSET_result.IM = IM;\n return CSET_result;\n}\n\n\nCOMPLEX CSIN(COMPLEX X) {\n COMPLEX CSIN_result;\n CSIN_result.RE = COSH(X.IM) * SIN(X.RE);\n CSIN_result.IM = SINH(X.IM) * COS(X.RE);\n return CSIN_result;\n}\n\n\nCOMPLEX CSINH(COMPLEX X) {\n COMPLEX CSINH_result;\n CSINH_result.RE = SINH(X.RE) * COS(X.IM);\n CSINH_result.IM = COSH(X.RE) * SIN(X.IM);\n return CSINH_result;\n}\n\n\nCOMPLEX CSQRT(COMPLEX X) {\n COMPLEX CSQRT_result;\n IEC_REAL TEMP;\n TEMP = HYPOT(X.RE, X.IM);\n CSQRT_result.RE = SQRT(0.5 * (TEMP + X.RE));\n CSQRT_result.IM = SGN(X.IM) * SQRT(0.5 * (TEMP - X.RE));\n return CSQRT_result;\n}\n\n\nCOMPLEX CSUB(COMPLEX X, COMPLEX Y) {\n COMPLEX CSUB_result;\n CSUB_result.RE = X.RE - Y.RE;\n CSUB_result.IM = X.IM - Y.IM;\n return CSUB_result;\n}\n\n\nCOMPLEX CTAN(COMPLEX X) {\n COMPLEX CTAN_result;\n IEC_REAL TEMP;\n IEC_REAL XI2;\n IEC_REAL XR2;\n XI2 = 2.0 * X.IM;\n XR2 = 2.0 * X.RE;\n TEMP = 1.0 / (COS(XR2) + COSH(XI2));\n CTAN_result.RE = TEMP * SIN(XR2);\n CTAN_result.IM = TEMP * SINH(XI2);\n return CTAN_result;\n}\n\n\nCOMPLEX CTANH(COMPLEX X) {\n COMPLEX CTANH_result;\n IEC_REAL TEMP;\n IEC_REAL XI2;\n IEC_REAL XR2;\n XI2 = 2.0 * X.IM;\n XR2 = 2.0 * X.RE;\n TEMP = 1.0 / (COSH(XR2) + COS(XI2));\n CTANH_result.RE = TEMP * SINH(XR2);\n CTANH_result.IM = TEMP * SIN(XI2);\n return CTANH_result;\n}\n\n\nIEC_REAL CTRL_IN(IEC_REAL SET_POINT, IEC_REAL ACTUAL, IEC_REAL NOISE) {\n IEC_REAL CTRL_IN_result;\n CTRL_IN_result = DEAD_ZONE(SET_POINT - ACTUAL, NOISE);\n return CTRL_IN_result;\n}\n\n\nIEC_REAL C_TO_F(IEC_REAL CELSIUS) {\n IEC_REAL C_TO_F_result;\n C_TO_F_result = CELSIUS * 1.8 + 32.0;\n return C_TO_F_result;\n}\n\n\nIEC_REAL C_TO_K(IEC_REAL CELSIUS) {\n IEC_REAL C_TO_K_result;\n C_TO_K_result = CELSIUS - PHYS.T0;\n return C_TO_K_result;\n}\n\n\nIEC_DATE DATE_ADD(IEC_DATE IDATE, IEC_INT D, IEC_INT W, IEC_INT M, IEC_INT Y) {\n IEC_DATE DATE_ADD_result;\n IEC_INT MO;\n IEC_INT YR;\n IEC_INT DM;\n DATE_ADD_result = TO_DATE(TO_UDINT(IDATE) + TO_UDINT(D + W * 7) * static_cast(86400));\n YR = Y + YEAR_OF_DATE(DATE_ADD_result);\n MO = M + MONTH_OF_DATE(DATE_ADD_result);\n DM = DAY_OF_MONTH(DATE_ADD_result);\n while (MO > 12) {\n MO = MO - 12;\n YR = YR + 1;\n }\n while (MO < 1) {\n MO = MO + 12;\n YR = YR - 1;\n }\n DATE_ADD_result = SET_DATE(YR, MO, DM);\n return DATE_ADD_result;\n}\n\n\nIEC_DINT DAYS_DELTA(IEC_DATE DATE_1, IEC_DATE DATE_2) {\n IEC_DINT DAYS_DELTA_result;\n if (DATE_1 > DATE_2) {\n DAYS_DELTA_result = -TO_DINT((TO_DWORD(DATE_1) - TO_DWORD(DATE_2)) / 86400);\n } else {\n DAYS_DELTA_result = TO_DINT((TO_DWORD(DATE_2) - TO_DWORD(DATE_1)) / 86400);\n }\n return DAYS_DELTA_result;\n}\n\n\nIEC_INT DAYS_IN_MONTH(IEC_DATE IDATE) {\n IEC_INT DAYS_IN_MONTH_result;\n DAYS_IN_MONTH_result = DAY_OF_YEAR(IDATE);\n if (LEAP_OF_DATE(IDATE)) {\n switch (DAYS_IN_MONTH_result) {\n case 32:\n case 33:\n case 34:\n case 35:\n case 36:\n case 37:\n case 38:\n case 39:\n case 40:\n case 41:\n case 42:\n case 43:\n case 44:\n case 45:\n case 46:\n case 47:\n case 48:\n case 49:\n case 50:\n case 51:\n case 52:\n case 53:\n case 54:\n case 55:\n case 56:\n case 57:\n case 58:\n case 59:\n case 60:\n DAYS_IN_MONTH_result = 29;\n break;\n case 92:\n case 93:\n case 94:\n case 95:\n case 96:\n case 97:\n case 98:\n case 99:\n case 100:\n case 101:\n case 102:\n case 103:\n case 104:\n case 105:\n case 106:\n case 107:\n case 108:\n case 109:\n case 110:\n case 111:\n case 112:\n case 113:\n case 114:\n case 115:\n case 116:\n case 117:\n case 118:\n case 119:\n case 120:\n case 121:\n DAYS_IN_MONTH_result = 30;\n break;\n case 153:\n case 154:\n case 155:\n case 156:\n case 157:\n case 158:\n case 159:\n case 160:\n case 161:\n case 162:\n case 163:\n case 164:\n case 165:\n case 166:\n case 167:\n case 168:\n case 169:\n case 170:\n case 171:\n case 172:\n case 173:\n case 174:\n case 175:\n case 176:\n case 177:\n case 178:\n case 179:\n case 180:\n case 181:\n case 182:\n DAYS_IN_MONTH_result = 30;\n break;\n case 245:\n case 246:\n case 247:\n case 248:\n case 249:\n case 250:\n case 251:\n case 252:\n case 253:\n case 254:\n case 255:\n case 256:\n case 257:\n case 258:\n case 259:\n case 260:\n case 261:\n case 262:\n case 263:\n case 264:\n case 265:\n case 266:\n case 267:\n case 268:\n case 269:\n case 270:\n case 271:\n case 272:\n case 273:\n case 274:\n DAYS_IN_MONTH_result = 30;\n break;\n case 306:\n case 307:\n case 308:\n case 309:\n case 310:\n case 311:\n case 312:\n case 313:\n case 314:\n case 315:\n case 316:\n case 317:\n case 318:\n case 319:\n case 320:\n case 321:\n case 322:\n case 323:\n case 324:\n case 325:\n case 326:\n case 327:\n case 328:\n case 329:\n case 330:\n case 331:\n case 332:\n case 333:\n case 334:\n case 335:\n DAYS_IN_MONTH_result = 30;\n break;\n default:\n DAYS_IN_MONTH_result = 31;\n break;\n }\n } else {\n switch (DAYS_IN_MONTH_result) {\n case 32:\n case 33:\n case 34:\n case 35:\n case 36:\n case 37:\n case 38:\n case 39:\n case 40:\n case 41:\n case 42:\n case 43:\n case 44:\n case 45:\n case 46:\n case 47:\n case 48:\n case 49:\n case 50:\n case 51:\n case 52:\n case 53:\n case 54:\n case 55:\n case 56:\n case 57:\n case 58:\n case 59:\n DAYS_IN_MONTH_result = 28;\n break;\n case 91:\n case 92:\n case 93:\n case 94:\n case 95:\n case 96:\n case 97:\n case 98:\n case 99:\n case 100:\n case 101:\n case 102:\n case 103:\n case 104:\n case 105:\n case 106:\n case 107:\n case 108:\n case 109:\n case 110:\n case 111:\n case 112:\n case 113:\n case 114:\n case 115:\n case 116:\n case 117:\n case 118:\n case 119:\n case 120:\n DAYS_IN_MONTH_result = 30;\n break;\n case 152:\n case 153:\n case 154:\n case 155:\n case 156:\n case 157:\n case 158:\n case 159:\n case 160:\n case 161:\n case 162:\n case 163:\n case 164:\n case 165:\n case 166:\n case 167:\n case 168:\n case 169:\n case 170:\n case 171:\n case 172:\n case 173:\n case 174:\n case 175:\n case 176:\n case 177:\n case 178:\n case 179:\n case 180:\n case 181:\n DAYS_IN_MONTH_result = 30;\n break;\n case 244:\n case 245:\n case 246:\n case 247:\n case 248:\n case 249:\n case 250:\n case 251:\n case 252:\n case 253:\n case 254:\n case 255:\n case 256:\n case 257:\n case 258:\n case 259:\n case 260:\n case 261:\n case 262:\n case 263:\n case 264:\n case 265:\n case 266:\n case 267:\n case 268:\n case 269:\n case 270:\n case 271:\n case 272:\n case 273:\n DAYS_IN_MONTH_result = 30;\n break;\n case 305:\n case 306:\n case 307:\n case 308:\n case 309:\n case 310:\n case 311:\n case 312:\n case 313:\n case 314:\n case 315:\n case 316:\n case 317:\n case 318:\n case 319:\n case 320:\n case 321:\n case 322:\n case 323:\n case 324:\n case 325:\n case 326:\n case 327:\n case 328:\n case 329:\n case 330:\n case 331:\n case 332:\n case 333:\n case 334:\n DAYS_IN_MONTH_result = 30;\n break;\n default:\n DAYS_IN_MONTH_result = 31;\n break;\n }\n }\n return DAYS_IN_MONTH_result;\n}\n\n\nIEC_INT DAYS_IN_YEAR(IEC_DATE IDATE) {\n IEC_INT DAYS_IN_YEAR_result;\n if (LEAP_OF_DATE(IDATE)) {\n DAYS_IN_YEAR_result = 366;\n } else {\n DAYS_IN_YEAR_result = 365;\n }\n return DAYS_IN_YEAR_result;\n}\n\n\nIEC_DINT DAY_OF_DATE(IEC_DATE IDATE) {\n IEC_DINT DAY_OF_DATE_result;\n DAY_OF_DATE_result = TO_DINT(TO_DWORD(IDATE) / 86400);\n return DAY_OF_DATE_result;\n}\n\n\nIEC_INT DAY_OF_MONTH(IEC_DATE IDATE) {\n IEC_INT DAY_OF_MONTH_result;\n IEC_INT LEAP;\n DAY_OF_MONTH_result = DAY_OF_YEAR(IDATE);\n LEAP = TO_INT(LEAP_OF_DATE(IDATE));\n DAY_OF_MONTH_result = DAY_OF_MONTH_result - LEAP;\n if (DAY_OF_MONTH_result > SETUP.MTH_OFS[9]) {\n if (DAY_OF_MONTH_result > SETUP.MTH_OFS[11]) {\n if (DAY_OF_MONTH_result > SETUP.MTH_OFS[12]) {\n DAY_OF_MONTH_result = DAY_OF_MONTH_result - SETUP.MTH_OFS[12];\n } else {\n DAY_OF_MONTH_result = DAY_OF_MONTH_result - SETUP.MTH_OFS[11];\n }\n } else {\n if (DAY_OF_MONTH_result > SETUP.MTH_OFS[10]) {\n DAY_OF_MONTH_result = DAY_OF_MONTH_result - SETUP.MTH_OFS[10];\n } else {\n DAY_OF_MONTH_result = DAY_OF_MONTH_result - SETUP.MTH_OFS[9];\n }\n }\n } else if (DAY_OF_MONTH_result > SETUP.MTH_OFS[5]) {\n if (DAY_OF_MONTH_result > SETUP.MTH_OFS[7]) {\n if (DAY_OF_MONTH_result > SETUP.MTH_OFS[8]) {\n DAY_OF_MONTH_result = DAY_OF_MONTH_result - SETUP.MTH_OFS[8];\n } else {\n DAY_OF_MONTH_result = DAY_OF_MONTH_result - SETUP.MTH_OFS[7];\n }\n } else {\n if (DAY_OF_MONTH_result > SETUP.MTH_OFS[6]) {\n DAY_OF_MONTH_result = DAY_OF_MONTH_result - SETUP.MTH_OFS[6];\n } else {\n DAY_OF_MONTH_result = DAY_OF_MONTH_result - SETUP.MTH_OFS[5];\n }\n }\n } else if (DAY_OF_MONTH_result > SETUP.MTH_OFS[3]) {\n if (DAY_OF_MONTH_result > SETUP.MTH_OFS[4]) {\n DAY_OF_MONTH_result = DAY_OF_MONTH_result - SETUP.MTH_OFS[4];\n } else {\n DAY_OF_MONTH_result = DAY_OF_MONTH_result - SETUP.MTH_OFS[3];\n }\n } else {\n DAY_OF_MONTH_result = DAY_OF_MONTH_result + LEAP;\n if (DAY_OF_MONTH_result > SETUP.MTH_OFS[2]) {\n DAY_OF_MONTH_result = DAY_OF_MONTH_result - SETUP.MTH_OFS[2];\n }\n }\n return DAY_OF_MONTH_result;\n}\n\n\nIEC_INT DAY_OF_WEEK(IEC_DATE IDATE) {\n IEC_INT DAY_OF_WEEK_result;\n DAY_OF_WEEK_result = TO_INT((TO_DWORD(IDATE) / 86400 + 3) % 7) + 1;\n return DAY_OF_WEEK_result;\n}\n\n\nIEC_INT DAY_OF_YEAR(IEC_DATE IDATE) {\n IEC_INT DAY_OF_YEAR_result;\n DAY_OF_YEAR_result = TO_INT((TO_UDINT(IDATE) / static_cast(86400)) % static_cast(1461));\n if (DAY_OF_YEAR_result > 729) {\n if (DAY_OF_YEAR_result > 1095) {\n DAY_OF_YEAR_result = DAY_OF_YEAR_result - 1095;\n } else {\n DAY_OF_YEAR_result = DAY_OF_YEAR_result - 729;\n }\n } else if (DAY_OF_YEAR_result > 364) {\n DAY_OF_YEAR_result = DAY_OF_YEAR_result - 364;\n } else {\n DAY_OF_YEAR_result = DAY_OF_YEAR_result + 1;\n }\n return DAY_OF_YEAR_result;\n}\n\n\nIEC_TIME DAY_TO_TIME(IEC_REAL IN) {\n IEC_TIME DAY_TO_TIME_result;\n DAY_TO_TIME_result = TO_TIME(TO_DWORD(IN * 86400000.0));\n return DAY_TO_TIME_result;\n}\n\n\nIEC_REAL DEAD_BAND(IEC_REAL X, IEC_REAL L) {\n IEC_REAL DEAD_BAND_result;\n if (X > L) {\n DEAD_BAND_result = X - L;\n } else if (X < -L) {\n DEAD_BAND_result = X + L;\n } else {\n DEAD_BAND_result = 0.0;\n }\n return DEAD_BAND_result;\n}\n\n\nIEC_REAL DEAD_ZONE(IEC_REAL X, IEC_REAL L) {\n IEC_REAL DEAD_ZONE_result;\n if (ABS(X) > L) {\n DEAD_ZONE_result = X;\n } else {\n DEAD_ZONE_result = 0.0;\n }\n return DEAD_ZONE_result;\n}\n\n\nIEC_INT DEC1(IEC_INT X, IEC_INT N) {\n IEC_INT DEC1_result;\n if (X == 0) {\n DEC1_result = N - 1;\n } else {\n DEC1_result = X - 1;\n }\n return DEC1_result;\n}\n\n\nIEC_BYTE DEC_TO_BYTE(IECStringVar<10> DEC) {\n IEC_BYTE DEC_TO_BYTE_result;\n IEC_Ptr PT;\n IEC_INT I;\n IEC_BYTE X;\n IEC_INT STOP;\n PT = &(DEC);\n STOP = LEN(DEC);\n for (I = 1; I <= STOP; I++) {\n X = (*PT);\n if ((X > 47) & (X < 58)) {\n DEC_TO_BYTE_result = DEC_TO_BYTE_result * 10 + X - 48;\n }\n PT = PT + 1;\n }\n return DEC_TO_BYTE_result;\n}\n\n\nIEC_DWORD DEC_TO_DWORD(IECStringVar<20> DEC) {\n IEC_DWORD DEC_TO_DWORD_result;\n IEC_Ptr PT;\n IEC_INT I;\n IEC_BYTE X;\n IEC_INT STOP;\n PT = &(DEC);\n STOP = LEN(DEC);\n for (I = 1; I <= STOP; I++) {\n X = (*PT);\n if ((X > 47) & (X < 58)) {\n DEC_TO_DWORD_result = DEC_TO_DWORD_result * 10 + X - 48;\n }\n PT = PT + 1;\n }\n return DEC_TO_DWORD_result;\n}\n\n\nIEC_INT DEC_TO_INT(IECStringVar<10> DEC) {\n IEC_INT DEC_TO_INT_result;\n IEC_Ptr PT;\n IEC_INT I;\n IEC_BYTE X;\n IEC_BOOL SIGN;\n IEC_INT STOP;\n PT = &(DEC);\n STOP = LEN(DEC);\n for (I = 1; I <= STOP; I++) {\n X = (*PT);\n if ((X > 47) & (X < 58)) {\n DEC_TO_INT_result = DEC_TO_INT_result * 10 + X - 48;\n } else if ((X == 45) & (DEC_TO_INT_result == 0)) {\n SIGN = true;\n }\n PT = PT + 1;\n }\n if (SIGN) {\n DEC_TO_INT_result = -DEC_TO_INT_result;\n }\n return DEC_TO_INT_result;\n}\n\n\nIEC_REAL DEG(IEC_REAL RAD) {\n IEC_REAL DEG_result;\n DEG_result = MODR(57.29577951308232 * RAD, 360.0);\n return DEG_result;\n}\n\n\nIECStringVar<3> DEG_TO_DIR(IEC_INT DEG, IEC_INT N, IEC_INT L) {\n IECStringVar<3> DEG_TO_DIR_result;\n IEC_INT LY;\n if (L == 0) {\n LY = LANGUAGE.DEFAULT;\n } else {\n LY = MIN(L, LANGUAGE.LMAX);\n }\n DEG_TO_DIR_result = LANGUAGE.DIRS(LY, ((SHL(DEG, N - 1) + 45) / 90) % SHL(static_cast(2), N) * SHR(static_cast(8), N));\n return DEG_TO_DIR_result;\n}\n\n\nIECStringVar DEL_CHARS(IECStringVar IN, IECStringVar<80> CX) {\n IECStringVar DEL_CHARS_result;\n IEC_INT POS = 1;\n IEC_INT STOP;\n DEL_CHARS_result = IN;\n STOP = LEN(IN);\n while (POS <= STOP) {\n if (FIND(CX, MID(DEL_CHARS_result, 1, POS)) > 0) {\n DEL_CHARS_result = DELETE_STR(DEL_CHARS_result, 1, POS);\n STOP = STOP - 1;\n } else {\n POS = POS + 1;\n }\n }\n return DEL_CHARS_result;\n}\n\n\nIEC_BOOL DIFFER(IEC_REAL IN1, IEC_REAL IN2, IEC_REAL X) {\n IEC_BOOL DIFFER_result;\n DIFFER_result = ABS(IN1 - IN2) > X;\n return DIFFER_result;\n}\n\n\nIEC_INT DIR_TO_DEG(IECStringVar<3> DIR, IEC_INT L) {\n IEC_INT DIR_TO_DEG_result;\n IEC_INT LY;\n IEC_INT I;\n if (L == 0) {\n LY = LANGUAGE.DEFAULT;\n } else {\n LY = MIN(L, LANGUAGE.LMAX);\n }\n for (I = 0; I <= 15; I++) {\n if (LANGUAGE.DIRS(LY, I) == DIR) {\n goto __strucpp_loop_exit_55;\n }\n }\n __strucpp_loop_exit_55: ;\n DIR_TO_DEG_result = SHR(I * 45 + 1, 1);\n return DIR_TO_DEG_result;\n}\n\n\nIEC_BOOL DST(IEC_DT UTC) {\n IEC_BOOL DST_result;\n IEC_INT YR;\n IEC_DWORD YR4;\n IEC_DWORD LTC;\n IEC_DWORD IDATE;\n YR = YEAR_OF_DATE(TO_DATE(UTC));\n LTC = TO_DWORD(UTC);\n IDATE = TO_DWORD(SET_DT(YR, 3, 31, 1, 0, 0));\n YR4 = SHR(5 * TO_DWORD(YR), 2) + 1;\n DST_result = ((IDATE - ((YR4 + 3) % 7) * 86400 <= LTC)) & ((IDATE + (214 - (YR4) % 7) * 86400 > LTC));\n return DST_result;\n}\n\n\nSDT DT2_TO_SDT(IEC_DATE DI, IEC_TOD TI) {\n SDT DT2_TO_SDT_result;\n DT2_TO_SDT_result.YEAR = YEAR_OF_DATE(DI);\n DT2_TO_SDT_result.MONTH = MONTH_OF_DATE(DI);\n DT2_TO_SDT_result.DAY = DAY_OF_MONTH(DI);\n DT2_TO_SDT_result.WEEKDAY = DAY_OF_WEEK(DI);\n DT2_TO_SDT_result.MS = TO_INT(TO_DWORD(TI) % 1000);\n DT2_TO_SDT_result.SECOND = TO_INT((TO_DWORD(TI) / 1000) % 60);\n DT2_TO_SDT_result.MINUTE = TO_INT((TO_DWORD(TI) / 60000) % 60);\n DT2_TO_SDT_result.HOUR = TO_INT(TO_DWORD(TI) / 3600000);\n return DT2_TO_SDT_result;\n}\n\n\nSDT DT_TO_SDT(IEC_DT DTI) {\n SDT DT_TO_SDT_result;\n IEC_DATE TMP;\n IEC_DWORD TDT;\n TMP = TO_DATE(DTI);\n TDT = TO_DWORD(DTI) - TO_DWORD(TMP);\n DT_TO_SDT_result.YEAR = YEAR_OF_DATE(TMP);\n DT_TO_SDT_result.MONTH = MONTH_OF_DATE(TMP);\n DT_TO_SDT_result.DAY = DAY_OF_MONTH(TMP);\n DT_TO_SDT_result.WEEKDAY = DAY_OF_WEEK(TMP);\n DT_TO_SDT_result.SECOND = TO_INT(TDT % 60);\n DT_TO_SDT_result.MINUTE = TO_INT((TDT / 60) % 60);\n DT_TO_SDT_result.HOUR = TO_INT(TDT / 3600);\n return DT_TO_SDT_result;\n}\n\n\nIEC_STRING DT_TO_STRF(IEC_DT DTI, IEC_INT MS, IEC_STRING FMT, IEC_INT LANG) {\n IEC_STRING DT_TO_STRF_result;\n IECStringVar<1> FILL = \"0\";\n IECStringVar<1> BLANK = \" \";\n IEC_INT LY;\n IEC_DATE DX;\n IECStringVar<10> FS;\n IEC_TOD TD;\n IEC_INT TMP;\n IEC_INT POS;\n IEC_INT F;\n if (LANG < 1) {\n LY = LANGUAGE.DEFAULT;\n } else {\n LY = MIN(LANGUAGE.LMAX, LANG);\n }\n DX = TO_DATE(DTI);\n TD = TO_TOD(DTI);\n DT_TO_STRF_result = FMT;\n POS = FIND(DT_TO_STRF_result, \"#\");\n while (POS > 0) {\n F = CODE(DT_TO_STRF_result, POS + 1);\n FS = \"\";\n switch (F) {\n case 65:\n FS = TO_STRING(YEAR_OF_DATE(DX));\n break;\n case 66:\n FS = RIGHT(TO_STRING(YEAR_OF_DATE(DX)), 2);\n break;\n case 67:\n FS = TO_STRING(MONTH_OF_DATE(DX));\n break;\n case 68:\n FS = TO_STRING(MONTH_OF_DATE(DX));\n if (LEN(FS) < 2) {\n FS = CONCAT(\"0\", FS);\n }\n break;\n case 69:\n FS = MONTH_TO_STRING(MONTH_OF_DATE(DX), LY, 3);\n break;\n case 70:\n FS = MONTH_TO_STRING(MONTH_OF_DATE(DX), LY, 0);\n break;\n case 71:\n FS = TO_STRING(DAY_OF_MONTH(DX));\n break;\n case 72:\n FS = TO_STRING(DAY_OF_MONTH(DX));\n if (LEN(FS) < 2) {\n FS = CONCAT(FILL, FS);\n }\n break;\n case 73:\n FS = TO_STRING(DAY_OF_WEEK(DX));\n break;\n case 74:\n FS = WEEKDAY_TO_STRING(DAY_OF_WEEK(DX), LY, 2);\n break;\n case 75:\n FS = WEEKDAY_TO_STRING(DAY_OF_WEEK(DX), LY, 0);\n break;\n case 76:\n if (TD >= 0) {\n FS = \"PM\";\n } else {\n FS = \"AM\";\n }\n break;\n case 77:\n FS = TO_STRING(HOUR(TD));\n break;\n case 78:\n FS = TO_STRING(HOUR(TD));\n if (LEN(FS) < 2) {\n FS = CONCAT(FILL, FS);\n }\n break;\n case 79:\n TMP = HOUR(TD) % 12;\n if (TMP == 0) {\n TMP = 12;\n }\n FS = TO_STRING(TMP);\n break;\n case 80:\n TMP = HOUR(TD) % 12;\n if (TMP == 0) {\n TMP = 12;\n }\n FS = TO_STRING(TMP);\n if (LEN(FS) < 2) {\n FS = CONCAT(FILL, FS);\n }\n break;\n case 81:\n FS = TO_STRING(MINUTE(TD));\n break;\n case 82:\n FS = TO_STRING(MINUTE(TD));\n if (LEN(FS) < 2) {\n FS = CONCAT(FILL, FS);\n }\n break;\n case 83:\n FS = TO_STRING(TO_INT(SECOND(TD)));\n break;\n case 84:\n FS = TO_STRING(TO_INT(SECOND(TD)));\n if (LEN(FS) < 2) {\n FS = CONCAT(FILL, FS);\n }\n break;\n case 85:\n FS = TO_STRING(MS);\n break;\n case 86:\n FS = TO_STRING(MS);\n FS = CONCAT(\"00\", FS);\n FS = RIGHT(FS, 3);\n break;\n case 87:\n FS = TO_STRING(DAY_OF_MONTH(DX));\n if (LEN(FS) < 2) {\n FS = CONCAT(BLANK, FS);\n }\n break;\n case 88:\n FS = TO_STRING(MONTH_OF_DATE(DX));\n if (LEN(FS) < 2) {\n FS = CONCAT(BLANK, FS);\n }\n break;\n }\n DT_TO_STRF_result = REPLACE(DT_TO_STRF_result, FS, 2, POS);\n POS = FIND(DT_TO_STRF_result, \"#\");\n }\n return DT_TO_STRF_result;\n}\n\n\nIEC_DWORD DWORD_OF_BYTE(IEC_BYTE B3, IEC_BYTE B2, IEC_BYTE B1, IEC_BYTE B0) {\n IEC_DWORD DWORD_OF_BYTE_result;\n DWORD_OF_BYTE_result = (SHL((SHL((SHL(TO_DWORD(B3), 8)) | (TO_DWORD(B2)), 8)) | (TO_DWORD(B1)), 8)) | (TO_DWORD(B0));\n return DWORD_OF_BYTE_result;\n}\n\n\nIEC_DWORD DWORD_OF_WORD(IEC_WORD W1, IEC_WORD W0) {\n IEC_DWORD DWORD_OF_WORD_result;\n DWORD_OF_WORD_result = (SHL(TO_DWORD(W1), 16)) | (TO_DWORD(W0));\n return DWORD_OF_WORD_result;\n}\n\n\nIECStringVar<32> DWORD_TO_STRB(IEC_DWORD IN) {\n IECStringVar<32> DWORD_TO_STRB_result;\n IEC_Ptr PT;\n IEC_INT I;\n PT = &(DWORD_TO_STRB_result);\n for (I = 1; I <= 32; I++) {\n (*PT) = TO_BYTE(((static_cast(IN) >> 31) & 1)) + 48;\n IN = SHL(IN, 1);\n PT = PT + 1;\n }\n (*PT) = 0;\n return DWORD_TO_STRB_result;\n}\n\n\nIECStringVar<20> DWORD_TO_STRF(IEC_DWORD IN, IEC_INT N) {\n IECStringVar<20> DWORD_TO_STRF_result;\n DWORD_TO_STRF_result = FIX(TO_STRING(IN), LIMIT(0, N, 20), static_cast(48), 1);\n return DWORD_TO_STRF_result;\n}\n\n\nIECStringVar<8> DWORD_TO_STRH(IEC_DWORD IN) {\n IECStringVar<8> DWORD_TO_STRH_result;\n IEC_INT I;\n IEC_BYTE TEMP;\n IEC_Ptr PT;\n PT = &(DWORD_TO_STRH_result) + 8;\n (*PT) = 0;\n for (I = 1; I <= 8; I++) {\n PT = PT - 1;\n TEMP = TO_BYTE((IN) & (0x0000000F));\n if (TEMP <= 9) {\n TEMP = TEMP + 48;\n } else {\n TEMP = TEMP + 55;\n }\n (*PT) = TEMP;\n IN = SHR(IN, 4);\n }\n return DWORD_TO_STRH_result;\n}\n\n\nIEC_REAL DW_TO_REAL(IEC_DWORD X) {\n IEC_REAL DW_TO_REAL_result;\n IEC_Ptr PT;\n PT = &(X);\n DW_TO_REAL_result = (*PT);\n return DW_TO_REAL_result;\n}\n\n\nIEC_DINT D_TRUNC(IEC_REAL X) {\n IEC_DINT D_TRUNC_result;\n D_TRUNC_result = TO_DINT(X);\n if (X > 0.0) {\n if (TO_REAL(D_TRUNC_result) > X) {\n D_TRUNC_result = D_TRUNC_result - 1;\n }\n } else {\n if (TO_REAL(D_TRUNC_result) < X) {\n D_TRUNC_result = D_TRUNC_result + 1;\n }\n }\n return D_TRUNC_result;\n}\n\n\nIEC_DATE EASTER(IEC_INT YEAR) {\n IEC_DATE EASTER_result;\n IEC_INT B;\n IEC_INT C;\n IEC_INT ODAY;\n B = (204 - 11 * (YEAR % 19)) % 30;\n if (B > 27) {\n B = B - 1;\n }\n C = (YEAR + SHR(YEAR, 2) + B - 13) % 7;\n ODAY = 28 + B - C;\n if (ODAY > 33) {\n EASTER_result = SET_DATE(YEAR, 4, ODAY - 31);\n } else {\n EASTER_result = SET_DATE(YEAR, 3, ODAY);\n }\n return EASTER_result;\n}\n\n\nIEC_REAL ELLIPSE_A(IEC_REAL R1, IEC_REAL R2) {\n IEC_REAL ELLIPSE_A_result;\n ELLIPSE_A_result = MATH.PI * R1 * R2;\n return ELLIPSE_A_result;\n}\n\n\nIEC_REAL ELLIPSE_C(IEC_REAL R1, IEC_REAL R2) {\n IEC_REAL ELLIPSE_C_result;\n ELLIPSE_C_result = MATH.PI * (3.0 * (R1 + R2) - SQRT((3.0 * R1 + R2) * (3.0 * R2 + R1)));\n return ELLIPSE_C_result;\n}\n\n\nIEC_REAL ERF(IEC_REAL X) {\n IEC_REAL ERF_result;\n IEC_REAL X2;\n IEC_REAL AX2;\n X2 = X * X;\n AX2 = 0.147 * X2 + 1.0;\n ERF_result = SQRT(1.0 - EXP(-X2 * ((0.27323954473516 + AX2) / (AX2)))) * SGN(X);\n return ERF_result;\n}\n\n\nIEC_REAL ERFC(IEC_REAL X) {\n IEC_REAL ERFC_result;\n ERFC_result = 1.0 - ERF(X);\n return ERFC_result;\n}\n\n\nIEC_BOOL EVEN(IEC_DINT IN) {\n IEC_BOOL EVEN_result;\n EVEN_result = !((static_cast(IN) >> 0) & 1);\n return EVEN_result;\n}\n\n\nIECStringVar EXEC(IECStringVar STR) {\n IECStringVar EXEC_result;\n IEC_INT POS;\n IEC_REAL R1;\n IEC_REAL R2;\n IECStringVar<10> OPERATOR;\n EXEC_result = UPPERCASE(TRIM(STR));\n POS = FINDB_NONUM(EXEC_result);\n if (POS > 1) {\n R1 = TO_REAL(LEFT(EXEC_result, POS - 1));\n }\n R2 = TO_REAL(RIGHT(EXEC_result, LEN(EXEC_result) - POS));\n EXEC_result = LEFT(EXEC_result, POS);\n POS = FINDB_NUM(EXEC_result);\n OPERATOR = RIGHT(EXEC_result, LEN(EXEC_result) - POS);\n if ((OPERATOR == \"\") & (LEN(STR) == 0)) {\n EXEC_result = \"\";\n return EXEC_result;\n } else if (OPERATOR == \"\") {\n EXEC_result = STR;\n return EXEC_result;\n }\n if (OPERATOR == \"^\") {\n EXEC_result = TO_STRING(EXPT(R1, R2));\n } else if (OPERATOR == \"SQRT\") {\n EXEC_result = TO_STRING(SQRT(R2));\n } else if (OPERATOR == \"SIN\") {\n EXEC_result = TO_STRING(SIN(R2));\n } else if (OPERATOR == \"COS\") {\n EXEC_result = TO_STRING(COS(R2));\n } else if (OPERATOR == \"TAN\") {\n EXEC_result = TO_STRING(TAN(R2));\n } else if (OPERATOR == \"*\") {\n EXEC_result = TO_STRING(R1 * R2);\n } else if (OPERATOR == \"/\") {\n if (R2 != 0) {\n EXEC_result = TO_STRING(R1 / R2);\n } else {\n EXEC_result = \"ERROR\";\n }\n } else if (OPERATOR == \"+\") {\n EXEC_result = TO_STRING(R1 + R2);\n } else if (OPERATOR == \"-\") {\n EXEC_result = TO_STRING(R1 - R2);\n } else {\n EXEC_result = \"ERROR\";\n }\n if (EXEC_result == \"ERROR\") {\n return EXEC_result;\n } else if (FIND(EXEC_result, \".\") == 0) {\n EXEC_result = CONCAT(EXEC_result, \".0\");\n } else if (RIGHT(EXEC_result, 1) == \".\") {\n EXEC_result = CONCAT(EXEC_result, \"0\");\n }\n return EXEC_result;\n}\n\n\nIEC_REAL EXP10(IEC_REAL X) {\n IEC_REAL EXP10_result;\n EXP10_result = EXP(X * 2.30258509299405);\n return EXP10_result;\n}\n\n\nIEC_REAL EXPN(IEC_REAL X, IEC_INT N) {\n IEC_REAL EXPN_result;\n IEC_BOOL SIGN;\n SIGN = ((static_cast(N) >> 15) & 1);\n N = ABS(N);\n if (((static_cast(N) >> 0) & 1)) {\n EXPN_result = X;\n } else {\n EXPN_result = 1.0;\n }\n N = SHR(N, 1);\n while (N > 0) {\n X = X * X;\n if (((static_cast(N) >> 0) & 1)) {\n EXPN_result = EXPN_result * X;\n }\n N = SHR(N, 1);\n }\n if (SIGN) {\n EXPN_result = 1.0 / EXPN_result;\n }\n return EXPN_result;\n}\n\n\nIEC_DINT FACT(IEC_INT X) {\n IEC_DINT FACT_result;\n if ((X >= 0) & (X <= 12)) {\n FACT_result = MATH.FACTS[X];\n } else {\n FACT_result = -1;\n }\n return FACT_result;\n}\n\n\nIEC_DINT FIB(IEC_INT X) {\n IEC_DINT FIB_result;\n IEC_DINT T1;\n IEC_DINT T2;\n if ((X < 0) | (X > 46)) {\n FIB_result = -1;\n } else if (X < 2) {\n FIB_result = X;\n return FIB_result;\n } else {\n T2 = 1;\n while (X > 3) {\n X = X - 2;\n T1 = T1 + T2;\n T2 = T1 + T2;\n }\n if (X > 2) {\n T1 = T1 + T2;\n }\n FIB_result = T1 + T2;\n }\n return FIB_result;\n}\n\n\nIECStringVar FILL(IEC_BYTE C, IEC_INT L) {\n IECStringVar FILL_result;\n IEC_INT I;\n IECStringVar<1> SX;\n SX = CHR_TO_STRING(C);\n L = LIMIT(static_cast(0), L, STRING_LENGTH);\n for (I = 1; I <= 8; I++) {\n FILL_result = CONCAT(FILL_result, FILL_result);\n if (((static_cast(L) >> 7) & 1)) {\n FILL_result = CONCAT(FILL_result, SX);\n }\n L = SHL(L, 1);\n }\n return FILL_result;\n}\n\n\nIEC_INT FINDB(IECStringVar STR1, IECStringVar STR2) {\n IEC_INT FINDB_result;\n IEC_INT POS;\n IEC_INT LENGTH;\n LENGTH = LEN(STR2);\n for (POS = LEN(STR1) - LENGTH + 1; POS >= 1; POS += -1) {\n if (MID(STR1, LENGTH, POS) == STR2) {\n FINDB_result = POS;\n return FINDB_result;\n }\n }\n FINDB_result = 0;\n return FINDB_result;\n}\n\n\nIEC_INT FINDB_NONUM(IECStringVar STR) {\n IEC_INT FINDB_NONUM_result;\n IEC_INT POS;\n IEC_Ptr PT;\n PT = &(STR) + LEN(STR) - 1;\n for (POS = LEN(STR); POS >= 1; POS += -1) {\n if (((((*PT) < 48) & ((*PT) != 46))) | ((*PT) > 57)) {\n FINDB_NONUM_result = POS;\n return FINDB_NONUM_result;\n }\n PT = PT - 1;\n }\n FINDB_NONUM_result = 0;\n return FINDB_NONUM_result;\n}\n\n\nIEC_INT FINDB_NUM(IECStringVar STR) {\n IEC_INT FINDB_NUM_result;\n IEC_INT POS;\n IEC_Ptr PT;\n PT = &(STR) + LEN(STR) - 1;\n for (POS = LEN(STR); POS >= 1; POS += -1) {\n if (((((*PT) > 47) & ((*PT) < 58))) | ((*PT) == 46)) {\n FINDB_NUM_result = POS;\n return FINDB_NUM_result;\n }\n PT = PT - 1;\n }\n FINDB_NUM_result = 0;\n return FINDB_NUM_result;\n}\n\n\nIEC_INT FINDP(IECStringVar STR, IECStringVar SRC, IEC_INT POS) {\n IEC_INT FINDP_result;\n IEC_INT I;\n IEC_INT LS;\n IEC_INT LX;\n IEC_INT STP;\n LS = LEN(STR);\n LX = LEN(SRC);\n if ((LS < LX) | (LX == 0)) {\n return FINDP_result;\n }\n STP = LS - LX + 1;\n for (I = MAX(POS, 1); I <= STP; I++) {\n if (MID(STR, LX, I) == SRC) {\n FINDP_result = I;\n return FINDP_result;\n }\n }\n FINDP_result = 0;\n return FINDP_result;\n}\n\n\nIEC_INT FIND_CHAR(IECStringVar STR, IEC_INT POS) {\n IEC_INT FIND_CHAR_result;\n IEC_INT I;\n IEC_Ptr> PT;\n IEC_INT STOP;\n IEC_BYTE X;\n PT = &(STR);\n STOP = LEN(STR);\n for (I = MAX(POS, 1); I <= STOP; I++) {\n X = (*PT)[I];\n if ((X > 31) & (((((SETUP.EXTENDED_ASCII) & (X != 127))) | (((!SETUP.EXTENDED_ASCII) & (X < 127)))))) {\n FIND_CHAR_result = I;\n return FIND_CHAR_result;\n }\n }\n FIND_CHAR_result = 0;\n return FIND_CHAR_result;\n}\n\n\nIEC_INT FIND_CTRL(IECStringVar STR, IEC_INT POS) {\n IEC_INT FIND_CTRL_result;\n IEC_INT I;\n IEC_Ptr> PT;\n IEC_INT STOP;\n IEC_BYTE X;\n PT = &(STR);\n STOP = LEN(STR);\n for (I = MAX(POS, 1); I <= STOP; I++) {\n X = (*PT)[I];\n if ((X < 32) | (X == 127)) {\n FIND_CTRL_result = I;\n return FIND_CTRL_result;\n }\n }\n FIND_CTRL_result = 0;\n return FIND_CTRL_result;\n}\n\n\nIEC_INT FIND_NONUM(IECStringVar STR, IEC_INT POS) {\n IEC_INT FIND_NONUM_result;\n IEC_INT I;\n IEC_Ptr> PT;\n IEC_INT END;\n IEC_BYTE X;\n PT = &(STR);\n END = LEN(STR);\n for (I = MAX(POS, 1); I <= END; I++) {\n X = (*PT)[I];\n if ((((X < 48) & (X != 46))) | (X > 57)) {\n FIND_NONUM_result = I;\n return FIND_NONUM_result;\n }\n }\n FIND_NONUM_result = 0;\n return FIND_NONUM_result;\n}\n\n\nIEC_INT FIND_NUM(IECStringVar STR, IEC_INT POS) {\n IEC_INT FIND_NUM_result;\n IEC_INT I;\n IEC_Ptr> PT;\n IEC_INT STOP;\n IEC_BYTE X;\n PT = &(STR);\n STOP = LEN(STR);\n for (I = MAX(POS, 1); I <= STOP; I++) {\n X = (*PT)[I];\n if ((((X > 47) & (X < 58))) | (X == 46)) {\n FIND_NUM_result = I;\n return FIND_NUM_result;\n }\n }\n FIND_NUM_result = 0;\n return FIND_NUM_result;\n}\n\n\nIECStringVar FIX(IECStringVar STR, IEC_INT L, IEC_BYTE C, IEC_INT M) {\n IECStringVar FIX_result;\n IEC_INT N;\n IECStringVar SX;\n N = LIMIT(static_cast(0), L, STRING_LENGTH) - LEN(STR);\n if (N <= 0) {\n if (M == 1) {\n FIX_result = RIGHT(STR, L);\n } else {\n FIX_result = LEFT(STR, L);\n }\n } else if (M == 1) {\n SX = FILL(C, N);\n FIX_result = CONCAT(SX, STR);\n } else if (M == 2) {\n SX = FILL(C, SHR(N + 1, 1));\n FIX_result = CONCAT(STR, SX);\n SX = LEFT(SX, SHR(N, 1));\n FIX_result = CONCAT(SX, FIX_result);\n } else {\n SX = FILL(C, N);\n FIX_result = CONCAT(STR, SX);\n }\n return FIX_result;\n}\n\n\nIEC_REAL FLOAT_TO_REAL(IECStringVar<20> FLT) {\n IEC_REAL FLOAT_TO_REAL_result;\n IEC_Ptr> PT;\n IEC_INT I;\n IEC_BYTE X;\n IEC_INT SIGN = 1;\n IEC_INT STOP;\n IEC_DINT TMP;\n IEC_INT D;\n PT = &(FLT);\n STOP = LEN(FLT);\n for (I = 1; I <= STOP; I++) {\n X = (*PT)[I];\n if (((X > 47) & (X < 58)) | (X == 46)) {\n goto __strucpp_loop_exit_70;\n } else if (X == 45) {\n SIGN = -1;\n }\n }\n __strucpp_loop_exit_70: ;\n for (I = I; I <= STOP; I++) {\n X = (*PT)[I];\n if ((((X == 44) | (X == 46)) | (X == 69)) | (X == 101)) {\n goto __strucpp_loop_exit_71;\n } else if ((X > 47) & (X < 58)) {\n TMP = TMP * 10 + X - 48;\n }\n }\n __strucpp_loop_exit_71: ;\n if ((X == 44) | (X == 46)) {\n for (I = I + 1; I <= STOP; I++) {\n X = (*PT)[I];\n if ((X == 69) | (X == 101)) {\n goto __strucpp_loop_exit_72;\n } else if ((X > 47) & (X < 58)) {\n TMP = TMP * 10 + X - 48;\n D = D - 1;\n }\n }\n __strucpp_loop_exit_72: ;\n }\n if ((X == 69) | (X == 101)) {\n D = D + DEC_TO_INT(RIGHT(FLT, STOP - I));\n }\n FLOAT_TO_REAL_result = EXPN(static_cast(10), D) * TO_REAL(TMP * SIGN);\n return FLOAT_TO_REAL_result;\n}\n\n\nIEC_INT FLOOR(IEC_REAL X) {\n IEC_INT FLOOR_result;\n FLOOR_result = TO_INT(X);\n if (FLOOR_result > X) {\n FLOOR_result = FLOOR_result - 1;\n }\n return FLOOR_result;\n}\n\n\nIEC_DINT FLOOR2(IEC_REAL X) {\n IEC_DINT FLOOR2_result;\n FLOOR2_result = TO_DINT(X);\n if (TO_REAL(FLOOR2_result) > X) {\n FLOOR2_result = FLOOR2_result - 1;\n }\n return FLOOR2_result;\n}\n\n\nIEC_REAL FRACT(IEC_REAL X) {\n IEC_REAL FRACT_result;\n if (ABS(X) < 2000000000.0) {\n FRACT_result = X - TO_REAL(D_TRUNC(X));\n } else {\n FRACT_result = 0.0;\n }\n return FRACT_result;\n}\n\n\nIEC_BYTE FRMP_B(IEC_BYTE START, IEC_BOOL DIR, IEC_TIME TD, IEC_TIME TR) {\n IEC_BYTE FRMP_B_result;\n if (TD < TR) {\n FRMP_B_result = MIN(TO_BYTE(SHL(TO_DWORD(TD), 8) / TO_DWORD(TR)), SEL(DIR, START, static_cast(255) - START));\n if (DIR) {\n FRMP_B_result = START + FRMP_B_result;\n } else {\n FRMP_B_result = START - FRMP_B_result;\n }\n } else {\n FRMP_B_result = SEL(DIR, 0, 255);\n }\n return FRMP_B_result;\n}\n\n\nIEC_BYTE FSTRING_TO_BYTE(IECStringVar<12> IN) {\n IEC_BYTE FSTRING_TO_BYTE_result;\n if (LEFT(IN, 2) == \"2#\") {\n FSTRING_TO_BYTE_result = BIN_TO_BYTE(RIGHT(IN, LEN(IN) - 2));\n } else if (LEFT(IN, 2) == \"8#\") {\n FSTRING_TO_BYTE_result = OCT_TO_BYTE(RIGHT(IN, LEN(IN) - 2));\n } else if (LEFT(IN, 3) == \"16#\") {\n FSTRING_TO_BYTE_result = HEX_TO_BYTE(RIGHT(IN, LEN(IN) - 3));\n } else {\n FSTRING_TO_BYTE_result = DEC_TO_BYTE(CLEAN(IN, \"0123456789\"));\n }\n return FSTRING_TO_BYTE_result;\n}\n\n\nIEC_DT FSTRING_TO_DT(IECStringVar<60> SDT, IECStringVar<60> FMT) {\n IEC_DT FSTRING_TO_DT_result;\n IECStringVar<1> IGNORE = \"*\";\n IECStringVar<1> FCHAR = \"#\";\n IECStringVar<1> C;\n IECStringVar<20> TMP;\n IEC_INT END;\n IEC_INT DY = 1970;\n IEC_INT DM = 1;\n IEC_INT DD = 1;\n IEC_INT TH;\n IEC_INT TM;\n IEC_INT TS;\n while (FMT != \"\") {\n C = LEFT(FMT, 1);\n if (C == IGNORE) {\n FMT = DELETE_STR(FMT, 1, 1);\n SDT = DELETE_STR(SDT, 1, 1);\n } else if (C == FCHAR) {\n C = MID(FMT, 1, 2);\n FMT = DELETE_STR(FMT, 2, 1);\n if (FMT == \"\") {\n TMP = SDT;\n } else {\n END = FIND(SDT, LEFT(FMT, 1)) - 1;\n TMP = LEFT(SDT, END);\n SDT = DELETE_STR(SDT, END, 1);\n }\n if (C == \"Y\") {\n DY = TO_INT(TMP);\n if (DY < 100) {\n DY = DY + 2000;\n }\n } else if (C == \"M\") {\n DM = TO_INT(TMP);\n } else if (C == \"N\") {\n DM = FSTRING_TO_MONTH(TMP, 0);\n } else if (C == \"D\") {\n DD = TO_INT(TMP);\n } else if (C == \"h\") {\n TH = TO_INT(TMP);\n } else if (C == \"m\") {\n TM = TO_INT(TMP);\n } else if (C == \"s\") {\n TS = TO_INT(TMP);\n }\n } else if (C == LEFT(SDT, 1)) {\n FMT = DELETE_STR(FMT, 1, 1);\n SDT = DELETE_STR(SDT, 1, 1);\n } else {\n return FSTRING_TO_DT_result;\n }\n }\n FSTRING_TO_DT_result = SET_DT(DY, DM, DD, TH, TM, TS);\n return FSTRING_TO_DT_result;\n}\n\n\nIEC_DWORD FSTRING_TO_DWORD(IECStringVar<40> IN) {\n IEC_DWORD FSTRING_TO_DWORD_result;\n if (LEFT(IN, 2) == \"2#\") {\n FSTRING_TO_DWORD_result = BIN_TO_DWORD(RIGHT(IN, LEN(IN) - 2));\n } else if (LEFT(IN, 2) == \"8#\") {\n FSTRING_TO_DWORD_result = OCT_TO_DWORD(RIGHT(IN, LEN(IN) - 2));\n } else if (LEFT(IN, 3) == \"16#\") {\n FSTRING_TO_DWORD_result = HEX_TO_DWORD(RIGHT(IN, LEN(IN) - 3));\n } else {\n FSTRING_TO_DWORD_result = DEC_TO_DWORD(CLEAN(IN, \"0123456789\"));\n }\n return FSTRING_TO_DWORD_result;\n}\n\n\nIEC_INT FSTRING_TO_MONTH(IECStringVar<20> MTH, IEC_INT LANG) {\n IEC_INT FSTRING_TO_MONTH_result;\n IEC_INT LX;\n if (LANG == 0) {\n LX = LANGUAGE.DEFAULT;\n } else {\n LX = MIN(LANG, LANGUAGE.LMAX);\n }\n MTH = TRIM(MTH);\n MTH = CAPITALIZE(LOWERCASE(MTH));\n for (FSTRING_TO_MONTH_result = 1; FSTRING_TO_MONTH_result <= 12; FSTRING_TO_MONTH_result++) {\n if (MTH == LANGUAGE.MONTHS(LX, FSTRING_TO_MONTH_result)) {\n return FSTRING_TO_MONTH_result;\n }\n if (MTH == LANGUAGE.MONTHS3(LX, FSTRING_TO_MONTH_result)) {\n return FSTRING_TO_MONTH_result;\n }\n }\n FSTRING_TO_MONTH_result = TO_INT(MTH);\n return FSTRING_TO_MONTH_result;\n}\n\n\nIEC_BYTE FSTRING_TO_WEEK(IECStringVar<60> WEEK, IEC_INT LANG) {\n IEC_BYTE FSTRING_TO_WEEK_result;\n IEC_INT POS;\n POS = FIND(WEEK, \",\");\n while (POS > 0) {\n FSTRING_TO_WEEK_result = (FSTRING_TO_WEEK_result) | (SHR(static_cast(128), FSTRING_TO_WEEKDAY(MID(WEEK, POS - 1, 1), LANG)));\n WEEK = RIGHT(WEEK, LEN(WEEK) - POS);\n POS = FIND(WEEK, \",\");\n }\n FSTRING_TO_WEEK_result = (((FSTRING_TO_WEEK_result) | (SHR(static_cast(128), FSTRING_TO_WEEKDAY(WEEK, LANG))))) & (static_cast(127));\n return FSTRING_TO_WEEK_result;\n}\n\n\nIEC_INT FSTRING_TO_WEEKDAY(IECStringVar<20> WDAY, IEC_INT LANG) {\n IEC_INT FSTRING_TO_WEEKDAY_result;\n IECStringVar<2> TMP;\n IEC_INT I;\n IEC_INT LY;\n if (LANG == 0) {\n LY = LANGUAGE.DEFAULT;\n } else {\n LY = MIN(LANG, LANGUAGE.LMAX);\n }\n TMP = TRIM(WDAY);\n TMP = CAPITALIZE(LOWERCASE(TMP));\n for (I = 1; I <= 7; I++) {\n if (LANGUAGE.WEEKDAYS2(LY, I) == TMP) {\n FSTRING_TO_WEEKDAY_result = I;\n return FSTRING_TO_WEEKDAY_result;\n }\n }\n FSTRING_TO_WEEKDAY_result = TO_INT(WDAY);\n return FSTRING_TO_WEEKDAY_result;\n}\n\n\nIEC_REAL F_LIN(IEC_REAL X, IEC_REAL A, IEC_REAL B) {\n IEC_REAL F_LIN_result;\n F_LIN_result = A * X + B;\n return F_LIN_result;\n}\n\n\nIEC_REAL F_LIN2(IEC_REAL X, IEC_REAL X1, IEC_REAL Y1, IEC_REAL X2, IEC_REAL Y2) {\n IEC_REAL F_LIN2_result;\n F_LIN2_result = (Y2 - Y1) / (X2 - X1) * (X - X1) + Y1;\n return F_LIN2_result;\n}\n\n\nIEC_REAL F_POLY(IEC_REAL X, Array1D C) {\n IEC_REAL F_POLY_result;\n F_POLY_result = (((((((C[7] * X + C[6]) * X + C[5]) * X + C[4]) * X + C[3]) * X + C[2]) * X + C[1]) * X + C[0]);\n return F_POLY_result;\n}\n\n\nIEC_REAL F_POWER(IEC_REAL A, IEC_REAL X, IEC_REAL N) {\n IEC_REAL F_POWER_result;\n F_POWER_result = A * EXPT(X, N);\n return F_POWER_result;\n}\n\n\nIEC_REAL F_QUAD(IEC_REAL X, IEC_REAL A, IEC_REAL B, IEC_REAL C) {\n IEC_REAL F_QUAD_result;\n F_QUAD_result = (A * X + B) * X + C;\n return F_QUAD_result;\n}\n\n\nIEC_REAL F_TO_C(IEC_REAL FAHRENHEIT) {\n IEC_REAL F_TO_C_result;\n F_TO_C_result = (FAHRENHEIT - 32.0) * 0.5555555555555;\n return F_TO_C_result;\n}\n\n\nIEC_REAL F_TO_OM(IEC_REAL F) {\n IEC_REAL F_TO_OM_result;\n F_TO_OM_result = MATH.PI2 * F;\n return F_TO_OM_result;\n}\n\n\nIEC_TIME F_TO_PT(IEC_REAL F) {\n IEC_TIME F_TO_PT_result;\n F_TO_PT_result = TO_TIME(TO_DWORD(1.0 / F * 1000.0));\n return F_TO_PT_result;\n}\n\n\nIEC_REAL GAMMA(IEC_REAL X) {\n IEC_REAL GAMMA_result;\n if (X > 0.0) {\n GAMMA_result = SQRT(MATH.PI2 / X) * EXPT(MATH.E_INV * (X + 1.0 / (12.0 * X - 0.1 / X)), X);\n }\n return GAMMA_result;\n}\n\n\nIEC_REAL GAUSS(IEC_REAL X, IEC_REAL U, IEC_REAL SI) {\n IEC_REAL GAUSS_result;\n IEC_REAL TEMP;\n IEC_REAL SI_INV;\n TEMP = X - U;\n SI_INV = 1.0 / SI;\n GAUSS_result = EXP(TEMP * TEMP * SI_INV * SI_INV * -0.5) * 0.39894228 * SI_INV;\n return GAUSS_result;\n}\n\n\nIEC_REAL GAUSSCD(IEC_REAL X, IEC_REAL U, IEC_REAL SI) {\n IEC_REAL GAUSSCD_result;\n GAUSSCD_result = (ERF((X - U) / (SI * 1.414213562)) + 1.0) * 0.5;\n return GAUSSCD_result;\n}\n\n\nIEC_INT GCD(IEC_DINT A, IEC_DINT B) {\n IEC_INT GCD_result;\n IEC_DINT T;\n if (A == 0) {\n GCD_result = TO_INT(ABS(B));\n } else if (B == 0) {\n GCD_result = TO_INT(ABS(A));\n } else {\n A = ABS(A);\n B = ABS(B);\n GCD_result = 1;\n while (NOT((((static_cast(A) >> 0) & 1)) | (((static_cast(B) >> 0) & 1)))) {\n A = SHR(A, 1);\n B = SHR(B, 1);\n GCD_result = SHL(GCD_result, 1);\n }\n while (A > 0) {\n if (NOT(((static_cast(A) >> 0) & 1))) {\n A = SHR(A, 1);\n } else if (NOT(((static_cast(B) >> 0) & 1))) {\n B = SHR(B, 1);\n } else {\n T = SHR(ABS(A - B), 1);\n if (A < B) {\n B = T;\n } else {\n A = T;\n }\n }\n }\n GCD_result = GCD_result * TO_INT(B);\n }\n return GCD_result;\n}\n\n\nIEC_REAL GDF(IEC_REAL X) {\n IEC_REAL GDF_result;\n if (X == 0.0) {\n GDF_result = 0.0;\n } else if (X > 15.0) {\n GDF_result = MATH.PI05;\n } else if (X < -15.0) {\n GDF_result = -MATH.PI05;\n } else {\n GDF_result = ATAN(EXP(X)) * 2.0 - MATH.PI05;\n }\n return GDF_result;\n}\n\n\nIEC_REAL GEO_TO_DEG(IEC_INT D, IEC_INT M, IEC_REAL SEC) {\n IEC_REAL GEO_TO_DEG_result;\n GEO_TO_DEG_result = TO_REAL(D) + TO_REAL(M) * 0.016666666666667 + SEC * 0.00027777777777778;\n return GEO_TO_DEG_result;\n}\n\n\nIEC_REAL GOLD(IEC_REAL X) {\n IEC_REAL GOLD_result;\n GOLD_result = (X + SQRT(X * X + 4.0)) * 0.5;\n return GOLD_result;\n}\n\n\nIEC_BYTE GRAY_TO_BYTE(IEC_BYTE IN) {\n IEC_BYTE GRAY_TO_BYTE_result;\n GRAY_TO_BYTE_result = (SHR(IN, 4)) ^ (IN);\n GRAY_TO_BYTE_result = (SHR(GRAY_TO_BYTE_result, 2)) ^ (GRAY_TO_BYTE_result);\n GRAY_TO_BYTE_result = (SHR(GRAY_TO_BYTE_result, 1)) ^ (GRAY_TO_BYTE_result);\n return GRAY_TO_BYTE_result;\n}\n\n\nIEC_BYTE HEX_TO_BYTE(IECStringVar<5> HEX) {\n IEC_BYTE HEX_TO_BYTE_result;\n IEC_Ptr PT;\n IEC_INT I;\n IEC_BYTE X;\n IEC_INT STOP;\n PT = &(HEX);\n STOP = LEN(HEX);\n for (I = 1; I <= STOP; I++) {\n X = (*PT);\n if ((X > 47) & (X < 58)) {\n HEX_TO_BYTE_result = SHL(HEX_TO_BYTE_result, 4) + X - 48;\n } else if ((X > 64) & (X < 71)) {\n HEX_TO_BYTE_result = SHL(HEX_TO_BYTE_result, 4) + X - 55;\n } else if ((X > 96) & (X < 103)) {\n HEX_TO_BYTE_result = SHL(HEX_TO_BYTE_result, 4) + X - 87;\n }\n PT = PT + 1;\n }\n return HEX_TO_BYTE_result;\n}\n\n\nIEC_DWORD HEX_TO_DWORD(IECStringVar<20> HEX) {\n IEC_DWORD HEX_TO_DWORD_result;\n IEC_Ptr PT;\n IEC_INT I;\n IEC_BYTE X;\n IEC_INT STOP;\n PT = &(HEX);\n STOP = LEN(HEX);\n for (I = 1; I <= STOP; I++) {\n X = (*PT);\n if ((X > 47) & (X < 58)) {\n HEX_TO_DWORD_result = SHL(HEX_TO_DWORD_result, 4) + X - 48;\n } else if ((X > 64) & (X < 71)) {\n HEX_TO_DWORD_result = SHL(HEX_TO_DWORD_result, 4) + X - 55;\n } else if ((X > 96) & (X < 103)) {\n HEX_TO_DWORD_result = SHL(HEX_TO_DWORD_result, 4) + X - 87;\n }\n PT = PT + 1;\n }\n return HEX_TO_DWORD_result;\n}\n\n\nIEC_INT HOUR(IEC_TOD ITOD) {\n IEC_INT HOUR_result;\n HOUR_result = TO_INT(TO_DWORD(ITOD) / 3600000);\n return HOUR_result;\n}\n\n\nIEC_INT HOUR_OF_DT(IEC_DT XDT) {\n IEC_INT HOUR_OF_DT_result;\n HOUR_OF_DT_result = TO_INT((TO_DWORD(XDT) % 86400) / 3600);\n return HOUR_OF_DT_result;\n}\n\n\nIEC_TIME HOUR_TO_TIME(IEC_REAL IN) {\n IEC_TIME HOUR_TO_TIME_result;\n HOUR_TO_TIME_result = TO_TIME(TO_DWORD(IN * 3600000));\n return HOUR_TO_TIME_result;\n}\n\n\nIEC_TOD HOUR_TO_TOD(IEC_REAL IN) {\n IEC_TOD HOUR_TO_TOD_result;\n HOUR_TO_TOD_result = TO_TOD(TO_DWORD(IN * 3600000));\n return HOUR_TO_TOD_result;\n}\n\n\nIEC_REAL HYPOT(IEC_REAL X, IEC_REAL Y) {\n IEC_REAL HYPOT_result;\n HYPOT_result = SQRT(X * X + Y * Y);\n return HYPOT_result;\n}\n\n\nIEC_INT INC(IEC_INT X, IEC_INT D, IEC_INT M) {\n IEC_INT INC_result;\n INC_result = (X + D + M + 1) % (M + 1);\n return INC_result;\n}\n\n\nIEC_INT INC1(IEC_INT X, IEC_INT N) {\n IEC_INT INC1_result;\n if (X >= N - 1) {\n INC1_result = 0;\n } else {\n INC1_result = X + 1;\n }\n return INC1_result;\n}\n\n\nIEC_INT INC2(IEC_INT X, IEC_INT D, IEC_INT L, IEC_INT U) {\n IEC_INT INC2_result;\n IEC_INT TMP;\n TMP = U - L + 1;\n INC2_result = (X + D - L + TMP) % TMP + L;\n return INC2_result;\n}\n\n\nIEC_BYTE INT_TO_BCDC(IEC_INT IN) {\n IEC_BYTE INT_TO_BCDC_result;\n INT_TO_BCDC_result = (SHL(TO_BYTE(IN / static_cast(10)), 4)) | (TO_BYTE(IN % static_cast(10)));\n return INT_TO_BCDC_result;\n}\n\n\nIEC_REAL INV(IEC_REAL X) {\n IEC_REAL INV_result;\n if (X != 0.0) {\n INV_result = 1.0 / X;\n }\n return INV_result;\n}\n\n\nIEC_BOOL ISC_ALPHA(IEC_BYTE IN) {\n IEC_BOOL ISC_ALPHA_result;\n if (SETUP.EXTENDED_ASCII) {\n ISC_ALPHA_result = ((((IN > 64) & (IN < 91))) | ((((IN > 191) & (IN != 215)) & (IN != 247)))) | (((IN > 96) & (IN < 123)));\n } else {\n ISC_ALPHA_result = (((IN > 64) & (IN < 91))) | (((IN > 96) & (IN < 123)));\n }\n return ISC_ALPHA_result;\n}\n\n\nIEC_BOOL ISC_CTRL(IEC_BYTE IN) {\n IEC_BOOL ISC_CTRL_result;\n ISC_CTRL_result = (IN < 32) | (IN == 127);\n return ISC_CTRL_result;\n}\n\n\nIEC_BOOL ISC_HEX(IEC_BYTE IN) {\n IEC_BOOL ISC_HEX_result;\n ISC_HEX_result = ((((IN > 47) & (IN < 58))) | (((IN > 64) & (IN < 71)))) | (((IN > 96) & (IN < 103)));\n return ISC_HEX_result;\n}\n\n\nIEC_BOOL ISC_LOWER(IEC_BYTE IN) {\n IEC_BOOL ISC_LOWER_result;\n if (SETUP.EXTENDED_ASCII) {\n ISC_LOWER_result = ((((IN > 96)) & ((IN < 123)))) | ((((IN > 222)) & ((IN != 247))));\n } else {\n ISC_LOWER_result = (((IN > 96)) & ((IN < 123)));\n }\n return ISC_LOWER_result;\n}\n\n\nIEC_BOOL ISC_NUM(IEC_BYTE IN) {\n IEC_BOOL ISC_NUM_result;\n ISC_NUM_result = (IN > 47) & (IN < 58);\n return ISC_NUM_result;\n}\n\n\nIEC_BOOL ISC_UPPER(IEC_BYTE IN) {\n IEC_BOOL ISC_UPPER_result;\n if (SETUP.EXTENDED_ASCII) {\n ISC_UPPER_result = ((((IN > 64)) & ((IN < 91)))) | ((((((IN > 191)) & ((IN < 223)))) & ((IN != 215))));\n } else {\n ISC_UPPER_result = (((IN > 64)) & ((IN < 91)));\n }\n return ISC_UPPER_result;\n}\n\n\nIEC_BOOL IS_ALNUM(IECStringVar STR) {\n IEC_BOOL IS_ALNUM_result;\n IEC_INT L;\n IEC_Ptr PT;\n IEC_INT POS;\n PT = &(STR);\n L = LEN(STR);\n for (POS = 1; POS <= L; POS++) {\n if (NOT((ISC_ALPHA((*PT))) | (ISC_NUM((*PT))))) {\n IS_ALNUM_result = false;\n return IS_ALNUM_result;\n }\n PT = PT + 1;\n }\n IS_ALNUM_result = L > 0;\n return IS_ALNUM_result;\n}\n\n\nIEC_BOOL IS_ALPHA(IECStringVar STR) {\n IEC_BOOL IS_ALPHA_result;\n IEC_INT L;\n IEC_Ptr PT;\n IEC_INT POS;\n PT = &(STR);\n L = LEN(STR);\n for (POS = 1; POS <= L; POS++) {\n if (!ISC_ALPHA((*PT))) {\n IS_ALPHA_result = false;\n return IS_ALPHA_result;\n }\n PT = PT + 1;\n }\n IS_ALPHA_result = L > 0;\n return IS_ALPHA_result;\n}\n\n\nIEC_BOOL IS_CC(IECStringVar STR, IECStringVar CMP) {\n IEC_BOOL IS_CC_result;\n IEC_INT L;\n IEC_INT POS;\n L = LEN(STR);\n for (POS = 1; POS <= L; POS++) {\n if (FIND(CMP, MID(STR, 1, POS)) == 0) {\n return IS_CC_result;\n }\n }\n IS_CC_result = L > 0;\n return IS_CC_result;\n}\n\n\nIEC_BOOL IS_CTRL(IECStringVar STR) {\n IEC_BOOL IS_CTRL_result;\n IEC_INT L;\n IEC_Ptr PT;\n IEC_INT POS;\n PT = &(STR);\n L = LEN(STR);\n for (POS = 1; POS <= L; POS++) {\n if (NOT(ISC_CTRL((*PT)))) {\n IS_CTRL_result = false;\n return IS_CTRL_result;\n }\n PT = PT + 1;\n }\n IS_CTRL_result = L > 0;\n return IS_CTRL_result;\n}\n\n\nIEC_BOOL IS_HEX(IECStringVar STR) {\n IEC_BOOL IS_HEX_result;\n IEC_INT L;\n IEC_Ptr PT;\n IEC_INT POS;\n PT = &(STR);\n L = LEN(STR);\n for (POS = 1; POS <= L; POS++) {\n if (NOT(ISC_HEX((*PT)))) {\n IS_HEX_result = false;\n return IS_HEX_result;\n }\n PT = PT + 1;\n }\n IS_HEX_result = L > 0;\n return IS_HEX_result;\n}\n\n\nIEC_BOOL IS_LOWER(IECStringVar STR) {\n IEC_BOOL IS_LOWER_result;\n IEC_INT L;\n IEC_Ptr PT;\n IEC_INT POS;\n PT = &(STR);\n L = LEN(STR);\n for (POS = 1; POS <= L; POS++) {\n if (NOT(ISC_LOWER((*PT)))) {\n IS_LOWER_result = false;\n return IS_LOWER_result;\n }\n PT = PT + 1;\n }\n IS_LOWER_result = L > 0;\n return IS_LOWER_result;\n}\n\n\nIEC_BOOL IS_NCC(IECStringVar STR, IECStringVar CMP) {\n IEC_BOOL IS_NCC_result;\n IEC_INT L;\n IEC_INT POS;\n L = LEN(STR);\n for (POS = 1; POS <= L; POS++) {\n if (FIND(CMP, MID(STR, 1, POS)) > 0) {\n return IS_NCC_result;\n }\n }\n IS_NCC_result = true;\n return IS_NCC_result;\n}\n\n\nIEC_BOOL IS_NUM(IECStringVar STR) {\n IEC_BOOL IS_NUM_result;\n IEC_INT L;\n IEC_Ptr PT;\n IEC_INT POS;\n PT = &(STR);\n L = LEN(STR);\n for (POS = 1; POS <= L; POS++) {\n if (NOT(ISC_NUM((*PT)))) {\n IS_NUM_result = false;\n return IS_NUM_result;\n }\n PT = PT + 1;\n }\n IS_NUM_result = L > 0;\n return IS_NUM_result;\n}\n\n\nIEC_BOOL IS_SORTED(IEC_Ptr> PT, IEC_UINT SIZE) {\n IEC_BOOL IS_SORTED_result;\n IEC_INT STOP;\n IEC_INT I;\n STOP = TO_INT(SHR(SIZE, 2) - 2);\n for (I = 0; I <= STOP; I++) {\n if ((*PT)[I] > (*PT)[I + 1]) {\n IS_SORTED_result = false;\n return IS_SORTED_result;\n }\n }\n IS_SORTED_result = true;\n return IS_SORTED_result;\n}\n\n\nIEC_BOOL IS_UPPER(IECStringVar STR) {\n IEC_BOOL IS_UPPER_result;\n IEC_INT L;\n IEC_Ptr PT;\n IEC_INT POS;\n PT = &(STR);\n L = LEN(STR);\n for (POS = 1; POS <= L; POS++) {\n if (NOT(ISC_UPPER((*PT)))) {\n IS_UPPER_result = false;\n return IS_UPPER_result;\n }\n PT = PT + 1;\n }\n IS_UPPER_result = L > 0;\n return IS_UPPER_result;\n}\n\n\nIEC_REAL JD2000(IEC_DT DTI) {\n IEC_REAL JD2000_result;\n JD2000_result = TO_REAL(TO_DWORD(DTI) - 946728000) / 86400.0;\n return JD2000_result;\n}\n\n\nIEC_REAL KMH_TO_MS(IEC_REAL KMH) {\n IEC_REAL KMH_TO_MS_result;\n KMH_TO_MS_result = KMH * 0.2777777777777;\n return KMH_TO_MS_result;\n}\n\n\nIEC_REAL K_TO_C(IEC_REAL KELVIN) {\n IEC_REAL K_TO_C_result;\n K_TO_C_result = KELVIN + PHYS.T0;\n return K_TO_C_result;\n}\n\n\nIEC_REAL LAMBERT_W(IEC_REAL X) {\n IEC_REAL LAMBERT_W_result;\n IEC_REAL W;\n IEC_INT I;\n IEC_REAL WE;\n IEC_REAL W1E;\n IEC_DWORD LAST;\n IEC_REAL EWX;\n if (X < -0.367879441171442) {\n LAMBERT_W_result = -1000.0;\n return LAMBERT_W_result;\n } else if (X == 0.0) {\n return LAMBERT_W_result;\n } else if (X <= 500.0) {\n W = LN(X + 1.0);\n W = 0.665 * (1.0 + 0.0195 * W) * W + 0.04;\n } else {\n W = LN(X - 4.0) - (1.0 - 1.0 / LN(X)) * LN(LN(X));\n }\n for (I = 0; I <= 5; I++) {\n EWX = EXP(W);\n WE = W * EWX - X;\n W1E = (W + 1.0) * EWX;\n LAST = (REAL_TO_DW(W)) & (0xFFFFFFFC);\n W = W - (WE / (W1E - (W + 2.0) * WE / (2.0 * W + 2.0)));\n if (((REAL_TO_DW(W)) & (0xFFFFFFFC)) == LAST) {\n goto __strucpp_loop_exit_91;\n }\n }\n __strucpp_loop_exit_91: ;\n LAMBERT_W_result = W;\n return LAMBERT_W_result;\n}\n\n\nIEC_REAL LANGEVIN(IEC_REAL X) {\n IEC_REAL LANGEVIN_result;\n if (X == 0.0) {\n LANGEVIN_result = 0.0;\n } else {\n LANGEVIN_result = COTH(X) - 1.0 / X;\n }\n return LANGEVIN_result;\n}\n\n\nIEC_BOOL LEAP_DAY(IEC_DATE IDATE) {\n IEC_BOOL LEAP_DAY_result;\n LEAP_DAY_result = TO_UDINT(IDATE) % 126230400 == 68169600;\n return LEAP_DAY_result;\n}\n\n\nIEC_BOOL LEAP_OF_DATE(IEC_DATE IDATE) {\n IEC_BOOL LEAP_OF_DATE_result;\n LEAP_OF_DATE_result = SHL(((TO_DWORD(IDATE) + 43200) / 31557600), 30) == 0x80000000;\n return LEAP_OF_DATE_result;\n}\n\n\nIEC_BOOL LEAP_YEAR(IEC_INT YR) {\n IEC_BOOL LEAP_YEAR_result;\n LEAP_YEAR_result = SHL(YR, 14) == 0;\n return LEAP_YEAR_result;\n}\n\n\nIEC_REAL LINEAR_INT(IEC_REAL X, Array2D XY, IEC_INT PTS) {\n IEC_REAL LINEAR_INT_result;\n IEC_INT I;\n PTS = MIN(PTS, 20);\n I = 2;\n while (((I < PTS)) & ((XY(I, 0) < X))) {\n I = I + 1;\n }\n LINEAR_INT_result = ((XY(I, 1) - XY(I - 1, 1)) * X - XY(I, 1) * XY(I - 1, 0) + XY(I - 1, 1) * XY(I, 0)) / (XY(I, 0) - XY(I - 1, 0));\n return LINEAR_INT_result;\n}\n\n\nIEC_BOOL LIST_ADD(IEC_BYTE SEP, IECStringVar INS, IEC_STRING& LIST) {\n IEC_BOOL LIST_ADD_result;\n IECStringVar<1> SX;\n SX = CHR_TO_STRING(SEP);\n INS = CONCAT(SX, INS);\n if (LEN(LIST) + LEN(INS) > LIST_LENGTH) {\n LIST_ADD_result = false;\n } else {\n LIST = CONCAT(LIST, INS);\n LIST_ADD_result = true;\n }\n return LIST_ADD_result;\n}\n\n\nIEC_BOOL LIST_CLEAN(IEC_BYTE SEP, IEC_STRING& LIST) {\n IEC_BOOL LIST_CLEAN_result;\n IEC_Ptr> PT;\n IEC_INT READ = 1;\n IEC_INT WRITE = 1;\n IEC_BYTE LAST;\n IEC_BYTE C;\n PT = &(LIST);\n for (READ = 1; READ <= LIST_LENGTH; READ++) {\n C = (*PT)[READ];\n if (C == 0) {\n goto __strucpp_loop_exit_93;\n } else if ((C != SEP) | (SEP != LAST)) {\n (*PT)[WRITE] = C;\n WRITE = WRITE + 1;\n }\n LAST = C;\n }\n __strucpp_loop_exit_93: ;\n if (LAST == SEP) {\n WRITE = WRITE - 1;\n }\n if (WRITE <= STRING_LENGTH) {\n (*PT)[WRITE] = 0;\n }\n LIST_CLEAN_result = true;\n return LIST_CLEAN_result;\n}\n\n\nIECStringVar LIST_GET(IEC_BYTE SEP, IEC_INT POS, IEC_STRING& LIST) {\n IECStringVar LIST_GET_result;\n IEC_INT I = 1;\n IEC_INT O = 1;\n IEC_Ptr> PT;\n IEC_Ptr> PO;\n IEC_INT CNT = 0;\n IEC_BYTE C;\n PT = &(LIST);\n PO = &(LIST_GET_result);\n do {\n C = (*PT)[I];\n if (CNT == POS) {\n if (C == SEP) {\n goto __strucpp_loop_exit_94;\n }\n (*PO)[O] = C;\n O = O + 1;\n } else if (C == SEP) {\n CNT = CNT + 1;\n }\n I = I + 1;\n } while (!(((I == LIST_LENGTH)) | ((C == 0))));\n __strucpp_loop_exit_94: ;\n (*PO)[O] = 0;\n return LIST_GET_result;\n}\n\n\nIEC_BOOL LIST_INSERT(IEC_BYTE SEP, IEC_INT POS, IECStringVar INS, IEC_STRING& LIST) {\n IEC_BOOL LIST_INSERT_result;\n IEC_Ptr> PT;\n IEC_INT READ = 1;\n IEC_INT CNT = 1;\n IECStringVar<1> SX;\n PT = &(LIST);\n if (LEN(INS) + 1 + LEN(LIST) > LIST_LENGTH) {\n LIST_INSERT_result = false;\n } else {\n LIST_INSERT_result = true;\n while (READ < LIST_LENGTH) {\n if (CNT >= POS) {\n SX = CHR_TO_STRING(SEP);\n INS = CONCAT(SX, INS);\n LIST = INSERT(LIST, INS, READ - 1);\n LIST_INSERT_result = true;\n return LIST_INSERT_result;\n }\n if ((*PT)[READ] == 0) {\n (*PT)[READ] = SEP;\n (*PT)[READ + 1] = 0;\n }\n READ = READ + 1;\n if (((*PT)[READ] == SEP) | ((*PT)[READ] == 0)) {\n CNT = CNT + 1;\n }\n }\n }\n return LIST_INSERT_result;\n}\n\n\nIEC_INT LIST_LEN(IEC_BYTE SEP, IEC_STRING& LIST) {\n IEC_INT LIST_LEN_result;\n IEC_Ptr> PT;\n IEC_INT POS = 1;\n IEC_BYTE C;\n PT = &(LIST);\n LIST_LEN_result = 0;\n do {\n C = (*PT)[POS];\n if (C == SEP) {\n LIST_LEN_result = LIST_LEN_result + 1;\n }\n POS = POS + 1;\n } while (!((C == 0) | (POS > LIST_LENGTH)));\n return LIST_LEN_result;\n}\n\n\nIECStringVar LIST_RETRIEVE(IEC_BYTE SEP, IEC_INT POS, IEC_STRING& LIST) {\n IECStringVar LIST_RETRIEVE_result;\n IEC_INT I;\n IEC_INT O = 1;\n IEC_INT W = 1;\n IEC_Ptr> PT;\n IEC_Ptr> PO;\n IEC_INT CNT = 0;\n IEC_BYTE C;\n PT = &(LIST);\n PO = &(LIST_RETRIEVE_result);\n if (POS > 0) {\n for (I = 1; I <= LIST_LENGTH; I++) {\n C = (*PT)[I];\n if (C == 0) {\n (*PO)[O] = 0;\n if (CNT < POS) {\n (*PT)[W + 1] = 0;\n } else {\n (*PT)[W] = 0;\n }\n return LIST_RETRIEVE_result;\n } else if ((CNT == POS) & (C != SEP)) {\n (*PO)[O] = (*PT)[I];\n O = O + 1;\n } else if (CNT >= POS) {\n (*PT)[W] = C;\n W = W + 1;\n } else {\n W = I;\n }\n if (C == SEP) {\n CNT = CNT + 1;\n }\n }\n } else {\n LIST_RETRIEVE_result = \"\";\n }\n return LIST_RETRIEVE_result;\n}\n\n\nIECStringVar LIST_RETRIEVE_LAST(IEC_BYTE SEP, IEC_STRING& LIST) {\n IECStringVar LIST_RETRIEVE_LAST_result;\n IEC_INT I;\n IEC_INT LAST = 1;\n IEC_Ptr> PT;\n IEC_BYTE C;\n PT = &(LIST);\n for (I = 1; I <= LIST_LENGTH; I++) {\n C = (*PT)[I];\n if (C == 0) {\n goto __strucpp_loop_exit_98;\n } else if (C == SEP) {\n LAST = I;\n }\n }\n __strucpp_loop_exit_98: ;\n LIST_RETRIEVE_LAST_result = MID(LIST, LIST_LENGTH, LAST + 1);\n (*PT)[LAST] = 0;\n return LIST_RETRIEVE_LAST_result;\n}\n\n\nIECStringVar LOWERCASE(IECStringVar STR) {\n IECStringVar LOWERCASE_result;\n IEC_Ptr PT;\n IEC_INT POS;\n IEC_INT L;\n PT = &(LOWERCASE_result);\n LOWERCASE_result = STR;\n L = LEN(STR);\n for (POS = 1; POS <= L; POS++) {\n (*PT) = TO_LOWER((*PT));\n PT = PT + 1;\n }\n return LOWERCASE_result;\n}\n\n\nIEC_DT LTIME_TO_UTC(IEC_DT LTIME, IEC_BOOL DST, IEC_INT TIME_ZONE_OFFSET) {\n IEC_DT LTIME_TO_UTC_result;\n LTIME_TO_UTC_result = TO_DT(TO_UDINT(LTIME) - TO_UDINT(TIME_ZONE_OFFSET) * 60);\n if (DST) {\n LTIME_TO_UTC_result = LTIME_TO_UTC_result - 3600000000000LL;\n }\n return LTIME_TO_UTC_result;\n}\n\n\nIEC_BOOL MANUAL(IEC_BOOL IN, IEC_BOOL ON, IEC_BOOL OFF) {\n IEC_BOOL MANUAL_result;\n MANUAL_result = (!OFF) & (((IN) | (ON)));\n return MANUAL_result;\n}\n\n\nIEC_REAL MAX3(IEC_REAL IN1, IEC_REAL IN2, IEC_REAL IN3) {\n IEC_REAL MAX3_result;\n MAX3_result = MAX(MAX(IN1, IN2), IN3);\n return MAX3_result;\n}\n\n\nIEC_REAL MID3(IEC_REAL IN1, IEC_REAL IN2, IEC_REAL IN3) {\n IEC_REAL MID3_result;\n if (IN1 > IN2) {\n MID3_result = IN1;\n IN1 = IN2;\n IN2 = MID3_result;\n }\n if (IN2 > IN3) {\n IN2 = IN3;\n }\n MID3_result = SEL(IN1 > IN2, IN2, IN1);\n return MID3_result;\n}\n\n\nIEC_REAL MIN3(IEC_REAL IN1, IEC_REAL IN2, IEC_REAL IN3) {\n IEC_REAL MIN3_result;\n MIN3_result = MIN(MIN(IN1, IN2), IN3);\n return MIN3_result;\n}\n\n\nIEC_INT MINUTE(IEC_TOD ITOD) {\n IEC_INT MINUTE_result;\n MINUTE_result = TO_INT(TO_DWORD(ITOD) / 60000 - TO_DWORD(ITOD) / 3600000 * 60);\n return MINUTE_result;\n}\n\n\nIEC_INT MINUTE_OF_DT(IEC_DT XDT) {\n IEC_INT MINUTE_OF_DT_result;\n MINUTE_OF_DT_result = TO_INT(TO_DWORD(XDT) % 3600) / 60;\n return MINUTE_OF_DT_result;\n}\n\n\nIEC_TIME MINUTE_TO_TIME(IEC_REAL IN) {\n IEC_TIME MINUTE_TO_TIME_result;\n MINUTE_TO_TIME_result = TO_TIME(TO_DWORD(IN * 60000.0));\n return MINUTE_TO_TIME_result;\n}\n\n\nIECStringVar MIRROR(IECStringVar STR) {\n IECStringVar MIRROR_result;\n IEC_Ptr> PI;\n IEC_Ptr PO;\n IEC_INT LX;\n IEC_INT I;\n PI = &(STR);\n PO = &(MIRROR_result);\n LX = LEN(STR);\n for (I = LX; I >= 1; I += -1) {\n (*PO) = (*PI)[I];\n PO = PO + 1;\n }\n (*PO) = 0;\n return MIRROR_result;\n}\n\n\nIEC_REAL MIX(IEC_REAL A, IEC_REAL B, IEC_REAL M) {\n IEC_REAL MIX_result;\n MIX_result = (1.0 - M) * A + M * B;\n return MIX_result;\n}\n\n\nIEC_REAL MODR(IEC_REAL IN, IEC_REAL DIVI) {\n IEC_REAL MODR_result;\n if (DIVI == 0.0) {\n MODR_result = 0.0;\n } else {\n MODR_result = IN - TO_REAL(FLOOR2(IN / DIVI)) * DIVI;\n }\n return MODR_result;\n}\n\n\nIEC_DATE MONTH_BEGIN(IEC_DATE IDATE) {\n IEC_DATE MONTH_BEGIN_result;\n MONTH_BEGIN_result = TO_DATE(TO_DWORD(IDATE) - TO_DWORD(DAY_OF_MONTH(IDATE) - 1) * 86400);\n return MONTH_BEGIN_result;\n}\n\n\nIEC_DATE MONTH_END(IEC_DATE IDATE) {\n IEC_DATE MONTH_END_result;\n MONTH_END_result = TO_DATE(TO_DWORD(SET_DATE(YEAR_OF_DATE(IDATE), MONTH_OF_DATE(IDATE) + 1, 1)) - 86400);\n return MONTH_END_result;\n}\n\n\nIEC_INT MONTH_OF_DATE(IEC_DATE IDATE) {\n IEC_INT MONTH_OF_DATE_result;\n MONTH_OF_DATE_result = DAY_OF_YEAR(IDATE);\n if (MONTH_OF_DATE_result < 32) {\n MONTH_OF_DATE_result = 1;\n } else if (LEAP_OF_DATE(IDATE)) {\n MONTH_OF_DATE_result = (MONTH_OF_DATE_result * 53 + 1668) / 1623;\n } else {\n MONTH_OF_DATE_result = (MONTH_OF_DATE_result * 53 + 1700) / 1620;\n }\n return MONTH_OF_DATE_result;\n}\n\n\nIECStringVar<10> MONTH_TO_STRING(IEC_INT MTH, IEC_INT LANG, IEC_INT LX) {\n IECStringVar<10> MONTH_TO_STRING_result;\n IEC_INT LY;\n if (LANG <= 0) {\n LY = LANGUAGE.DEFAULT;\n } else {\n LY = MIN(LANG, LANGUAGE.LMAX);\n }\n if ((MTH < 1) | (MTH > 12)) {\n return MONTH_TO_STRING_result;\n } else if (LX == 0) {\n MONTH_TO_STRING_result = LANGUAGE.MONTHS(LY, MTH);\n } else if (LX == 3) {\n MONTH_TO_STRING_result = LANGUAGE.MONTHS3(LY, MTH);\n }\n return MONTH_TO_STRING_result;\n}\n\n\nIEC_INT MS_TO_BFT(IEC_REAL MS) {\n IEC_INT MS_TO_BFT_result;\n MS_TO_BFT_result = TO_INT(EXPT(MS * 1.196172, 0.666667));\n return MS_TO_BFT_result;\n}\n\n\nIEC_REAL MS_TO_KMH(IEC_REAL MS) {\n IEC_REAL MS_TO_KMH_result;\n MS_TO_KMH_result = MS * 3.6;\n return MS_TO_KMH_result;\n}\n\n\nIEC_TIME MULTIME(IEC_TIME T, IEC_REAL M) {\n IEC_TIME MULTIME_result;\n MULTIME_result = TO_TIME(TO_DWORD(TO_REAL(TO_DWORD(T)) * M));\n return MULTIME_result;\n}\n\n\nIEC_REAL MULTI_IN(IEC_REAL IN_1, IEC_REAL IN_2, IEC_REAL IN_3, IEC_REAL DEFAULT, IEC_REAL IN_MIN, IEC_REAL IN_MAX, IEC_BYTE MODE) {\n IEC_REAL MULTI_IN_result;\n IEC_INT COUNT;\n IEC_BOOL F1;\n IEC_BOOL F2;\n IEC_BOOL F3;\n F1 = (IN_1 > IN_MIN) & (IN_1 < IN_MAX);\n F2 = (IN_2 > IN_MIN) & (IN_2 < IN_MAX);\n F3 = (IN_3 > IN_MIN) & (IN_3 < IN_MAX);\n switch (MODE) {\n case 0:\n COUNT = 0;\n if (F1) {\n COUNT = COUNT + 1;\n MULTI_IN_result = IN_1;\n } else {\n MULTI_IN_result = 0.0;\n }\n if (F2) {\n COUNT = COUNT + 1;\n MULTI_IN_result = MULTI_IN_result + IN_2;\n }\n if (F3) {\n COUNT = COUNT + 1;\n MULTI_IN_result = MULTI_IN_result + IN_3;\n }\n MULTI_IN_result = SEL(COUNT == 0, MULTI_IN_result / TO_REAL(COUNT), DEFAULT);\n break;\n case 1:\n MULTI_IN_result = SEL(F1, DEFAULT, IN_1);\n break;\n case 2:\n MULTI_IN_result = SEL(F2, DEFAULT, IN_2);\n break;\n case 3:\n MULTI_IN_result = SEL(F3, DEFAULT, IN_3);\n break;\n case 4:\n MULTI_IN_result = DEFAULT;\n break;\n case 5:\n MULTI_IN_result = SEL(F1, IN_MAX, IN_1);\n if ((F2) & (IN_2 < MULTI_IN_result)) {\n MULTI_IN_result = IN_2;\n }\n if ((F3) & (IN_3 < MULTI_IN_result)) {\n MULTI_IN_result = IN_3;\n }\n if (MULTI_IN_result == IN_MAX) {\n MULTI_IN_result = DEFAULT;\n }\n break;\n case 6:\n MULTI_IN_result = SEL(F1, IN_MIN, IN_1);\n if ((F2) & (IN_2 > MULTI_IN_result)) {\n MULTI_IN_result = IN_2;\n }\n if ((F3) & (IN_3 > MULTI_IN_result)) {\n MULTI_IN_result = IN_3;\n }\n if (MULTI_IN_result == IN_MIN) {\n MULTI_IN_result = DEFAULT;\n }\n break;\n case 7:\n if (((F1) & (F2)) & (F3)) {\n MULTI_IN_result = MID3(IN_1, IN_2, IN_3);\n } else if ((F1) & (F2)) {\n MULTI_IN_result = MIN(IN_1, IN_2);\n } else if ((F1) & (F3)) {\n MULTI_IN_result = MIN(IN_1, IN_3);\n } else if ((F2) & (F3)) {\n MULTI_IN_result = MIN(IN_2, IN_3);\n } else if (F1) {\n MULTI_IN_result = IN_1;\n } else if (F2) {\n MULTI_IN_result = IN_2;\n } else if (F3) {\n MULTI_IN_result = IN_3;\n } else {\n MULTI_IN_result = DEFAULT;\n }\n break;\n }\n return MULTI_IN_result;\n}\n\n\nIEC_REAL MUL_ADD(IEC_REAL X, IEC_REAL K, IEC_REAL O) {\n IEC_REAL MUL_ADD_result;\n MUL_ADD_result = X * K + O;\n return MUL_ADD_result;\n}\n\n\nIEC_BOOL MUX_2(IEC_BOOL D0, IEC_BOOL D1, IEC_BOOL A0) {\n IEC_BOOL MUX_2_result;\n MUX_2_result = SEL(A0, D0, D1);\n return MUX_2_result;\n}\n\n\nIEC_BOOL MUX_4(IEC_BOOL D0, IEC_BOOL D1, IEC_BOOL D2, IEC_BOOL D3, IEC_BOOL A0, IEC_BOOL A1) {\n IEC_BOOL MUX_4_result;\n if (A1) {\n MUX_4_result = SEL(A0, D2, D3);\n } else {\n MUX_4_result = SEL(A0, D0, D1);\n }\n return MUX_4_result;\n}\n\n\nIEC_REAL MUX_R2(IEC_REAL IN0, IEC_REAL IN1, IEC_BOOL A) {\n IEC_REAL MUX_R2_result;\n MUX_R2_result = SEL(A, IN0, IN1);\n return MUX_R2_result;\n}\n\n\nIEC_REAL MUX_R4(IEC_REAL IN0, IEC_REAL IN1, IEC_REAL IN2, IEC_REAL IN3, IEC_BOOL A0, IEC_BOOL A1) {\n IEC_REAL MUX_R4_result;\n if (A1) {\n MUX_R4_result = SEL(A0, IN2, IN3);\n } else {\n MUX_R4_result = SEL(A0, IN0, IN1);\n }\n return MUX_R4_result;\n}\n\n\nIEC_REAL NEGX(IEC_REAL X) {\n IEC_REAL NEGX_result;\n NEGX_result = -X;\n return NEGX_result;\n}\n\n\nIEC_BYTE OCT_TO_BYTE(IECStringVar<10> OCT) {\n IEC_BYTE OCT_TO_BYTE_result;\n IEC_Ptr PT;\n IEC_INT I;\n IEC_BYTE X;\n IEC_INT STOP;\n PT = &(OCT);\n STOP = LEN(OCT);\n for (I = 1; I <= STOP; I++) {\n X = (*PT);\n if ((X > 47) & (X < 56)) {\n OCT_TO_BYTE_result = SHL(OCT_TO_BYTE_result, 3) + X - 48;\n }\n PT = PT + 1;\n }\n return OCT_TO_BYTE_result;\n}\n\n\nIEC_DWORD OCT_TO_DWORD(IECStringVar<20> OCT) {\n IEC_DWORD OCT_TO_DWORD_result;\n IEC_Ptr PT;\n IEC_INT I;\n IEC_BYTE X;\n IEC_INT STOP;\n PT = &(OCT);\n STOP = LEN(OCT);\n for (I = 1; I <= STOP; I++) {\n X = (*PT);\n if ((X > 47) & (X < 56)) {\n OCT_TO_DWORD_result = SHL(OCT_TO_DWORD_result, 3) + X - 48;\n }\n PT = PT + 1;\n }\n return OCT_TO_DWORD_result;\n}\n\n\nIEC_REAL OFFSET(IEC_REAL X, IEC_BOOL O1, IEC_BOOL O2, IEC_BOOL O3, IEC_BOOL O4, IEC_BOOL D, IEC_REAL OFFSET_1, IEC_REAL OFFSET_2, IEC_REAL OFFSET_3, IEC_REAL OFFSET_4, IEC_REAL DEFAULT) {\n IEC_REAL OFFSET_result;\n if (D) {\n OFFSET_result = DEFAULT;\n } else {\n OFFSET_result = X;\n }\n if (O1) {\n OFFSET_result = OFFSET_result + OFFSET_1;\n }\n if (O2) {\n OFFSET_result = OFFSET_result + OFFSET_2;\n }\n if (O3) {\n OFFSET_result = OFFSET_result + OFFSET_3;\n }\n if (O4) {\n OFFSET_result = OFFSET_result + OFFSET_4;\n }\n return OFFSET_result;\n}\n\n\nIEC_REAL OFFSET2(IEC_REAL X, IEC_BOOL O1, IEC_BOOL O2, IEC_BOOL O3, IEC_BOOL O4, IEC_BOOL D, IEC_REAL OFFSET_1, IEC_REAL OFFSET_2, IEC_REAL OFFSET_3, IEC_REAL OFFSET_4, IEC_REAL DEFAULT) {\n IEC_REAL OFFSET2_result;\n if (D) {\n OFFSET2_result = DEFAULT;\n } else {\n OFFSET2_result = X;\n }\n if (O4) {\n OFFSET2_result = OFFSET2_result + OFFSET_4;\n } else if (O3) {\n OFFSET2_result = OFFSET2_result + OFFSET_3;\n } else if (O2) {\n OFFSET2_result = OFFSET2_result + OFFSET_2;\n } else if (O1) {\n OFFSET2_result = OFFSET2_result + OFFSET_1;\n }\n return OFFSET2_result;\n}\n\n\nIEC_REAL OM_TO_F(IEC_REAL OM) {\n IEC_REAL OM_TO_F_result;\n OM_TO_F_result = OM / MATH.PI2;\n return OM_TO_F_result;\n}\n\n\nIEC_DWORD OSCAT_VERSION(IEC_BOOL IN) {\n IEC_DWORD OSCAT_VERSION_result;\n if (IN) {\n OSCAT_VERSION_result = TO_DWORD(0);\n } else {\n OSCAT_VERSION_result = 335;\n }\n return OSCAT_VERSION_result;\n}\n\n\nIEC_REAL OVERRIDE(IEC_REAL X1, IEC_REAL X2, IEC_REAL X3, IEC_BOOL E1, IEC_BOOL E2, IEC_BOOL E3) {\n IEC_REAL OVERRIDE_result;\n if (E1) {\n OVERRIDE_result = X1;\n }\n if ((E2) & (ABS(X2) > ABS(OVERRIDE_result))) {\n OVERRIDE_result = X2;\n }\n if ((E3) & (ABS(X3) > ABS(OVERRIDE_result))) {\n OVERRIDE_result = X3;\n }\n return OVERRIDE_result;\n}\n\n\nIEC_BOOL PARITY(IEC_DWORD IN) {\n IEC_BOOL PARITY_result;\n while (IN > 0) {\n PARITY_result = ((((PARITY_result) ^ (((static_cast(IN) >> 0) & 1))) ^ (((static_cast(IN) >> 1) & 1))) ^ (((static_cast(IN) >> 2) & 1))) ^ (((static_cast(IN) >> 3) & 1));\n IN = SHR(IN, 4);\n }\n return PARITY_result;\n}\n\n\nIEC_BOOL PERIOD(IEC_DATE D1, IEC_DATE DX, IEC_DATE D2) {\n IEC_BOOL PERIOD_result;\n IEC_INT DAY1;\n IEC_INT DAY2;\n IEC_INT DAYX;\n DAY1 = DAY_OF_YEAR(D1);\n DAY2 = DAY_OF_YEAR(D2);\n DAYX = DAY_OF_YEAR(DX);\n if ((!LEAP_OF_DATE(DX)) & (DAYX > 58)) {\n DAYX = DAYX + 1;\n }\n if ((!LEAP_OF_DATE(D1)) & (DAY1 > 58)) {\n DAY1 = DAY1 + 1;\n }\n if ((!LEAP_OF_DATE(D2)) & (DAY2 > 58)) {\n DAY2 = DAY2 + 1;\n }\n if (DAY2 < DAY1) {\n PERIOD_result = (DAYX <= DAY2) | (DAYX >= DAY1);\n } else {\n PERIOD_result = (DAYX >= DAY1) & (DAYX <= DAY2);\n }\n return PERIOD_result;\n}\n\n\nIEC_BOOL PERIOD2(Array2D DP, IEC_DATE DX) {\n IEC_BOOL PERIOD2_result;\n PERIOD2_result = (((((DX >= DP(0, 0)) & (DX <= DP(0, 1)))) | (((DX >= DP(1, 0)) & (DX <= DP(1, 1))))) | (((DX >= DP(2, 0)) & (DX <= DP(2, 1))))) | (((DX >= DP(3, 0)) & (DX <= DP(3, 1))));\n return PERIOD2_result;\n}\n\n\nIEC_REAL POLYNOM_INT(IEC_REAL X, Array2D XY, IEC_INT PTS) {\n IEC_REAL POLYNOM_INT_result;\n IEC_INT I;\n IEC_INT J;\n IEC_INT STOP;\n PTS = MIN(PTS, 5);\n for (I = 1; I <= PTS; I++) {\n STOP = I + 1;\n for (J = PTS; J >= STOP; J += -1) {\n XY(J, 1) = (XY(J, 1) - XY(J - 1, 1)) / (XY(J, 0) - XY(J - I, 0));\n }\n }\n POLYNOM_INT_result = 0.0;\n for (I = PTS; I >= 1; I += -1) {\n POLYNOM_INT_result = POLYNOM_INT_result * (X - XY(I, 0)) + XY(I, 1);\n }\n return POLYNOM_INT_result;\n}\n\n\nIEC_REAL PT_TO_F(IEC_TIME PT) {\n IEC_REAL PT_TO_F_result;\n PT_TO_F_result = 1000.0 / TO_REAL(TO_DWORD(PT));\n return PT_TO_F_result;\n}\n\n\nREAL2 R2_ABS(REAL2 X) {\n REAL2 R2_ABS_result;\n if (X.RX >= 0.0) {\n R2_ABS_result.RX = X.RX;\n R2_ABS_result.R1 = X.R1;\n } else {\n R2_ABS_result.RX = -X.RX;\n R2_ABS_result.R1 = -X.R1;\n }\n return R2_ABS_result;\n}\n\n\nREAL2 R2_ADD(REAL2 X, IEC_REAL Y) {\n REAL2 R2_ADD_result;\n IEC_REAL TEMP;\n TEMP = X.RX;\n R2_ADD_result.RX = Y + X.R1 + X.RX;\n R2_ADD_result.R1 = TEMP - R2_ADD_result.RX + Y + X.R1;\n return R2_ADD_result;\n}\n\n\nREAL2 R2_ADD2(REAL2 X, REAL2 Y) {\n REAL2 R2_ADD2_result;\n R2_ADD2_result.R1 = X.R1 + Y.R1;\n R2_ADD2_result.RX = X.RX + Y.RX;\n return R2_ADD2_result;\n}\n\n\nREAL2 R2_MUL(REAL2 X, IEC_REAL Y) {\n REAL2 R2_MUL_result;\n R2_MUL_result.RX = X.RX * Y;\n R2_MUL_result.R1 = X.R1 * Y;\n return R2_MUL_result;\n}\n\n\nREAL2 R2_SET(IEC_REAL X) {\n REAL2 R2_SET_result;\n R2_SET_result.RX = X;\n R2_SET_result.R1 = 0.0;\n return R2_SET_result;\n}\n\n\nIEC_REAL RAD(IEC_REAL DEG) {\n IEC_REAL RAD_result;\n RAD_result = MODR(0.0174532925199433 * DEG, MATH.PI2);\n return RAD_result;\n}\n\n\nIEC_BYTE RANGE_TO_BYTE(IEC_REAL X, IEC_REAL LOW, IEC_REAL HIGH) {\n IEC_BYTE RANGE_TO_BYTE_result;\n RANGE_TO_BYTE_result = TO_BYTE(TRUNC((LIMIT(LOW, X, HIGH) - LOW) * 255.0 / (HIGH - LOW)));\n return RANGE_TO_BYTE_result;\n}\n\n\nIEC_WORD RANGE_TO_WORD(IEC_REAL X, IEC_REAL LOW, IEC_REAL HIGH) {\n IEC_WORD RANGE_TO_WORD_result;\n RANGE_TO_WORD_result = TO_WORD(TRUNC((LIMIT(LOW, X, HIGH) - LOW) * 65535.0 / (HIGH - LOW)));\n return RANGE_TO_WORD_result;\n}\n\n\nIEC_REAL RDM(IEC_REAL LAST) {\n IEC_REAL RDM_result;\n IEC_DWORD TN;\n IEC_INT TC;\n TN = T_PLC_MS();\n TC = BIT_COUNT(TN);\n TN = (TN & ~(1ULL << 31)) | ((((static_cast(TN) >> 2) & 1) ? 1ULL : 0ULL) << 31);\n TN = (TN & ~(1ULL << 30)) | ((((static_cast(TN) >> 5) & 1) ? 1ULL : 0ULL) << 30);\n TN = (TN & ~(1ULL << 29)) | ((((static_cast(TN) >> 4) & 1) ? 1ULL : 0ULL) << 29);\n TN = (TN & ~(1ULL << 28)) | ((((static_cast(TN) >> 1) & 1) ? 1ULL : 0ULL) << 28);\n TN = (TN & ~(1ULL << 27)) | ((((static_cast(TN) >> 0) & 1) ? 1ULL : 0ULL) << 27);\n TN = (TN & ~(1ULL << 26)) | ((((static_cast(TN) >> 7) & 1) ? 1ULL : 0ULL) << 26);\n TN = (TN & ~(1ULL << 25)) | ((((static_cast(TN) >> 6) & 1) ? 1ULL : 0ULL) << 25);\n TN = (TN & ~(1ULL << 24)) | ((((static_cast(TN) >> 3) & 1) ? 1ULL : 0ULL) << 24);\n TN = (ROL(TN, BIT_COUNT(TN))) | (0x80000001);\n TN = TN % 71474513 + TO_DWORD(TC + 77);\n RDM_result = FRACT(TO_REAL(TN) / 10000000.0 * (MATH.E - LIMIT(0.0, LAST, 1.0)));\n return RDM_result;\n}\n\n\nIEC_INT RDM2(IEC_INT LAST, IEC_INT LOW, IEC_INT HIGH) {\n IEC_INT RDM2_result;\n RDM2_result = TRUNC(RDM(FRACT(LAST * MATH.PI)) * (HIGH - LOW + 1)) + LOW;\n return RDM2_result;\n}\n\n\nIEC_DWORD RDMDW(IEC_DWORD LAST) {\n IEC_DWORD RDMDW_result;\n IEC_REAL RX;\n IEC_REAL M;\n M = BIT_COUNT(LAST);\n RX = RDM(FRACT(M * MATH.PI));\n RDMDW_result = SHL(TO_DWORD(RX * 65535), 16);\n RX = RDM(FRACT(M * MATH.E));\n RDMDW_result = (RDMDW_result) | (((TO_DWORD(RX * 65535)) & (0x0000FFFF)));\n return RDMDW_result;\n}\n\n\nIEC_DWORD REAL_TO_DW(IEC_REAL X) {\n IEC_DWORD REAL_TO_DW_result;\n IEC_Ptr PT;\n PT = &(X);\n REAL_TO_DW_result = (*PT);\n return REAL_TO_DW_result;\n}\n\n\nFRACTION REAL_TO_FRAC(IEC_REAL X, IEC_INT N) {\n FRACTION REAL_TO_FRAC_result;\n IEC_DINT TEMP;\n IEC_BOOL SIGN;\n IEC_DINT X_GERUNDET;\n IEC_REAL X_OHNE_NACHKOMMA;\n IEC_DINT NUMERATOR = 1;\n IEC_DINT DENOMINATOR = 0;\n IEC_DINT NUMERATOR_OLD = 0;\n IEC_DINT DENOMINATOR_OLD = 1;\n if (X < 0.0) {\n SIGN = true;\n X = ABS(X);\n }\n do {\n X_GERUNDET = TO_DINT(X);\n TEMP = NUMERATOR * X_GERUNDET + NUMERATOR_OLD;\n NUMERATOR_OLD = NUMERATOR;\n NUMERATOR = TEMP;\n TEMP = DENOMINATOR * X_GERUNDET + DENOMINATOR_OLD;\n DENOMINATOR_OLD = DENOMINATOR;\n DENOMINATOR = TEMP;\n X_OHNE_NACHKOMMA = TO_REAL(X_GERUNDET);\n if (X == X_OHNE_NACHKOMMA) {\n if (ABS(DENOMINATOR) <= N) {\n NUMERATOR_OLD = NUMERATOR;\n DENOMINATOR_OLD = DENOMINATOR;\n }\n goto __strucpp_loop_exit_107;\n } else {\n X = 1.0 / (X - X_OHNE_NACHKOMMA);\n }\n } while (!(ABS(DENOMINATOR) > N));\n __strucpp_loop_exit_107: ;\n if (SIGN) {\n REAL_TO_FRAC_result.NUMERATOR = -1 * ABS(TO_INT(NUMERATOR_OLD));\n } else {\n REAL_TO_FRAC_result.NUMERATOR = ABS(TO_INT(NUMERATOR_OLD));\n }\n REAL_TO_FRAC_result.DENOMINATOR = ABS(TO_INT(DENOMINATOR_OLD));\n return REAL_TO_FRAC_result;\n}\n\n\nIECStringVar<20> REAL_TO_STRF(IEC_REAL IN, IEC_INT N, IECStringVar<1> D) {\n IECStringVar<20> REAL_TO_STRF_result;\n IEC_REAL O;\n IEC_INT I;\n N = LIMIT(0, N, 7);\n O = ABS(IN) * EXP10(static_cast(N));\n REAL_TO_STRF_result = TO_STRING(TO_DINT(O));\n for (I = LEN(REAL_TO_STRF_result); I <= N; I++) {\n REAL_TO_STRF_result = CONCAT(\"0\", REAL_TO_STRF_result);\n }\n if (N > 0) {\n REAL_TO_STRF_result = INSERT(REAL_TO_STRF_result, D, LEN(REAL_TO_STRF_result) - N);\n }\n if (IN < 0) {\n REAL_TO_STRF_result = CONCAT(\"-\", REAL_TO_STRF_result);\n }\n return REAL_TO_STRF_result;\n}\n\n\nIEC_DWORD REFLECT(IEC_DWORD D, IEC_INT L) {\n IEC_DWORD REFLECT_result;\n IEC_INT I;\n REFLECT_result = 0;\n for (I = 1; I <= L; I++) {\n REFLECT_result = (SHL(REFLECT_result, 1)) | (TO_DWORD(((static_cast(D) >> 0) & 1)));\n D = SHR(D, 1);\n }\n REFLECT_result = (REFLECT_result) | (SHL(D, L));\n return REFLECT_result;\n}\n\n\nIEC_REAL REFRACTION(IEC_REAL ELEV) {\n IEC_REAL REFRACTION_result;\n ELEV = LIMIT(-1.9, ELEV, 80.0);\n REFRACTION_result = 0.0174532925199433 / TAN(0.0174532925199433 * (ELEV + 10.3 / (ELEV + 5.11)));\n return REFRACTION_result;\n}\n\n\nIECStringVar REPLACE_ALL(IECStringVar STR, IECStringVar SRC, IECStringVar REP) {\n IECStringVar REPLACE_ALL_result;\n IEC_INT POS;\n IEC_INT LP;\n IEC_INT LX;\n REPLACE_ALL_result = STR;\n LX = LEN(SRC);\n LP = LEN(REP);\n POS = FINDP(REPLACE_ALL_result, SRC, 1);\n while (POS > 0) {\n REPLACE_ALL_result = REPLACE(REPLACE_ALL_result, REP, LX, POS);\n POS = FINDP(REPLACE_ALL_result, SRC, POS + LP);\n }\n return REPLACE_ALL_result;\n}\n\n\nIECStringVar REPLACE_CHARS(IECStringVar STR, IEC_STRING SRC, IEC_STRING REP) {\n IECStringVar REPLACE_CHARS_result;\n IEC_INT A;\n IEC_INT B;\n IECStringVar<1> C;\n IEC_INT STP;\n REPLACE_CHARS_result = STR;\n A = LEN(SRC);\n B = LEN(REP);\n if (A < B) {\n REP = LEFT(REP, A);\n } else if (B < A) {\n SRC = LEFT(SRC, B);\n }\n STP = LEN(STR);\n for (A = 1; A <= STP; A++) {\n C = MID(REPLACE_CHARS_result, 1, A);\n B = FIND(SRC, C);\n if (B > 0) {\n REPLACE_CHARS_result = REPLACE(REPLACE_CHARS_result, MID(REP, 1, B), 1, A);\n }\n }\n return REPLACE_CHARS_result;\n}\n\n\nIECStringVar REPLACE_UML(IECStringVar STR) {\n IECStringVar REPLACE_UML_result;\n IEC_INT L;\n IEC_Ptr PT;\n IEC_Ptr PTO;\n IEC_Ptr PTM;\n IEC_Ptr PT1;\n IEC_Ptr PT2;\n IECStringVar<2> SU;\n IEC_INT POS;\n PT = &(STR);\n PTO = &(REPLACE_UML_result);\n PTM = PTO + TO_DWORD(STRING_LENGTH);\n PT1 = &(SU);\n PT2 = PT1 + 1;\n L = LEN(STR);\n while ((POS < L) & (POS < STRING_LENGTH)) {\n if ((*PT) < 127) {\n (*PTO) = (*PT);\n } else {\n SU = TO_UML((*PT));\n (*PTO) = (*PT1);\n if ((PTO < PTM) & ((*PT2) > 0)) {\n PTO = PTO + 1;\n (*PTO) = (*PT2);\n }\n }\n PT = PT + 1;\n PTO = PTO + 1;\n POS = POS + 1;\n }\n (*PTO) = 0;\n return REPLACE_UML_result;\n}\n\n\nIEC_REAL RES_NI(IEC_REAL T, IEC_REAL R0) {\n IEC_REAL RES_NI_result;\n IEC_REAL A = 0.5485;\n IEC_REAL B = 0.000665;\n IEC_REAL C = 2.805e-9;\n IEC_REAL T2;\n T2 = T * T;\n RES_NI_result = R0 + A * T + B * T2 + C * T2 * T2;\n return RES_NI_result;\n}\n\n\nIEC_REAL RES_NTC(IEC_REAL T, IEC_REAL RN, IEC_REAL B) {\n IEC_REAL RES_NTC_result;\n RES_NTC_result = RN * EXP(B * (1.0 / (T + 273.15) - 0.00335401643468053));\n return RES_NTC_result;\n}\n\n\nIEC_REAL RES_PT(IEC_REAL T, IEC_REAL R0) {\n IEC_REAL RES_PT_result;\n IEC_REAL A = 0.00390802;\n IEC_REAL B = -5.802e-7;\n IEC_REAL C = -4.2735e-12;\n IEC_REAL T2;\n T2 = T * T;\n if (T >= 0.0) {\n RES_PT_result = R0 * (1.0 + A * T + B * T2);\n } else {\n RES_PT_result = R0 * (1.0 + A * T + B * T2 + C * (T - 100.0) * T2 * T);\n }\n return RES_PT_result;\n}\n\n\nIEC_REAL RES_SI(IEC_REAL T, IEC_REAL RS, IEC_REAL TS) {\n IEC_REAL RES_SI_result;\n IEC_REAL A = 0.00764;\n IEC_REAL B = 0.0000166;\n IEC_REAL TX;\n TX = T - TS;\n RES_SI_result = RS * (1.0 + A * TX + B * TX * TX);\n return RES_SI_result;\n}\n\n\nIEC_BYTE REVERSE(IEC_BYTE IN) {\n IEC_BYTE REVERSE_result;\n REVERSE_result = ((((ROR(IN, 1)) & (0b10001000)) | ((ROL(IN, 1)) & (0b00010001))) | ((ROR(IN, 3)) & (0b01000100))) | ((ROL(IN, 3)) & (0b00100010));\n return REVERSE_result;\n}\n\n\nIEC_REAL RND(IEC_REAL X, IEC_INT N) {\n IEC_REAL RND_result;\n IEC_REAL M;\n if (X == 0.0) {\n RND_result = 0.0;\n } else {\n M = EXPN(10.0, N - CEIL(LOG(ABS(X))));\n RND_result = TO_REAL(TO_DINT(X * M)) / M;\n }\n return RND_result;\n}\n\n\nIEC_REAL ROUND(IEC_REAL IN, IEC_INT N) {\n IEC_REAL ROUND_result;\n IEC_REAL X;\n X = SETUP.DECADES[LIMIT(0, N, 8)];\n ROUND_result = TO_REAL(TO_DINT(IN * X)) / X;\n return ROUND_result;\n}\n\n\nIEC_REAL SCALE(IEC_REAL X, IEC_REAL K, IEC_REAL O, IEC_REAL MX, IEC_REAL MN) {\n IEC_REAL SCALE_result;\n SCALE_result = LIMIT(MN, X * K + O, MX);\n return SCALE_result;\n}\n\n\nIEC_REAL SCALE_B(IEC_BYTE X, IEC_BYTE I_LO, IEC_BYTE I_HI, IEC_REAL O_LO, IEC_REAL O_HI) {\n IEC_REAL SCALE_B_result;\n if (I_HI == I_LO) {\n SCALE_B_result = O_LO;\n } else {\n SCALE_B_result = (O_HI - O_LO) / TO_REAL(I_HI - I_LO) * TO_REAL(LIMIT(I_LO, X, I_HI));\n }\n return SCALE_B_result;\n}\n\n\nIEC_REAL SCALE_B2(IEC_BYTE IN1, IEC_BYTE IN2, IEC_REAL K, IEC_REAL O, IEC_REAL IN1_MIN, IEC_REAL IN1_MAX, IEC_REAL IN2_MIN, IEC_REAL IN2_MAX) {\n IEC_REAL SCALE_B2_result;\n SCALE_B2_result = (((IN1_MAX - IN1_MIN) * IN1 + (IN2_MAX - IN2_MIN) * IN2) * 0.003921569 + IN1_MIN + IN2_MIN) * K + O;\n return SCALE_B2_result;\n}\n\n\nIEC_REAL SCALE_B4(IEC_BYTE IN1, IEC_BYTE IN2, IEC_BYTE IN3, IEC_BYTE IN4, IEC_REAL K, IEC_REAL O, IEC_REAL IN1_MIN, IEC_REAL IN1_MAX, IEC_REAL IN2_MIN, IEC_REAL IN2_MAX, IEC_REAL IN3_MIN, IEC_REAL IN3_MAX, IEC_REAL IN4_MIN, IEC_REAL IN4_MAX) {\n IEC_REAL SCALE_B4_result;\n SCALE_B4_result = (((IN1_MAX - IN1_MIN) * IN1 + (IN2_MAX - IN2_MIN) * IN2 + (IN3_MAX - IN3_MIN) * IN3 + (IN4_MAX - IN4_MIN) * IN4) * 0.003921569 + IN1_MIN + IN2_MIN + IN3_MIN + IN4_MIN) * K + O;\n return SCALE_B4_result;\n}\n\n\nIEC_REAL SCALE_B8(IEC_BYTE IN1, IEC_BYTE IN2, IEC_BYTE IN3, IEC_BYTE IN4, IEC_BYTE IN5, IEC_BYTE IN6, IEC_BYTE IN7, IEC_BYTE IN8, IEC_REAL K, IEC_REAL O, IEC_REAL IN1_MIN, IEC_REAL IN1_MAX, IEC_REAL IN2_MIN, IEC_REAL IN2_MAX, IEC_REAL IN3_MIN, IEC_REAL IN3_MAX, IEC_REAL IN4_MIN, IEC_REAL IN4_MAX, IEC_REAL IN5_MIN, IEC_REAL IN5_MAX, IEC_REAL IN6_MIN, IEC_REAL IN6_MAX, IEC_REAL IN7_MIN, IEC_REAL IN7_MAX, IEC_REAL IN8_MIN, IEC_REAL IN8_MAX) {\n IEC_REAL SCALE_B8_result;\n SCALE_B8_result = (((IN1_MAX - IN1_MIN) * IN1 + (IN2_MAX - IN2_MIN) * IN2 + (IN3_MAX - IN3_MIN) * IN3 + (IN4_MAX - IN4_MIN) * IN4 + (IN5_MAX - IN5_MIN) * IN5 + (IN6_MAX - IN6_MIN) * IN6 + (IN7_MAX - IN7_MIN) * IN7 + (IN8_MAX - IN8_MIN) * IN8) * 0.003921569 + IN1_MIN + IN2_MIN + IN3_MIN + IN4_MIN + IN5_MIN + IN6_MIN + IN7_MIN + IN8_MIN) * K + O;\n return SCALE_B8_result;\n}\n\n\nIEC_REAL SCALE_D(IEC_DWORD X, IEC_DWORD I_LO, IEC_DWORD I_HI, IEC_REAL O_LO, IEC_REAL O_HI) {\n IEC_REAL SCALE_D_result;\n if (I_HI == I_LO) {\n SCALE_D_result = O_LO;\n } else {\n SCALE_D_result = (O_HI - O_LO) / TO_REAL(I_HI - I_LO) * TO_REAL(LIMIT(I_LO, X, I_HI) - I_LO) + O_LO;\n }\n return SCALE_D_result;\n}\n\n\nIEC_REAL SCALE_R(IEC_REAL X, IEC_REAL I_LO, IEC_REAL I_HI, IEC_REAL O_LO, IEC_REAL O_HI) {\n IEC_REAL SCALE_R_result;\n if (I_LO == I_HI) {\n SCALE_R_result = O_LO;\n } else {\n SCALE_R_result = (O_HI - O_LO) / (I_HI - I_LO) * (LIMIT(I_LO, X, I_HI) - I_LO) + O_LO;\n }\n return SCALE_R_result;\n}\n\n\nIEC_REAL SCALE_X2(IEC_BOOL IN1, IEC_BOOL IN2, IEC_REAL K, IEC_REAL O, IEC_REAL IN1_MIN, IEC_REAL IN1_MAX, IEC_REAL IN2_MIN, IEC_REAL IN2_MAX) {\n IEC_REAL SCALE_X2_result;\n SCALE_X2_result = (SEL(IN1, IN1_MIN, IN1_MAX) + SEL(IN2, IN2_MIN, IN2_MAX)) * K + O;\n return SCALE_X2_result;\n}\n\n\nIEC_REAL SCALE_X4(IEC_BOOL IN1, IEC_BOOL IN2, IEC_BOOL IN3, IEC_BOOL IN4, IEC_REAL K, IEC_REAL O, IEC_REAL IN1_MIN, IEC_REAL IN1_MAX, IEC_REAL IN2_MIN, IEC_REAL IN2_MAX, IEC_REAL IN3_MIN, IEC_REAL IN3_MAX, IEC_REAL IN4_MIN, IEC_REAL IN4_MAX) {\n IEC_REAL SCALE_X4_result;\n SCALE_X4_result = (SEL(IN1, IN1_MIN, IN1_MAX) + SEL(IN2, IN2_MIN, IN2_MAX) + SEL(IN3, IN3_MIN, IN3_MAX) + SEL(IN4, IN4_MIN, IN4_MAX)) * K + O;\n return SCALE_X4_result;\n}\n\n\nIEC_REAL SCALE_X8(IEC_BOOL IN1, IEC_BOOL IN2, IEC_BOOL IN3, IEC_BOOL IN4, IEC_BOOL IN5, IEC_BOOL IN6, IEC_BOOL IN7, IEC_BOOL IN8, IEC_REAL K, IEC_REAL O, IEC_REAL IN1_MIN, IEC_REAL IN1_MAX, IEC_REAL IN2_MIN, IEC_REAL IN2_MAX, IEC_REAL IN3_MIN, IEC_REAL IN3_MAX, IEC_REAL IN4_MIN, IEC_REAL IN4_MAX, IEC_REAL IN5_MIN, IEC_REAL IN5_MAX, IEC_REAL IN6_MIN, IEC_REAL IN6_MAX, IEC_REAL IN7_MIN, IEC_REAL IN7_MAX, IEC_REAL IN8_MIN, IEC_REAL IN8_MAX) {\n IEC_REAL SCALE_X8_result;\n SCALE_X8_result = (SEL(IN1, IN1_MIN, IN1_MAX) + SEL(IN2, IN2_MIN, IN2_MAX) + SEL(IN3, IN3_MIN, IN3_MAX) + SEL(IN4, IN4_MIN, IN4_MAX) + SEL(IN5, IN5_MIN, IN5_MAX) + SEL(IN6, IN6_MIN, IN6_MAX) + SEL(IN7, IN7_MIN, IN7_MAX) + SEL(IN8, IN8_MIN, IN8_MAX)) * K + O;\n return SCALE_X8_result;\n}\n\n\nIEC_DATE SDT_TO_DATE(SDT DTI) {\n IEC_DATE SDT_TO_DATE_result;\n SDT_TO_DATE_result = SET_DATE(DTI.YEAR, DTI.MONTH, DTI.DAY);\n return SDT_TO_DATE_result;\n}\n\n\nIEC_DT SDT_TO_DT(SDT DTI) {\n IEC_DT SDT_TO_DT_result;\n SDT_TO_DT_result = SET_DT(DTI.YEAR, DTI.MONTH, DTI.DAY, DTI.HOUR, DTI.MINUTE, DTI.SECOND);\n return SDT_TO_DT_result;\n}\n\n\nIEC_TOD SDT_TO_TOD(SDT DTI) {\n IEC_TOD SDT_TO_TOD_result;\n SDT_TO_TOD_result = TO_TOD(TO_DWORD(DTI.HOUR) * 3600000 + TO_DWORD(DTI.MINUTE) * 60000 + TO_DWORD(DTI.SECOND) * 1000 + TO_DWORD(DTI.MS));\n return SDT_TO_TOD_result;\n}\n\n\nIEC_REAL SECOND(IEC_TOD ITOD) {\n IEC_REAL SECOND_result;\n SECOND_result = TO_REAL(TO_DWORD(ITOD) - TO_DWORD(ITOD) / 60000 * 60000) / 1000.0;\n return SECOND_result;\n}\n\n\nIEC_INT SECOND_OF_DT(IEC_DT XDT) {\n IEC_INT SECOND_OF_DT_result;\n SECOND_OF_DT_result = TO_INT(TO_DWORD(XDT) % 60);\n return SECOND_OF_DT_result;\n}\n\n\nIEC_TIME SECOND_TO_TIME(IEC_REAL IN) {\n IEC_TIME SECOND_TO_TIME_result;\n SECOND_TO_TIME_result = TO_TIME(TO_DWORD(IN * 1000.0));\n return SECOND_TO_TIME_result;\n}\n\n\nIEC_REAL SENSOR_INT(IEC_REAL VOLTAGE, IEC_REAL CURRENT, IEC_REAL RP, IEC_REAL RS) {\n IEC_REAL SENSOR_INT_result;\n IEC_REAL RG;\n if (CURRENT != 0.0) {\n RG = VOLTAGE / CURRENT;\n SENSOR_INT_result = RP * (RG - RS) / (RP + RS - RG);\n }\n return SENSOR_INT_result;\n}\n\n\nIEC_DATE SET_DATE(IEC_INT YEAR, IEC_INT MONTH, IEC_INT DAY) {\n IEC_DATE SET_DATE_result;\n IEC_INT COUNT;\n Array1D OFS = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};\n IEC_BOOL ENDIF;\n if (((MONTH > 2)) & ((SHL(YEAR, 14) == 0))) {\n SET_DATE_result = TO_DATE((TO_DWORD(OFS[MONTH] + DAY) + SHR(TO_DWORD(YEAR) * 1461 - 2878169, 2)) * 86400);\n } else {\n SET_DATE_result = TO_DATE((TO_DWORD(OFS[MONTH] + DAY - 1) + SHR(TO_DWORD(YEAR) * 1461 - 2878169, 2)) * 86400);\n }\n return SET_DATE_result;\n}\n\n\nIEC_DT SET_DT(IEC_INT YEAR, IEC_INT MONTH, IEC_INT DAY, IEC_INT HOUR, IEC_INT MINUTE, IEC_INT SECOND) {\n IEC_DT SET_DT_result;\n SET_DT_result = TO_DT(TO_DWORD(SET_DATE(YEAR, MONTH, DAY)) + TO_DWORD(SECOND) + TO_DWORD(MINUTE) * 60 + TO_DWORD(HOUR) * 3600);\n return SET_DT_result;\n}\n\n\nIEC_TOD SET_TOD(IEC_INT HOUR, IEC_INT MINUTE, IEC_REAL SECOND) {\n IEC_TOD SET_TOD_result;\n SET_TOD_result = TO_TOD(TO_DWORD(SECOND * 1000.0) + TO_DWORD(MINUTE) * 60000 + TO_DWORD(HOUR) * 3600000);\n return SET_TOD_result;\n}\n\n\nIEC_INT SGN(IEC_REAL X) {\n IEC_INT SGN_result;\n if (X > 0) {\n SGN_result = 1;\n } else if (X < 0) {\n SGN_result = -1;\n } else {\n SGN_result = 0;\n }\n return SGN_result;\n}\n\n\nIEC_DWORD SHL1(IEC_DWORD IN, IEC_INT N) {\n IEC_DWORD SHL1_result;\n IEC_DWORD TEMP = 0xFFFFFFFF;\n SHL1_result = (SHR(TEMP, 32 - N)) | (SHL(IN, N));\n return SHL1_result;\n}\n\n\nIEC_DWORD SHR1(IEC_DWORD IN, IEC_INT N) {\n IEC_DWORD SHR1_result;\n IEC_DWORD TEMP = 0xFFFFFFFF;\n SHR1_result = (SHL(TEMP, 32 - N)) | (SHR(IN, N));\n return SHR1_result;\n}\n\n\nIEC_REAL SIGMOID(IEC_REAL X) {\n IEC_REAL SIGMOID_result;\n if (X > 20.0) {\n SIGMOID_result = 1.0;\n } else if (X < -85.0) {\n SIGMOID_result = 0.0;\n } else {\n SIGMOID_result = 1.0 / (1.0 + EXP(-X));\n }\n return SIGMOID_result;\n}\n\n\nIEC_BOOL SIGN_I(IEC_DINT IN) {\n IEC_BOOL SIGN_I_result;\n SIGN_I_result = ((static_cast(IN) >> 31) & 1);\n return SIGN_I_result;\n}\n\n\nIEC_BOOL SIGN_R(IEC_REAL IN) {\n IEC_BOOL SIGN_R_result;\n SIGN_R_result = IN < 0.0;\n return SIGN_R_result;\n}\n\n\nIEC_REAL SINC(IEC_REAL X) {\n IEC_REAL SINC_result;\n if (X == 0.0) {\n SINC_result = 1.0;\n } else {\n SINC_result = SIN(X) / X;\n }\n return SINC_result;\n}\n\n\nIEC_REAL SINH(IEC_REAL X) {\n IEC_REAL SINH_result;\n if (ABS(X) < 0.002) {\n SINH_result = X;\n } else {\n SINH_result = (EXP(X) - EXP(-X)) * 0.5;\n }\n return SINH_result;\n}\n\n\nIEC_REAL SPHERE_V(IEC_REAL RX) {\n IEC_REAL SPHERE_V_result;\n SPHERE_V_result = 4.188790205 * RX * RX * RX;\n return SPHERE_V_result;\n}\n\n\nIEC_REAL SQRTN(IEC_REAL X, IEC_INT N) {\n IEC_REAL SQRTN_result;\n if (N > 0) {\n SQRTN_result = EXP(LN(X) / TO_REAL(N));\n } else {\n SQRTN_result = 0.0;\n }\n return SQRTN_result;\n}\n\n\nIEC_REAL STAIR(IEC_REAL X, IEC_REAL D) {\n IEC_REAL STAIR_result;\n if (D > 0.0) {\n STAIR_result = TO_REAL(TO_DINT(X / D)) * D;\n } else {\n STAIR_result = X;\n }\n return STAIR_result;\n}\n\n\nESR_DATA STATUS_TO_ESR(IEC_BYTE STATUS, IECStringVar<10> ADRESS, IEC_DT DT_IN, IEC_TIME TS) {\n ESR_DATA STATUS_TO_ESR_result;\n if (STATUS < 100) {\n STATUS_TO_ESR_result.TYP = 1;\n } else if (STATUS < 200) {\n STATUS_TO_ESR_result.TYP = 2;\n } else {\n STATUS_TO_ESR_result.TYP = 3;\n }\n STATUS_TO_ESR_result.ADRESS = ADRESS;\n STATUS_TO_ESR_result.DS = DT_IN;\n STATUS_TO_ESR_result.TS = TS;\n STATUS_TO_ESR_result.DATA[0] = STATUS;\n return STATUS_TO_ESR_result;\n}\n\n\nIEC_TOD SUN_MIDDAY(IEC_REAL LON, IEC_DATE UTC) {\n IEC_TOD SUN_MIDDAY_result;\n IEC_REAL T;\n IEC_REAL OFFSET;\n T = TO_REAL(DAY_OF_YEAR(UTC));\n OFFSET = -0.1752 * SIN(0.03343 * T + 0.5474) - 0.134 * SIN(0.018234 * T - 0.1939);\n SUN_MIDDAY_result = HOUR_TO_TOD(12.0 - OFFSET - LON * 0.0666666666666);\n return SUN_MIDDAY_result;\n}\n\n\nIEC_WORD SWAP_BYTE(IEC_WORD IN) {\n IEC_WORD SWAP_BYTE_result;\n SWAP_BYTE_result = ROL(IN, 8);\n return SWAP_BYTE_result;\n}\n\n\nIEC_DWORD SWAP_BYTE2(IEC_DWORD IN) {\n IEC_DWORD SWAP_BYTE2_result;\n SWAP_BYTE2_result = (((ROR(IN, 8)) & (0xFF00FF00))) | (((ROL(IN, 8)) & (0x00FF00FF)));\n return SWAP_BYTE2_result;\n}\n\n\nIEC_REAL TANC(IEC_REAL X) {\n IEC_REAL TANC_result;\n if (X == 0.0) {\n TANC_result = 1.0;\n } else {\n TANC_result = TAN(X) / X;\n }\n return TANC_result;\n}\n\n\nIEC_REAL TANH(IEC_REAL X) {\n IEC_REAL TANH_result;\n if (X > 20.0) {\n TANH_result = 1.0;\n } else if (X < -20.0) {\n TANH_result = -1.0;\n } else {\n TANH_result = 1.0 - 2.0 / (EXP(2.0 * X) + 1.0);\n }\n return TANH_result;\n}\n\n\nIEC_REAL TEMP_NI(IEC_REAL RES, IEC_REAL R0) {\n IEC_REAL TEMP_NI_result;\n TEMP_NI_result = (SQRT(0.30085225 - 0.00266 * (R0 - RES)) - 0.5485) * 751.8796992;\n return TEMP_NI_result;\n}\n\n\nIEC_REAL TEMP_NTC(IEC_REAL RES, IEC_REAL RN, IEC_REAL B) {\n IEC_REAL TEMP_NTC_result;\n if (RES > 0.0) {\n TEMP_NTC_result = B * 298.15 / (B + LN(RES / RN) * 298.15) - 273.15;\n }\n return TEMP_NTC_result;\n}\n\n\nIEC_REAL TEMP_PT(IEC_REAL RES, IEC_REAL R0) {\n IEC_REAL TEMP_PT_result;\n IEC_REAL A = 0.0039083;\n IEC_REAL B = -5.775e-7;\n IEC_REAL ACCURACY = 0.01;\n IEC_REAL STEP = 50.0;\n IEC_REAL X;\n IEC_REAL Y;\n IEC_REAL T1;\n IEC_Ptr PT;\n X = A * R0;\n Y = B * R0;\n if (RES >= R0) {\n T1 = X * X - 4.0 * Y * (R0 - RES);\n if (T1 < 0.0) {\n TEMP_PT_result = 10000.0;\n } else {\n TEMP_PT_result = (-X + SQRT(T1)) / (2.0 * Y);\n }\n } else {\n PT = &(STEP);\n TEMP_PT_result = -100.0;\n while (STEP > ACCURACY) {\n if (RES_PT(TEMP_PT_result, R0) < RES) {\n TEMP_PT_result = TEMP_PT_result + STEP;\n } else {\n TEMP_PT_result = TEMP_PT_result - STEP;\n }\n (*PT) = (*PT) - 8388608;\n }\n }\n return TEMP_PT_result;\n}\n\n\nIEC_REAL TEMP_SI(IEC_REAL RES, IEC_REAL RS, IEC_REAL TS) {\n IEC_REAL TEMP_SI_result;\n TEMP_SI_result = (-0.00764 + SQRT(RES / RS * 0.0000664 - 0.00000803)) * 30120.48193 + TS;\n return TEMP_SI_result;\n}\n\n\nIEC_BOOL TIMECHECK(IEC_TOD TD, IEC_TOD START, IEC_TOD STOP) {\n IEC_BOOL TIMECHECK_result;\n if (STOP < START) {\n TIMECHECK_result = (START <= TD) | (TD < STOP);\n } else {\n TIMECHECK_result = (START <= TD) & (TD < STOP);\n }\n return TIMECHECK_result;\n}\n\n\nIEC_BYTE TO_LOWER(IEC_BYTE IN) {\n IEC_BYTE TO_LOWER_result;\n if ((IN > 64) & (IN < 91)) {\n TO_LOWER_result = (IN) | (0x20);\n } else if (((((IN > 191) & (IN < 223))) & (IN != 215)) & (SETUP.EXTENDED_ASCII)) {\n TO_LOWER_result = (IN) | (0x20);\n } else {\n TO_LOWER_result = IN;\n }\n return TO_LOWER_result;\n}\n\n\nIECStringVar<2> TO_UML(IEC_BYTE IN) {\n IECStringVar<2> TO_UML_result;\n switch (IN) {\n case 196:\n TO_UML_result = \"Ae\";\n break;\n case 214:\n TO_UML_result = \"Oe\";\n break;\n case 220:\n TO_UML_result = \"Ue\";\n break;\n case 223:\n TO_UML_result = \"ss\";\n break;\n case 228:\n TO_UML_result = \"ae\";\n break;\n case 246:\n TO_UML_result = \"oe\";\n break;\n case 252:\n TO_UML_result = \"ue\";\n break;\n default:\n TO_UML_result = CHR_TO_STRING(IN);\n break;\n }\n return TO_UML_result;\n}\n\n\nIEC_BYTE TO_UPPER(IEC_BYTE IN) {\n IEC_BYTE TO_UPPER_result;\n if ((IN > 96) & (IN < 123)) {\n TO_UPPER_result = (IN) & (0xDF);\n } else if ((((IN > 223) & (IN != 247)) & (IN != 255)) & (SETUP.EXTENDED_ASCII)) {\n TO_UPPER_result = (IN) & (0xDF);\n } else {\n TO_UPPER_result = IN;\n }\n return TO_UPPER_result;\n}\n\n\nIEC_REAL TRIANGLE_A(IEC_REAL S1, IEC_REAL A, IEC_REAL S2, IEC_REAL S3) {\n IEC_REAL TRIANGLE_A_result;\n if (A == 0.0) {\n TRIANGLE_A_result = SQRT((S1 + S2 + S3) * (S1 + S2 - S3) * (S2 + S3 - S1) * (S3 + S1 - S2)) * 0.25;\n } else {\n TRIANGLE_A_result = S1 * S2 * SIN(RAD(A)) * 0.5;\n }\n return TRIANGLE_A_result;\n}\n\n\nIECStringVar TRIM(IECStringVar STR) {\n IECStringVar TRIM_result;\n IEC_INT POS;\n TRIM_result = STR;\n do {\n POS = FIND(TRIM_result, \" \");\n if (POS > 0) {\n TRIM_result = REPLACE(TRIM_result, \"\", 1, POS);\n }\n } while (!(POS == 0));\n return TRIM_result;\n}\n\n\nIECStringVar TRIM1(IECStringVar STR) {\n IECStringVar TRIM1_result;\n IEC_INT POS;\n TRIM1_result = STR;\n do {\n POS = FIND(TRIM1_result, \" \");\n if (POS > 0) {\n TRIM1_result = REPLACE(TRIM1_result, \" \", 2, POS);\n }\n } while (!(POS == 0));\n if (LEFT(TRIM1_result, 1) == \" \") {\n TRIM1_result = DELETE_STR(TRIM1_result, 1, 1);\n }\n if (RIGHT(TRIM1_result, 1) == \" \") {\n TRIM1_result = DELETE_STR(TRIM1_result, 1, LEN(TRIM1_result));\n }\n return TRIM1_result;\n}\n\n\nIECStringVar TRIME(IECStringVar STR) {\n IECStringVar TRIME_result;\n TRIME_result = STR;\n while (LEFT(TRIME_result, 1) == \" \") {\n TRIME_result = DELETE_STR(TRIME_result, 1, 1);\n }\n while (RIGHT(TRIME_result, 1) == \" \") {\n TRIME_result = DELETE_STR(TRIME_result, 1, LEN(TRIME_result));\n }\n return TRIME_result;\n}\n\n\nIEC_DWORD T_PLC_MS() {\n IEC_DWORD T_PLC_MS_result;\n IEC_BOOL DEBUG = 0;\n IEC_INT N = 0;\n IEC_DWORD OFFSET = 0;\n IEC_TIME TX;\n TX = TIME();\n T_PLC_MS_result = TO_DWORD(TX);\n if (DEBUG) {\n T_PLC_MS_result = ((SHL(T_PLC_MS_result, N)) | (SHL(static_cast(1), N) - 1)) + OFFSET;\n }\n return T_PLC_MS_result;\n}\n\n\nIEC_DWORD T_PLC_US() {\n IEC_DWORD T_PLC_US_result;\n IEC_BOOL DEBUG = 0;\n IEC_INT N = 0;\n IEC_DWORD OFFSET = 0;\n IEC_TIME TX;\n TX = TIME();\n T_PLC_US_result = TO_DWORD(TX) * 1000;\n if (DEBUG) {\n T_PLC_US_result = ((SHL(T_PLC_US_result, N)) | (SHL(static_cast(1), N) - 1)) + OFFSET;\n }\n return T_PLC_US_result;\n}\n\n\nIECStringVar UPPERCASE(IECStringVar STR) {\n IECStringVar UPPERCASE_result;\n IEC_Ptr PT;\n IEC_INT POS;\n IEC_INT L;\n PT = &(UPPERCASE_result);\n UPPERCASE_result = STR;\n L = LEN(STR);\n for (POS = 1; POS <= L; POS++) {\n (*PT) = TO_UPPER((*PT));\n PT = PT + 1;\n }\n return UPPERCASE_result;\n}\n\n\nIEC_DT UTC_TO_LTIME(IEC_DT UTC, IEC_BOOL DST_ENABLE, IEC_INT TIME_ZONE_OFFSET) {\n IEC_DT UTC_TO_LTIME_result;\n IEC_INT TMP;\n TMP = TIME_ZONE_OFFSET * 60 + TO_INT((DST_ENABLE) & (DST(UTC))) * 3600;\n if (TMP < 0) {\n TMP = ABS(TMP);\n UTC_TO_LTIME_result = TO_DT(TO_DWORD(UTC) - TO_DWORD(TMP));\n } else {\n UTC_TO_LTIME_result = TO_DT(TO_DWORD(UTC) + TO_DWORD(TMP));\n }\n return UTC_TO_LTIME_result;\n}\n\n\nIEC_REAL V3_ABS(VECTOR_3 A) {\n IEC_REAL V3_ABS_result;\n V3_ABS_result = SQRT(A.X * A.X + A.Y * A.Y + A.Z * A.Z);\n return V3_ABS_result;\n}\n\n\nVECTOR_3 V3_ADD(VECTOR_3 A, VECTOR_3 B) {\n VECTOR_3 V3_ADD_result;\n V3_ADD_result.X = A.X + B.X;\n V3_ADD_result.Y = A.Y + B.Y;\n V3_ADD_result.Z = A.Z + B.Z;\n return V3_ADD_result;\n}\n\n\nIEC_REAL V3_ANG(VECTOR_3 A, VECTOR_3 B) {\n IEC_REAL V3_ANG_result;\n IEC_REAL D;\n D = V3_ABS(A) * V3_ABS(B);\n if (D > 0) {\n V3_ANG_result = ACOS(LIMIT(-1.0, V3_DPRO(A, B) / D, 1.0));\n }\n return V3_ANG_result;\n}\n\n\nIEC_REAL V3_DPRO(VECTOR_3 A, VECTOR_3 B) {\n IEC_REAL V3_DPRO_result;\n V3_DPRO_result = A.X * B.X + A.Y * B.Y + A.Z * B.Z;\n return V3_DPRO_result;\n}\n\n\nVECTOR_3 V3_NORM(VECTOR_3 A) {\n VECTOR_3 V3_NORM_result;\n IEC_REAL LA;\n LA = V3_ABS(A);\n if (LA > 0.0) {\n V3_NORM_result = V3_SMUL(A, 1.0 / LA);\n }\n return V3_NORM_result;\n}\n\n\nIEC_BOOL V3_NUL(VECTOR_3 A) {\n IEC_BOOL V3_NUL_result;\n V3_NUL_result = ((A.X == 0.0) & (A.Y == 0.0)) & (A.Z == 0.0);\n return V3_NUL_result;\n}\n\n\nIEC_BOOL V3_PAR(VECTOR_3 A, VECTOR_3 B) {\n IEC_BOOL V3_PAR_result;\n V3_PAR_result = V3_ABS(V3_XPRO(A, B)) == 0.0;\n return V3_PAR_result;\n}\n\n\nVECTOR_3 V3_REV(VECTOR_3 A) {\n VECTOR_3 V3_REV_result;\n V3_REV_result.X = -A.X;\n V3_REV_result.Y = -A.Y;\n V3_REV_result.Z = -A.Z;\n return V3_REV_result;\n}\n\n\nVECTOR_3 V3_SMUL(VECTOR_3 A, IEC_REAL M) {\n VECTOR_3 V3_SMUL_result;\n V3_SMUL_result.X = A.X * M;\n V3_SMUL_result.Y = A.Y * M;\n V3_SMUL_result.Z = A.Z * M;\n return V3_SMUL_result;\n}\n\n\nVECTOR_3 V3_SUB(VECTOR_3 A, VECTOR_3 B) {\n VECTOR_3 V3_SUB_result;\n V3_SUB_result.X = A.X - B.X;\n V3_SUB_result.Y = A.Y - B.Y;\n V3_SUB_result.Z = A.Z - B.Z;\n return V3_SUB_result;\n}\n\n\nIEC_REAL V3_XANG(VECTOR_3 A) {\n IEC_REAL V3_XANG_result;\n IEC_REAL LA;\n LA = V3_ABS(A);\n if (LA > 0.0) {\n V3_XANG_result = ACOS(A.X / LA);\n }\n return V3_XANG_result;\n}\n\n\nVECTOR_3 V3_XPRO(VECTOR_3 A, VECTOR_3 B) {\n VECTOR_3 V3_XPRO_result;\n V3_XPRO_result.X = A.Y * B.Z - A.Z * B.Y;\n V3_XPRO_result.Y = A.Z * B.X - A.X * B.Z;\n V3_XPRO_result.Z = A.X * B.Y - A.Y * B.X;\n return V3_XPRO_result;\n}\n\n\nIEC_REAL V3_YANG(VECTOR_3 A) {\n IEC_REAL V3_YANG_result;\n IEC_REAL LA;\n LA = V3_ABS(A);\n if (LA > 0.0) {\n V3_YANG_result = ACOS(A.Y / LA);\n }\n return V3_YANG_result;\n}\n\n\nIEC_REAL V3_ZANG(VECTOR_3 A) {\n IEC_REAL V3_ZANG_result;\n IEC_REAL LA;\n LA = V3_ABS(A);\n if (LA > 0.0) {\n V3_ZANG_result = ACOS(A.Z / LA);\n }\n return V3_ZANG_result;\n}\n\n\nIECStringVar<10> WEEKDAY_TO_STRING(IEC_INT WDAY, IEC_INT LANG, IEC_INT LX) {\n IECStringVar<10> WEEKDAY_TO_STRING_result;\n IEC_INT LY;\n if (LANG == 0) {\n LY = LANGUAGE.DEFAULT;\n } else {\n LY = MIN(LANG, LANGUAGE.LMAX);\n }\n if ((WDAY < 1) | (WDAY > 7)) {\n return WEEKDAY_TO_STRING_result;\n } else if (LX == 0) {\n WEEKDAY_TO_STRING_result = LANGUAGE.WEEKDAYS(LY, WDAY);\n } else if (LX == 2) {\n WEEKDAY_TO_STRING_result = LANGUAGE.WEEKDAYS2(LY, WDAY);\n }\n return WEEKDAY_TO_STRING_result;\n}\n\n\nIEC_BOOL WINDOW(IEC_REAL LOW, IEC_REAL IN, IEC_REAL HIGH) {\n IEC_BOOL WINDOW_result;\n WINDOW_result = (IN < HIGH) & (IN > LOW);\n return WINDOW_result;\n}\n\n\nIEC_BOOL WINDOW2(IEC_REAL LOW, IEC_REAL IN, IEC_REAL HIGH) {\n IEC_BOOL WINDOW2_result;\n WINDOW2_result = (IN >= LOW) & (IN <= HIGH);\n return WINDOW2_result;\n}\n\n\nIEC_WORD WORD_OF_BYTE(IEC_BYTE B1, IEC_BYTE B0) {\n IEC_WORD WORD_OF_BYTE_result;\n WORD_OF_BYTE_result = (SHL(TO_WORD(B1), 8)) | (TO_WORD(B0));\n return WORD_OF_BYTE_result;\n}\n\n\nIEC_WORD WORD_OF_DWORD(IEC_DWORD IN, IEC_BYTE N) {\n IEC_WORD WORD_OF_DWORD_result;\n WORD_OF_DWORD_result = TO_WORD(SHR(IN, SHL(N, 4)));\n return WORD_OF_DWORD_result;\n}\n\n\nIEC_REAL WORD_TO_RANGE(IEC_WORD X, IEC_REAL LOW, IEC_REAL HIGH) {\n IEC_REAL WORD_TO_RANGE_result;\n WORD_TO_RANGE_result = (HIGH - LOW) * TO_REAL(X) * 0.0000152590218966964 + LOW;\n return WORD_TO_RANGE_result;\n}\n\n\nIEC_INT WORK_WEEK(IEC_DATE IDATE) {\n IEC_INT WORK_WEEK_result;\n IEC_DATE D1;\n IEC_INT W1;\n IEC_DWORD DS;\n IEC_INT YR;\n IEC_INT W31;\n IEC_INT W01;\n IEC_INT WM;\n YR = YEAR_OF_DATE(IDATE);\n D1 = YEAR_BEGIN(YR);\n W1 = DAY_OF_WEEK(D1);\n if (W1 < 5) {\n DS = TO_DWORD(D1) - TO_DWORD(W1 + 6) * 86400;\n } else {\n DS = TO_DWORD(D1) - TO_DWORD(W1 - 1) * 86400;\n }\n WORK_WEEK_result = TO_INT((TO_DWORD(IDATE) - DS) / 604800);\n if (WORK_WEEK_result == 0) {\n if (W1 > 1) {\n W31 = W1 - 1;\n } else {\n W31 = 7;\n }\n if ((LEAP_YEAR(YR - 1)) & (W31 > 1)) {\n W01 = W31 - 1;\n } else {\n W1 = 7;\n }\n WORK_WEEK_result = 52 + TO_INT((W31 == 4) | (W01 == 4));\n } else {\n if (LEAP_YEAR(YR)) {\n if (W1 < 7) {\n W31 = W1 + 1;\n } else {\n W31 = 1;\n }\n } else {\n W31 = W1;\n }\n WM = 52 + TO_INT((W31 == 4) | (W1 == 4));\n if (WORK_WEEK_result > WM) {\n WORK_WEEK_result = 1;\n }\n }\n return WORK_WEEK_result;\n}\n\n\nIEC_DATE YEAR_BEGIN(IEC_INT Y) {\n IEC_DATE YEAR_BEGIN_result;\n YEAR_BEGIN_result = TO_DATE(SHR(TO_DWORD(Y) * 1461 - 2878169, 2) * 86400);\n return YEAR_BEGIN_result;\n}\n\n\nIEC_DATE YEAR_END(IEC_INT Y) {\n IEC_DATE YEAR_END_result;\n YEAR_END_result = TO_DATE(SHR(TO_DWORD(Y) * 1461 - 2876712, 2) * 86400);\n return YEAR_END_result;\n}\n\n\nIEC_INT YEAR_OF_DATE(IEC_DATE IDATE) {\n IEC_INT YEAR_OF_DATE_result;\n YEAR_OF_DATE_result = TO_INT((TO_DWORD(IDATE) + 43200) / 31557600 + 1970);\n return YEAR_OF_DATE_result;\n}\n\n\nIEC_BOOL _ARRAY_ABS(IEC_Ptr> PT, IEC_UINT SIZE) {\n IEC_BOOL _ARRAY_ABS_result;\n IEC_UINT I;\n IEC_UINT STOP;\n STOP = SHR(SIZE, 2) - 1;\n for (I = 0; I <= STOP; I++) {\n (*PT)[I] = ABS((*PT)[I]);\n }\n _ARRAY_ABS_result = true;\n return _ARRAY_ABS_result;\n}\n\n\nIEC_BOOL _ARRAY_ADD(IEC_Ptr> PT, IEC_UINT SIZE, IEC_REAL X) {\n IEC_BOOL _ARRAY_ADD_result;\n IEC_UINT I;\n IEC_UINT STOP;\n STOP = SHR(SIZE, 2) - 1;\n for (I = 0; I <= STOP; I++) {\n (*PT)[I] = (*PT)[I] + X;\n }\n _ARRAY_ADD_result = true;\n return _ARRAY_ADD_result;\n}\n\n\nIEC_BOOL _ARRAY_INIT(IEC_Ptr> PT, IEC_UINT SIZE, IEC_REAL INIT) {\n IEC_BOOL _ARRAY_INIT_result;\n IEC_UINT I;\n IEC_UINT STOP;\n STOP = SHR(SIZE, 2) - 1;\n for (I = 0; I <= STOP; I++) {\n (*PT)[I] = INIT;\n }\n _ARRAY_INIT_result = true;\n return _ARRAY_INIT_result;\n}\n\n\nIEC_REAL _ARRAY_MEDIAN(IEC_Ptr> PT, IEC_UINT SIZE) {\n IEC_REAL _ARRAY_MEDIAN_result;\n IEC_UINT I;\n IEC_UINT STOP;\n _ARRAY_SORT(PT, SIZE);\n STOP = SHR(SIZE, 2) - 1;\n if (EVEN(static_cast(TO_INT(STOP)))) {\n _ARRAY_MEDIAN_result = (*PT)[SHR(STOP, 1)];\n } else {\n I = SHR(STOP, 1);\n _ARRAY_MEDIAN_result = ((*PT)[I] + (*PT)[I + 1]) * 0.5;\n }\n return _ARRAY_MEDIAN_result;\n}\n\n\nIEC_BOOL _ARRAY_MUL(IEC_Ptr> PT, IEC_UINT SIZE, IEC_REAL X) {\n IEC_BOOL _ARRAY_MUL_result;\n IEC_UINT I;\n IEC_UINT STOP;\n STOP = SHR(SIZE, 2) - 1;\n for (I = 0; I <= STOP; I++) {\n (*PT)[I] = (*PT)[I] * X;\n }\n _ARRAY_MUL_result = true;\n return _ARRAY_MUL_result;\n}\n\n\nIEC_BOOL _ARRAY_SHUFFLE(IEC_Ptr> PT, IEC_UINT SIZE) {\n IEC_BOOL _ARRAY_SHUFFLE_result;\n IEC_REAL TEMP;\n IEC_INT POS;\n IEC_INT I;\n IEC_INT STOP;\n STOP = TO_INT(SHR(SIZE, 2) - 1);\n for (I = 0; I <= STOP; I++) {\n POS = RDM2(I + POS, 0, STOP);\n TEMP = (*PT)[I];\n (*PT)[I] = (*PT)[POS];\n (*PT)[POS] = TEMP;\n }\n _ARRAY_SHUFFLE_result = true;\n return _ARRAY_SHUFFLE_result;\n}\n\n\nIEC_BOOL _ARRAY_SORT(IEC_Ptr> PT, IEC_UINT SIZE) {\n IEC_BOOL _ARRAY_SORT_result;\n IEC_UINT STACK_COUNT;\n Array1D STACK;\n IEC_UINT LINKS;\n IEC_UINT RECHTS;\n IEC_REAL PIVOT;\n IEC_UINT I;\n IEC_UINT J;\n IEC_BOOL ENDE_INNEN;\n IEC_BOOL ENDE_AUSSEN;\n IEC_REAL TMP;\n LINKS = 1;\n RECHTS = SHR(SIZE, 2);\n STACK_COUNT = 1;\n while (!ENDE_AUSSEN) {\n if (LINKS < RECHTS) {\n PIVOT = (*PT)[SHR(RECHTS + LINKS, 1)];\n I = LINKS - 1;\n J = RECHTS + 1;\n ENDE_INNEN = false;\n do {\n do {\n I = I + 1;\n } while (!((((*PT)[I] >= PIVOT)) | (NOT(I < RECHTS))));\n do {\n J = J - 1;\n } while (!((((*PT)[J] <= PIVOT)) | (NOT(J > LINKS))));\n if (I >= J) {\n ENDE_INNEN = true;\n } else {\n TMP = (*PT)[J];\n (*PT)[J] = (*PT)[I];\n (*PT)[I] = TMP;\n }\n } while (!(ENDE_INNEN));\n STACK[STACK_COUNT] = RECHTS;\n if (STACK_COUNT < 32) {\n STACK_COUNT = STACK_COUNT + 1;\n } else {\n ENDE_AUSSEN = true;\n _ARRAY_SORT_result = false;\n }\n RECHTS = MAX(LINKS, I - 1);\n } else {\n if (STACK_COUNT == 1) {\n ENDE_AUSSEN = true;\n } else {\n LINKS = RECHTS + 1;\n STACK_COUNT = STACK_COUNT - 1;\n RECHTS = STACK[STACK_COUNT];\n }\n }\n }\n _ARRAY_SORT_result = true;\n return _ARRAY_SORT_result;\n}\n\n\nIEC_BOOL _BUFFER_CLEAR(IEC_Ptr PT, IEC_UINT SIZE) {\n IEC_BOOL _BUFFER_CLEAR_result;\n IEC_Ptr PTW;\n IEC_DWORD TEMP;\n IEC_DWORD END;\n IEC_DWORD END32;\n TEMP = PT;\n END = TEMP + TO_DWORD(SIZE);\n END32 = END - 3;\n while (((PT < END)) & ((((TEMP) & (0x00000003)) > 0))) {\n (*PT) = 0;\n PT = PT + 1;\n TEMP = TEMP + 1;\n }\n PTW = PT;\n while (PTW < END32) {\n (*PTW) = 0;\n PTW = PTW + 4;\n }\n PT = PTW;\n while (PT < END) {\n (*PT) = 0;\n PT = PT + 1;\n }\n _BUFFER_CLEAR_result = true;\n return _BUFFER_CLEAR_result;\n}\n\n\nIEC_BOOL _BUFFER_INIT(IEC_Ptr PT, IEC_UINT SIZE, IEC_BYTE INIT) {\n IEC_BOOL _BUFFER_INIT_result;\n IEC_Ptr PTW;\n IEC_DWORD TEMP;\n IEC_DWORD END;\n IEC_DWORD END32;\n TEMP = PT;\n END = TEMP + TO_DWORD(SIZE);\n END32 = END - 3;\n while (((PT < END)) & ((((TEMP) & (0x00000003)) > 0))) {\n (*PT) = INIT;\n PT = PT + 1;\n TEMP = TEMP + 1;\n }\n PTW = PT;\n TEMP = (((SHL(TO_DWORD(INIT), 24)) | (SHL(TO_DWORD(INIT), 16))) | (SHL(TO_DWORD(INIT), 8))) | (TO_DWORD(INIT));\n while (PTW < END32) {\n (*PTW) = TEMP;\n PTW = PTW + 4;\n }\n PT = PTW;\n while (PT < END) {\n (*PT) = INIT;\n PT = PT + 1;\n }\n _BUFFER_INIT_result = true;\n return _BUFFER_INIT_result;\n}\n\n\nIEC_INT _BUFFER_INSERT(IECStringVar STR, IEC_INT POS, IEC_Ptr> PT, IEC_UINT SIZE) {\n IEC_INT _BUFFER_INSERT_result;\n IEC_INT END;\n IEC_INT LX;\n IEC_INT I;\n LX = LEN(STR);\n END = POS + LX;\n for (I = TO_INT(SIZE) - 1; I >= END; I += -1) {\n (*PT)[I] = (*PT)[I - LX];\n }\n _BUFFER_INSERT_result = _STRING_TO_BUFFER(STR, POS, PT, SIZE);\n return _BUFFER_INSERT_result;\n}\n\n\nIEC_BOOL _BUFFER_UPPERCASE(IEC_Ptr> PT, IEC_INT SIZE) {\n IEC_BOOL _BUFFER_UPPERCASE_result;\n IEC_INT POS;\n POS = 0;\n while (POS < SIZE) {\n (*PT)[POS] = TO_UPPER((*PT)[POS]);\n POS = POS + 1;\n }\n _BUFFER_UPPERCASE_result = true;\n return _BUFFER_UPPERCASE_result;\n}\n\n\nIEC_INT _STRING_TO_BUFFER(IECStringVar STR, IEC_INT POS, IEC_Ptr> PT, IEC_UINT SIZE) {\n IEC_INT _STRING_TO_BUFFER_result;\n IEC_Ptr PS;\n IEC_INT I;\n IEC_INT END;\n PS = &(STR);\n END = MIN(POS + LEN(STR), TO_INT(SIZE));\n if (END > 0) {\n END = END - 1;\n }\n for (I = POS; I <= END; I++) {\n (*PT)[I] = (*PS);\n PS = PS + 1;\n }\n _STRING_TO_BUFFER_result = I;\n return _STRING_TO_BUFFER_result;\n}\n", - "dependencies": [ - { - "name": "iec-standard-fb", - "version": "1.0.0" - } - ], - "sources": [ - { - "fileName": "ACOSH.st", - "source": "FUNCTION ACOSH : REAL\nVAR_INPUT\n\tX : REAL;\nEND_VAR\n\n\n(*\nversion 1.3\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the arcus cos hyperbolicus\n\n*)\n\nACOSH := LN(SQRT(X * X - 1.0) + X);\n\n(* revision history\nhm\t\t12 jan 2007\trev 1.0\n\toriginal version\n\nhm\t\t2. dec 2007\trev 1.1\n\tchanged code for better performance\n\nhm\t16. mar. 2007\t\trev 1.2\n\tchanged sequence of calculations to improve performance\n\nhm\t10. mar. 2009\t\trev 1.3\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "ACOTH.st", - "source": "FUNCTION ACOTH : REAL\nVAR_INPUT\n\tX : REAL;\nEND_VAR\n\n\n(*\nversion 1.2\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the arcus cotangens hyperbolicus\n\n*)\n\nACOTH := LN((x+1.0)/(x-1.0))*0.5;\n\n(* revision history\nhm\t\t12 jan 2007\trev 1.0\n\toriginal version\n\nhm\t\t5. jan 2008\trev 1.1\n\timproved code for better performance\n\nhm\t10. mar. 2009\t\trev 1.2\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "AGDF.st", - "source": "FUNCTION AGDF : REAL\nVAR_INPUT\n\tX : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the inverse Gudermannian function.\n\n*)\n\nAGDF := LN((1.0 + SIN(X)) / COS(X));\n\n(* comment\nthe current implementation gives sufficient accuracy only up to X = 1.57 or an output > 10.\nis X closer to PI/2 then the function is more and more unreliable\n*)\n\n\n\n(* revision history\nhm\t27. apr. 2008\trev 1.0\n\toriginal version\n\nhm\t10. mar. 2009\trev 1.1\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "AIN.st", - "source": "FUNCTION AIN : REAL\nVAR_INPUT\n\tin : DWORD;\nEND_VAR\nVAR_INPUT CONSTANT\n\tBits : BYTE;\n\tsign : BYTE := 255;\n\tlow : REAL;\n\thigh : REAL := 10.0;\nEND_VAR\nVAR CONSTANT\n\tff : DWORD := 16#FFFFFFFF;\nEND_VAR\nVAR\n\ttemp1 : DWORD;\n\ttemp2 : DWORD;\n\tsx : BOOL;\nEND_VAR\n\n(*\nversion 1.5\t16 mar 2008\nprogrammer \toscat\ntested by\t\ttobias\n\nAin converts signals from A/D converters or other digital sources to an internal real value\nthe lowest number of bits are extracted from the input word and the sign will be extracted if available separately.\nthe output signal is then conditioned to range from low to high values for a 0 to max value on the analog inputs:\nfor example a 15bit input (bits := 12) with sign at bit 15 (0..15) will deliver 0.0 (low value at 0) for an input value of 2#0000_0000_0000\nan input value of 2#1111_1111_1111 will deliver 10.0 on the output (high value set to 10).\n\n*)\n\n(* extract the sign bit *)\nIF sign < 32 THEN\n\ttemp1 := SHR(in,sign);\n\tsx := temp1.0;\nELSE\n\tsx := FALSE;\nEND_IF;\ntemp1 := SHR(ff, 32-bits);\ntemp2 := in AND temp1;\nAIN := (high - low) * DWORD_TO_REAL(temp2) / DWORD_TO_REAL(temp1) + low;\nIF sx THEN AIN := -AIN; END_IF;\n\n(* revision history\nhm 18.8.2006\trev 1.1\n\tfixed an error with low value negative and high value 0.\n\nhm 19.1.2007\trev 1.2\n\tfixed an error with sign bit.\n\nhm\t13.9.2007\trev 1.3\n\tchanged code to avoid warning under codesys 2.8.1\n\nhm\t2. dec 2007\trev 1.4\n\tchanged code for better performance\n\nhm\t16. mar 2008\trev 1.5\n\tadded type conversions to avoid warnings under codesys 30\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "AIN1.st", - "source": "FUNCTION_BLOCK AIN1\nVAR_INPUT\n\tin : DWORD;\nEND_VAR\nVAR_INPUT CONSTANT\n\tsign_bit : INT := 255;\n\terror_bit : INT := 255;\n\terror_code_en : BOOL;\n\terror_code : DWORD;\n\toverflow_bit : INT := 255;\n\toverflow_code_en : BOOL;\n\toverflow_code : DWORD;\n\tBit_0 : INT;\n\tBit_N : INT := 31;\n\tout_min : REAL;\n\tout_max : REAL := 10.0;\n\tcode_min : DWORD;\n\tcode_max : DWORD := 16#FFFFFFFF;\n\terror_output : REAL;\n\toverflow_output : REAL := 10.0;\nEND_VAR\nVAR_OUTPUT\n\tout : REAL;\n\tsign : BOOL;\n\terror : BOOL;\n\toverflow : BOOL;\nEND_VAR\nVAR\n\ttB: DWORD;\nEND_VAR\n\n(*\nversion 1.3\t10. mar. 2009\nprogrammer \toscat\ntested by\t\ttobias\n\nAin1 converts signals from A/D converters or other digital sources to an internal real value.\n\n*)\n\n(* extract error bit *)\nerror := ((SHR(in,error_bit) AND 16#0000_0001) = 1) OR (error_code_en AND error_code = in);\nIF error THEN\n\tout := error_output;\n\tRETURN;\nEND_IF;\n\n(* strip off the data input *)\ntb := SHR(SHL(in, 31 - bit_N), 31 - bit_N + Bit_0);\n\n(* extract overflow bit *)\noverflow := ((SHR(in,overflow_bit) AND 16#0000_0001) = 1) OR (overflow_code_en AND overflow_code = in) OR (tb < code_min OR tb > code_max);\nIF overflow THEN\n\tout := overflow_output;\n\tRETURN;\nEND_IF;\n\n(* extract sign bit *)\nsign := (SHR(in,sign_bit) AND 16#0000_0001) = 1;\n\n(* convert in to out *)\nout := (DWORD_TO_REAL(tb - code_min) * (out_max - out_min) / DWORD_TO_REAL(code_max - code_min) + out_min);\nIF sign THEN out := out * -1.0; END_IF;\n\n\n\n(* revision history\nhm\t23. feb 2008\trev 1.0\n\toriginal version\n\nhm\t16. mar 2008\trev 1.1\n\tadded type conversions to avoid warnngs under codesys 30\n\nhm\t22. apr. 2008\trev 1.2\n\tcorrected error in formula when code_min was set\n\tcorrected error when sign bit was used\n\toptimized code for better performance\n\nhm\t10. mar. 2009\trev 1.3\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "ALARM_2.st", - "source": "FUNCTION_BLOCK ALARM_2\nVAR_INPUT\n\tX : REAL;\n\tLO_1 : REAL;\n\tHI_1 : REAL;\n\tLO_2 : REAL;\n\tHI_2 : REAL;\n\tHYS : REAL;\nEND_VAR\nVAR_OUTPUT\n\tQ1_LO : BOOL;\n\tQ1_HI : BOOL;\n\tQ2_LO : BOOL;\n\tQ2_HI : BOOL;\nEND_VAR\nVAR\n\ttmp: REAL;\nEND_VAR\n\n(*\n\tversion 1.1\t11. mar. 2009\n\tprogrammer \thugo\n\ttested BY\t\ttobias\n\nALARM_2 will check two pairs of limits and signal when the input is above or below a set limit.\nwith the input HYS a hysteresis can be defined for all limits. \n\n*)\n\ntmp := X - Hys * 0.5;\nIF tmp > LO_1 THEN Q1_LO := FALSE; END_IF;\nIF tmp > LO_2 THEN Q2_LO := FALSE; END_IF;\nIF tmp > HI_1 THEN Q1_HI := TRUE; END_IF;\nIF tmp > HI_2 THEN Q2_HI := TRUE; END_IF;\ntmp := tmp + hys;\nIF tmp < LO_1 THEN Q1_LO := TRUE; END_IF;\nIF tmp < LO_2 THEN Q2_LO := TRUE; END_IF;\nIF tmp < HI_1 THEN Q1_HI := FALSE; END_IF;\nIF tmp < HI_2 THEN Q2_HI := FALSE; END_IF;\n\n\n\n(* revision history\nhm\t19. may. 2008\t\trev 1.0\n\toriginal version\n\nhm\t11. mar. 2009\trev 1.1\n\timproved code\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "AOUT.st", - "source": "FUNCTION AOUT : DWORD\nVAR_INPUT\n\tin : REAL;\nEND_VAR\nVAR_INPUT CONSTANT\n\tBits : BYTE;\n\tsign : BYTE := 255;\n\tlow : REAL;\n\thigh : REAL := 10.0;\nEND_VAR\nVAR CONSTANT\n\tff : DWORD := 2#1;\nEND_VAR\nVAR\n\tin2 : REAL;\n\tsx : BOOL;\nEND_VAR\n\n(*\nversion 1.4\t23 feb 2008\nprogrammer \toscat\ntested by\t\ttobias\n\nthis module conditions an internal real value for D/A converter.\nAout converts and internal real value to a word for an D/A converter or other output devices.\nThe input value is converted to a n-bit wide output and a sign bit is set separately as specified.\nthe outout min value is set for the specified min input value and the max output is set for the max input value.\nan input higher or lower then the max or min value will set the respective max or min value or the output.\n\n\n*)\n\n(* if sign bit is defined *)\nIF sign < 32 THEN\n\tsx := sign_R(in);\n\tin2 := ABS(in);\nELSE\n\tin2 := in;\nEND_IF;\n\n(* begrenze in auf die zulässigen werte *)\nin2 := LIMIT(low, in2, high);\n\n(* Berechne den Ausgangswert *)\nAout := REAL_TO_DWORD((in2 - low) / (high - low) * DWORD_TO_REAL(SHL(ff,bits) -1));\nIF sx THEN Aout := SHL(ff,sign) OR Aout; END_IF;\n\n(*\nrevision history\n\nhm 18.1.2007\t\trev 1.1\n\trenamed Modul to aout.\n\tchanged Output to 32 Bit max.\n\tcorrected error with sign bit.\n\nhm\t13.9.2007\t\trev 1.2\n\tchanged code to avoid warning under codesys 2.8.1\n\nhm\t2. dec 2007\t\trev 1.3\n\tchanged code for better performance\n\nhm\t23. feb 2008\trev 1.4\n\tchanged code for better performance\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "AOUT1.st", - "source": "FUNCTION AOUT1 : DWORD\nVAR_INPUT\n\tin : REAL;\nEND_VAR\nVAR_INPUT CONSTANT\n\tBit_0 : INT;\n\tBit_N : INT := 31;\n\tsign : INT := 255;\n\tlow : REAL;\n\thigh : REAL := 10.0;\nEND_VAR\nVAR CONSTANT\n\tff : DWORD := 2#1;\nEND_VAR\nVAR\n\tsx: BOOL;\n\tin2 : REAL;\nEND_VAR\n\n(*\nversion 1.0\t23 feb 2008\nprogrammer \toscat\ntested by\t\ttobias\n\nthis module conditions an internal real value for a D/A converter.\n\n*)\n\n(* if sign bit is defined *)\nIF sign < 32 THEN\n\tsx := SIGN_R(in);\n\tin2 := ABS(in);\nELSE\n\tin2 := in;\nEND_IF;\n\n(* begrenze in auf die zulässigen werte *)\nin2 := LIMIT(low, in2, high);\n\n(* Berechne den Ausgangswert *)\nAOUT1 := SHL(REAL_TO_DWORD((in2 - low) / (high - low) * DWORD_TO_REAL(SHL(ff,bit_n - Bit_0 + 1) -1)),Bit_0);\nIF sx THEN AOUT1 := SHL(ff,sign) OR AOUT1; END_IF;\n\n\n(* revision history\nhm\t23. feb 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "ARRAY_AVG.st", - "source": "FUNCTION ARRAY_AVG : REAL\nVAR_INPUT\n\tpt : POINTER TO ARRAY[0..32000] OF REAL;\n\tsize : UINT;\nEND_VAR\nVAR\n\ti: UINT;\n\tstop: UINT;\nEND_VAR\n\n(*\nversion 1.3\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function will calculate the average of a given array.\nthe function needs to be called:\tarray_avg(adr(\"array\"),sizeof(\"array\"));\nbecause this function works with pointers its very time efficient and it needs no extra memory.\n\n*)\n\nstop := SHR(size,2)-1;\nARRAY_AVG := pt^[0];\nFOR i := 1 TO stop DO\n\tARRAY_AVG := ARRAY_AVG + pt^[i];\nEND_FOR;\nARRAY_AVG := ARRAY_AVG / UINT_TO_REAL(stop + 1);\n\n\n(* revision history\nhm\t2. oct 2007\t\trev 1.0\n\toriginal version\n\nhm\t12. dec 2007\trev 1.1\n\tchaged code for better performance\n\nhm\t16. mar. 2008\trev 1.2\n\tchanged input size to uint\n\nhm\t10. mar. 2009\trev 1.3\n\tadded type conversion for compatibility reasons\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "ARRAY_GAV.st", - "source": "FUNCTION ARRAY_GAV : REAL\nVAR_INPUT\n\tpt : POINTER TO ARRAY[0..32000] OF REAL;\n\tsize : UINT;\nEND_VAR\nVAR\n\ti: UINT;\n\tstop: UINT;\nEND_VAR\n\n(*\nversion 1.1\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function will calculate the geometric average of a given array.\nthe function needs to be called:\tarray_avg(adr(\"array\"),sizeof(\"array\"));\nbecause this function works with pointers its very time efficient and it needs no extra memory.\n\n*)\n\nstop := SHR(size,2)-1;\nARRAY_GAV := 1.0;\nFOR i := 0 TO stop DO\n\tIF pt^[i] > 0.0 THEN\n\t\tARRAY_GAV := ARRAY_GAV * pt^[i];\n\tELSE\n\t\tARRAY_GAV := 0.0;\n\t\tRETURN;\n\tEND_IF;\nEND_FOR;\nARRAY_GAV := SQRTN(ARRAY_GAV,UINT_TO_INT(stop)+1);\n\n\n(* revision history\nhm\t2. apr 2008\trev 1.0\n\toriginal version\n\nhm\t10. mar. 2009\trev 1.1\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "ARRAY_HAV.st", - "source": "FUNCTION ARRAY_HAV : REAL\nVAR_INPUT\n\tpt : POINTER TO ARRAY[0..32000] OF REAL;\n\tsize : UINT;\nEND_VAR\nVAR\n\ti: UINT;\n\tstop: UINT;\nEND_VAR\n\n(*\nversion 1.1\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function will calculate the harmonic average of a given array.\nthe function needs to be called:\tarray_avg(adr(\"array\"),sizeof(\"array\"));\nbecause this function works with pointers its very time efficient and it needs no extra memory.\n\n*)\n\nstop := SHR(size,2)-1;\nFOR i := 0 TO stop DO\n\tIF pt^[i] <> 0.0 THEN\n\t\tARRAY_HAV := ARRAY_HAV + 1.0 / pt^[i];\n\tELSE\n\t\tARRAY_HAV := 0.0;\n\t\tRETURN;\n\tEND_IF;\nEND_FOR;\nARRAY_HAV := UINT_TO_REAL(stop + 1) / ARRAY_HAV;\n\n\n(* revision history\nhm\t2. apr 2008\trev 1.0\n\toriginal version\n\nhm\t10. mar. 2009\trev 1.1\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "ARRAY_MAX.st", - "source": "FUNCTION ARRAY_MAX : REAL\nVAR_INPUT\n\tpt : POINTER TO ARRAY[0..32000] OF REAL;\n\tsize : UINT;\nEND_VAR\nVAR\n\ti: UINT;\n\tstop: UINT;\nEND_VAR\n\n(*\nversion 1.1\t16. mar. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function will calculate the max value of a given array.\nthe function needs to be called:\tarray_max(adr(\"array\"),sizeof(\"array\"));\nbecause this function works with pointers its very time efficient and it needs no extra memory.\n\n*)\n\nstop := (size -SIZEOF(pt)) / SIZEOF(pt);\narray_max := pt^[0];\nFOR i := 1 TO stop DO\n\tIF pt^[i] > array_max THEN array_max := pt^[i]; END_IF;\nEND_FOR;\n\n(* revision history\nhm\t2. oct 2006\t\trev 1.0\n\toriginal version\n\nhm\t16. mar. 2008\trev 1.1\n\tchanged input size to uint\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "ARRAY_MIN.st", - "source": "FUNCTION ARRAY_MIN : REAL\nVAR_INPUT\n\tpt : POINTER TO ARRAY[0..32000] OF REAL;\n\tsize : UINT;\nEND_VAR\nVAR\n\ti: UINT;\n\tstop: UINT;\nEND_VAR\n\n(*\nversion 1.1\t16. mar. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function will calculate the min value of a given array.\nthe function needs to be called:\tarray_min(adr(\"array\"),sizeof(\"array\"));\nbecause this function works with pointers its very time efficient and it needs no extra memory.\n\n*)\n\nstop := (size - SIZEOF(pt)) / SIZEOF(pt);\narray_min := pt^[0];\nFOR i := 1 TO stop DO\n\tIF pt^[i] < array_min THEN array_min := pt^[i]; END_IF;\nEND_FOR;\n\n\n(* revision history\nhm\t\t2. oct. 2006\n\toriginal version\n\nhm\t\t16. mar. 2008\n\tchanged type of input size to uint\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "ARRAY_SDV.st", - "source": "FUNCTION ARRAY_SDV : REAL\nVAR_INPUT\n\tpt : POINTER TO ARRAY[0..32000] OF REAL;\n\tsize : UINT;\nEND_VAR\n\n\n(*\nversion 1.1\t16. mar 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function will calculate the standard deviation of a given array.\nthe function needs to be called:\tarray_sdv(adr(\"array\"),sizeof(\"array\"));\nbecause this function works with pointers its very time efficient and it needs no extra memory.\n\n*)\n\n(* standard deviation is simply the square root of the variance *)\n\narray_sdv := SQRT(array_var(pt, size));\n\n(* revision history\nhm \t1.4.2007\t\trev 1.0\n\tfunction created\n\nhm\t16. mar. 2008\trev 1.1\n\tchanged type of input size to uint\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "ARRAY_SPR.st", - "source": "FUNCTION ARRAY_SPR : REAL\nVAR_INPUT\n\tpt : POINTER TO ARRAY[0..32000] OF REAL;\n\tsize : UINT;\nEND_VAR\nVAR\n\ti: UINT;\n\tstop: UINT;\n\tarray_max : REAL;\n\tarray_min : REAL;\nEND_VAR\n\n(*\nversion 1.1\t16. mar. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function will calculate the spread of a given array.\nthe function needs to be called:\tarray_spr(adr(\"array\"),sizeof(\"array\"));\nfor example: spread of [12,0,4,1,7] is 12 - 0 = 12.\nbecause this function works with pointers its very time efficient and it needs no extra memory.\n\n*)\n\nstop := (size -SIZEOF(pt)) / SIZEOF(pt);\narray_min := pt^[0];\narray_max := pt^[0];\nFOR i := 1 TO stop DO\n\tIF pt^[i] > array_max THEN array_max := pt^[i];\n\tELSIF pt^[i] < array_min THEN array_min := pt^[i];\n\tEND_IF;\nEND_FOR;\narray_spr := array_max - array_min;\n\n\n(* revision history\nhm \t2. oct. 2006\trev 1.0\n\toriginal version\n\nhm\t16. mar. 2008\trev 1.1\n\tchanged type of input size to uint\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "ARRAY_SUM.st", - "source": "FUNCTION ARRAY_SUM : REAL\nVAR_INPUT\n\tpt : POINTER TO ARRAY[0..32000] OF REAL;\n\tsize : UINT;\nEND_VAR\nVAR\n\ti: UINT;\n\tstop: UINT;\nEND_VAR\n\n\n(*\nversion 1.1\t16. mar. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function will calculate the sum of a given array.\nthe function needs to be called:\tarray_sum(adr(\"array\"),sizeof(\"array\"));\nbecause this function works with pointers its very time efficient and it needs no extra memory.\n\n*)\n\nstop := (size -SIZEOF(pt)) / SIZEOF(pt);\narray_sum := pt^[0];\nFOR i := 1 TO stop DO\n\tarray_sum := array_sum + pt^[i];\nEND_FOR;\n\n(* revision history\nhm \t2. oct. 2006\trev 1.0\n\tfunction created\n\nhm\t16. mar. 2008\trev 1.1\n\tchanged type of input size to uint\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "ARRAY_TREND.st", - "source": "FUNCTION ARRAY_TREND : REAL\nVAR_INPUT\n\tpt : POINTER TO ARRAY[0..32000] OF REAL;\n\tsize : UINT;\nEND_VAR\nVAR\n\ti: UINT;\n\tstop: UINT;\n\tx: REAL;\n\tstop2: UINT;\nEND_VAR\n\n(*\nversion 1.3\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function will calculate the trend of a given array.\ntrend will calculate the avg of the first half of the array and then the avg of the second half, trend = avg2 - avg1.\nfor example: [0,1,4,5,3,4,6,3] = 4 - 2.5 = 1.5\nthe function needs to be called:\tarray_trend(adr(\"array\"),sizeof(\"array\"));\nbecause this function works with pointers its very time efficient and it needs no extra memory.\n\n*)\n\nstop := SHR(size,2)-1;\nstop2 := SHR(stop,1);\nFOR i := 0 TO stop2 DO x := x - pt^[i]; END_FOR;\nIF EVEN(UINT_TO_INT(stop)) THEN\n\tFOR i := stop2 TO stop DO X := X + pt^[i]; END_FOR;\nELSE\n\tFOR i := stop2 + 1 TO stop DO X := X + pt^[i]; END_FOR;\nEND_IF;\nARRAY_TREND := x / UINT_TO_REAL(stop2 + 1);\n\n(* revision history\nhm\t2 oct 2007\trev 1.0\n\toriginal version\n\nhm\t12 dec 2007\trev 1.1\n\tchanged code for better performance\n\nhm\t16. mar. 2008\trev 1.2\n\tchanged type of input size to uint\n\nhm\t10. mar. 2009\trev 1.3\n\tadded type conversions for compatibility reasons\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "ARRAY_VAR.st", - "source": "FUNCTION ARRAY_VAR : REAL\nVAR_INPUT\n\tpt : POINTER TO ARRAY[0..32000] OF REAL;\n\tsize : UINT;\nEND_VAR\nVAR\n\tavg : REAL;\n\ti: UINT;\n\tstop: UINT;\nEND_VAR\n\n(*\nversion 1.3\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function will calculate the variance of a given array.\nthe function needs to be called:\tarray_var(adr(\"array\"),sizeof(\"array\"));\nbecause this function works with pointers its very time efficient and it needs no extra memory.\n\n*)\n\n(* at first we calualte the arithmetic average of the array *)\n\nstop := SHR(size,2)-1;\navg := pt^[0];\nFOR i := 1 TO stop DO\n\tavg := avg + pt^[i];\nEND_FOR;\navg := avg / UINT_TO_REAL(stop + 1);\n\n(* in a second run we calculate the variance of the array *)\n\narray_var := (pt^[0] - avg) * (pt^[0] - avg);\nFOR i := 1 TO stop DO\n\tarray_var := array_var + (pt^[i] - avg) * (pt^[i] - avg);\nEND_FOR;\nARRAY_VAR := ARRAY_VAR / UINT_TO_REAL(stop);\n\n(* revision history\nhm \t1.4.2007\trev 1.0\n\tfunction created\n\nhm\t12.12.2007\trev 1.1\n\tchanged code for better performance\n\nhm\t16. mar. 2008\trev 1.2\n\tchanged type of input size to uint\n\nhm\t10. mar. 2009\trev 1.3\n\tadded type conversions for compatibility reasons\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "ASINH.st", - "source": "FUNCTION ASINH : REAL\nVAR_INPUT\n\tX : REAL;\nEND_VAR\n\n\n(*\nversion 1.3\t10. mar 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the arcus sin hyperbolicus\n\n*)\n\nASINH := LN(SQRT(X * X + 1.0)+X);\n\n(* revision history\nhm\t\t12 jan 2007\trev 1.0\n\toriginal version\n\nhm\t\t2. dec 2007\trev 1.1\n\tchanged code for better performance\n\nhm\t\t16.3. 2007\t\trev 1.2\n\tchanged sequence of calculations to improve performance\n\nhm\t10. mar. 2009\t\trev 1.3\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "ASTRO.st", - "source": "FUNCTION_BLOCK ASTRO\nVAR_INPUT\n\tm : REAL;\n\tAE : REAL;\n\tPC : REAL;\n\tLJ : REAL;\nEND_VAR\nVAR_OUTPUT\n\tYm : REAL;\n\tYAE : REAL;\n\tYPC : REAL;\n\tYLJ : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t11. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nthis function converts different length units\nany unused input can simply be left open.\ndifferent inputs connected at the same time will be added up.\n\n*)\n\nYAE :=\tAE\n\t\t+ m * 6.6845871535E-012\n\t\t+ PC * 206265.0\n\t\t+ LJ * 63240.0;\nYm := YAE * 149.597870E9;\nYPC := YAE * 4.8481322570E-006;\nYLJ := YAE * 1.5812776724E-005;\n\n\n(*\nLänge Meter m SI-Basiseinheit\nAstronomische Einheit* AE 1 AE = 149,597 870 · E9 m\nParsec pc 1 pc = 206265 AE = 30,857 · E15 m\nLichtjahr Lj 1 Lj = 9,460 530 · E15 m = 63240 AE = 0,306 59 pc\nÅngström Å 1 Å = E–l0 m\ntypograph. Punkt p 1 p = 0,376 065 mm • im Druckereigewerbe\ninch** in 1 in = 2,54 · E–2 m = 25,4 mm***\nfoot ft 1 ft = 0,3048 m = 30,48 cm\nyard yd 1 yd = 0,9144 m\nmile mile 1 mile = 1609,344 m\nInternat. Seemeile sm 1 sm = 1852 m\nFathom fm 1 fm = 1,829 m • in der Seeschifffahrt\n*)\n\n(* revision history\n\nhm\t27. mar. 2007\trev 1.0\n\toriginal version\n\nhm\t11. mar. 2009\trev 1.1\n\timproved code\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "ATAN2.st", - "source": "FUNCTION ATAN2 : REAL\nVAR_INPUT\n\tY : REAL;\n\tX : REAL;\nEND_VAR\n\n\n(*\nversion 1.2\t10. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nthis function calculates the angle in a coordinate system in rad.\n\n*)\n\nIF X > 0.0 THEN\n\tATAN2 := ATAN(Y/X);\nELSIF X < 0.0 THEN\n\tIF Y >=0.0 THEN\n\t\tATAN2 := ATAN(Y/X) + MATH.PI;\n\tELSE\n\t\tATAN2 := ATAN(Y/X) - MATH.PI;\n\tEND_IF;\nELSIF Y > 0.0 THEN\n\tATAN2 := MATH.PI05;\nELSIF Y < 0.0 THEN\n\tATAN2 := -MATH.PI05;\nELSE\n\tATAN2 := 0.0;\nEND_IF;\n\n\n(* revision history\nhm\t20. apr. 2008\trev 1.0\n\toriginal version\n\nhm\t18. oct. 2008\trev 1.1\n\tchanged to use math constants\n\nhm\t10. mar. 2009\trev 1.2\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "ATANH.st", - "source": "FUNCTION ATANH : REAL\nVAR_INPUT\n\tX : REAL;\nEND_VAR\n\n\n(*\nversion 1.2\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the arcus tangens hyperbolicus\n\n*)\n\nATANH := LN((1.0 + x)/(1.0 - x)) * 0.5;\n\n\n(* revision history\nhm\t\t12 jan 2007\trev 1.0\n\toriginal version\n\nhm\t\t5. jan 2008\trev 1.1\n\timproved code for better performance\n\nhm\t10. mar. 2009\t\trev 1.2\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "A_TRIG.st", - "source": "FUNCTION_BLOCK A_TRIG\nVAR_INPUT\n\tIN : REAL;\n\tRES : REAL;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\n\tD : REAL;\nEND_VAR\nVAR\n\tlast_in : REAL;\nEND_VAR\n\n(*\nversion 1.1\t25. oct. 2008\nprogrammer \thugo\ntested by\toscat\n\nthis block is similar to the IEC Standard R_trig and F_trig but it monitors a REAL for change.\nif the valiue on IN changes more then D from the last value it will generate trigger and display the difference in output D.\nthe trigger will only be active for one cycle.\n\n*)\n\nD := IN - LAST_IN;\nQ := ABS(D) > res;\nIF Q THEN last_in := IN; END_IF;\nD := IN - LAST_IN;\n\n\n(* revision history\n\nhm \t16. jul. 2008\trev 1.0\n\toriginal version released\n\nhm\t25. oct. 2008\trev 1.1\n\tcode optimization\n\ta_trig now also works for res = 0\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "BAND_B.st", - "source": "FUNCTION BAND_B : BYTE\nVAR_INPUT\n\tX : BYTE;\n\tB : BYTE;\nEND_VAR\n\n\n\n(*\nversion 1.0\t21. Nov. 2008\nprogrammer \thugo\ntested by\toscat\n\nBAND_B will limit X to B <= X <= 255-B. while X < B the resulkt will be 0 and while X > 255-B the output will be 255\notherwise the result = X.\n\n*)\n\nIF X < B THEN\n\tBAND_B := 0;\nELSIF X > BYTE#255-B THEN\n\tBAND_B := 255;\nELSE\n\tBAND_B := X;\nEND_IF;\n\n\n\n(* revision history\nhm\t21. nov. 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "BAR_GRAPH.st", - "source": "FUNCTION_BLOCK BAR_GRAPH\nVAR_INPUT\n\tX : REAL;\n\trst : BOOL;\nEND_VAR\nVAR_INPUT CONSTANT\n\ttrigger_Low : REAL;\n\ttrigger_High : REAL;\n\tAlarm_low : BOOL;\n\tAlarm_high : BOOL;\n\tlog_scale : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tLOW, Q1, Q2, Q3, Q4, Q5, Q6, HIGH : BOOL;\n\tAlarm : BOOL;\n\tStatus : BYTE;\nEND_VAR\nVAR\n\tinit : BOOL;\n\tT1, T2, T3, T4, T5 : REAL;\nEND_VAR\nVAR_TEMP\n\ttemp : REAL;\nEND_VAR\n\n(*\n\tversion 1.2\t6 jan 2008\n\tprogrammer \thugo\n\ttested BY\thans\n\nbar graph is a muti window comparator which displays an analog input signal on 8 digital outputs.\nonly one output is active a any given time depending on the value of the input signal.\nthe output can be of linear or logarithmic scale.\n\n*)\n\nIF NOT init THEN\n\tinit := TRUE;\n\tIF log_scale THEN\n\t\ttemp := EXP(LN(Trigger_high / Trigger_low) * 0.166666666666666666666);\n\t\tT1 := trigger_low * temp;\n\t\tT2 := T1 * temp;\n\t\tT3 := T2 * temp;\n\t\tT4 := T3 * temp;\n\t\tT5 := T4 * temp;\n\tELSE\n\t\ttemp := (trigger_high - trigger_low) * 0.142857142;\n\t\tT1 := trigger_low + temp;\n\t\tT2 := T1 + temp;\n\t\tT3 := T2 + temp;\n\t\tT4 := T3 + temp;\n\t\tT5 := T4 + temp;\n\tEND_IF;\nEND_IF;\n\n(* clear outputs before checking *)\nQ1 := FALSE;\nQ2 := FALSE;\nQ3 := FALSE;\nQ4 := FALSE;\nQ5 := FALSE;\nQ6 := FALSE;\nstatus := 110;\n\n(* low, high and alarm can only be cleared with rst depending on alarm_low and alarm_high *)\nIF NOT alarm_low THEN low := FALSE; END_IF;\nIF NOT alarm_high THEN high := FALSE; END_IF;\nIF rst THEN\n\talarm := FALSE;\n\tlow := FALSE;\n\thigh := FALSE;\nEND_IF;\n\n(* check and set outputs *)\nIF X < trigger_low THEN\n\tLow := TRUE;\n\tstatus := 111;\n\tIF alarm_low THEN\n\t\talarm := TRUE;\n\t\tstatus := 1;\n\tEND_IF;\nELSIF X < T1 THEN\n\tQ1 := TRUE;\nELSIF x < t2 THEN\n\tQ2 := TRUE;\nELSIF x < t3 THEN\n\tQ3 := TRUE;\nELSIF x < T4 THEN\n\tQ4 := TRUE;\nELSIF x < T5 THEN\n\tq5 := TRUE;\nELSIF x < trigger_high THEN\n\tq6 := TRUE;\nELSE\n\thigh := TRUE;\n\tstatus := 112;\n\tIF alarm_high THEN\n\t\talarm := TRUE;\n\t\tstatus := 2;\n\tEND_IF;\nEND_IF;\n\n(* revision history\nhm\t22. feb 2007\trev 1.0\n\toriginal version\n\nhm\t2. dec 2007\t\trev 1.1\n\tchaged code for better performance\n\nhm\t6. jan 2008\t\trev 1.2\n\tfurther performance improvement\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "BCDC_TO_INT.st", - "source": "FUNCTION BCDC_TO_INT : INT\nVAR_INPUT\n\tIN : BYTE;\nEND_VAR\n\n\n(*\nversion 1.1 30. jun. 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function converts a two digit bcd number into an integer.\n\n*)\n\nBCDC_TO_INT := (in AND 16#0F) + (SHR(in,4) * 10);\n\n(* revision history\nhm\t13.12.2007\trev 1.0\n\toriginal version\n\nhm\t30.6.2008\trev 1.1\n\tchanged name BCD_TO_INT to BCDC_TO_INT to avoid collision with util.lib\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "BETA.st", - "source": "FUNCTION BETA : REAL\nVAR_INPUT\n\tX : REAL;\n\tY : REAL;\nEND_VAR\n\n\n(*\nversion 1.0\t26. oct. 2008\nprogrammer \thugo\ntested by\t\toscat\n\nthis function calculates the beta function for real number > 0.\n\n*)\n\nBETA := GAMMA(X) * GAMMA(Y) / GAMMA(x + y);\n\n\n(* revision history\nhm\t26. oct. 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "BFT_TO_MS.st", - "source": "FUNCTION BFT_TO_MS : REAL\nVAR_INPUT\n\tBFT : INT;\nEND_VAR\n\n\n(*\nversion 1.0\t12. jun 2008\nprogrammer \thugo\ntested by\t\toscdat\n\nthis function converts wind speed from beaufort to m/s\n*)\n\nBFT_TO_MS := EXPT(BFT, 1.5) * 0.836;\n\n\n(* revision history\nhm\t12. 6. 2008\t\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "BINOM.st", - "source": "FUNCTION BINOM : DINT\nVAR_INPUT\n\tN : INT;\n\tK : INT;\nEND_VAR\n\nVAR\n\ti: INT;\nEND_VAR\n\n\n(*\nversion 1.0\t25. oct. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the binomialkoefficient (N over k)\n\n*)\n\nIF 2 * K > n THEN\n\tk := n - k;\nEND_IF;\nIF k > n THEN\n\tRETURN;\nELSIF k = 0 OR k = n THEN\n\tBINOM := 1;\nELSIF k = 1 THEN\n\tBINOM := n;\nELSE\n\tBINOM := n;\n\tn := n + 1;\n\tFOR i := 2 TO k DO\n\t\tBINOM := BINOM * (n - i) / i;\n\tEND_FOR;\nEND_IF;\n\n\n\n(*\nbinomialkoeffizient(n, k)\n1 wenn k = 0 return 1\n2 wenn 2k > n\n3 dann führe aus ergebnis \\leftarrow binomialkoeffizient(n, n-k)\n4 sonst führe aus ergebnis \\leftarrow n\n5 von i \\leftarrow 2 bis k\n6 führe aus ergebnis \\leftarrow ergebnis \\cdot (n + 1 - i)\n7 ergebnis \\leftarrow ergebnis : i\n8 return ergebnis\n*)\n\n\n\n(* revision history\nhm\t25. oct. 2008\trev 1.0\n\toriginal version\n\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "BIN_TO_BYTE.st", - "source": "FUNCTION BIN_TO_BYTE : BYTE\nVAR_INPUT\n\tBIN : STRING(12);\nEND_VAR\nVAR\n\tpt : POINTER TO BYTE;\n\ti: INT;\n\tX: BYTE;\n\tstop: INT;\nEND_VAR\n\n(*\nversion 1.2\t26. jul 2009\nprogrammer \thugo\ntested by\t\toscat\n\nBINARY_TO_byte converts a binary string into a byte.\n\n*)\n\npt := ADR(bin);\nstop := LEN(bin);\nFOR I := 1 TO stop DO\n\tx := pt^;\n\t(* calculate the value of the digit *)\n\tIF X = 48 THEN\n\t\tBIN_TO_BYTE := SHL(BIN_TO_BYTE,1);\n\tELSIF X = 49 THEN\n\t\tBIN_TO_BYTE := SHL(BIN_TO_BYTE,1) OR 1;\n\tEND_IF;\n\tpt := pt + 1;\nEND_FOR;\n\n\n\n(* revision histroy\nhm\t18. jun. 2008\trev 1.0\n\toriginal release\n\nhm\t20. sep. 2008\trev 1.1\n\tchanged length of input string from 20 to 12\n\nhm\t26. jul. 2009\trev 1.2\n\toptimized code\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "BIN_TO_DWORD.st", - "source": "FUNCTION BIN_TO_DWORD : DWORD\nVAR_INPUT\n\tBIN : STRING(40);\nEND_VAR\nVAR\n\tpt : POINTER TO BYTE;\n\ti: INT;\n\tX: BYTE;\n\tstop: INT;\nEND_VAR\n\n(*\nversion 1.2\t26. jul. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nBINARY_TO_DWORD converts a binary string into a dword.\n\n*)\n\npt := ADR(bin);\nstop := LEN(bin);\nFOR I := 1 TO stop DO\n\tx := pt^;\n\t(* calculate the value of the digit *)\n\tIF X = 48 THEN\n\t\tBIN_TO_DWORD := SHL(BIN_TO_DWORD,1);\n\tELSIF X = 49 THEN\n\t\tBIN_TO_DWORD := SHL(BIN_TO_DWORD,1) OR 1;\n\tEND_IF;\n\tpt := pt + 1;\nEND_FOR;\n\n\n\n(* revision histroy\nhm\t18. jun. 2008\trev 1.0\n\toriginal release\n\nhm\t20. sep. 2008\trev 1.1\n\tchanged length of input dtring from 20 to 40\n\nhm\t26. jul 2009\trev 1.2\n\toptimized code\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "BIT_COUNT.st", - "source": "FUNCTION BIT_COUNT : INT\nVAR_INPUT\n\tIN : DWORD;\nEND_VAR\n\n\n(*\nversion 1.1\t10 sep 2007\nprogrammer \thugo\ntested by\t\ttobias\n\nBIT_COUNT counts the amount True of bits in a dword.\nfor exabple: bit_count(3) returns 2 because two bits (bits 0 and 1) are true and all others are false. \n\n*)\n\nWHILE in > 0 DO\n\tIF in.0 THEN Bit_Count := Bit_Count + 1; END_IF;\n\tin := SHR(in,1);\nEND_WHILE;\n\n\n\n(* revision history\n5.7.2007\trev 1.0\t\toriginal version\n\n10.9.2007\trev 1.1\t\thm\n\tchanged algorithm for better performace\n\tthe execution time has reduced by a factor of 5\n\tdeleted unused variable temp\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "BIT_LOAD_B.st", - "source": "FUNCTION BIT_LOAD_B : BYTE\nVAR_INPUT\n\tIN : BYTE;\n\tVAL : BOOL;\n\tPOS : INT;\nEND_VAR\nVAR CONSTANT\n\tdat : BYTE := 1;\nEND_VAR\n\n(*\nversion 1.1\t16. mar 2008\nprogrammer \thugo\ntested by\ttobias\n\nthis function loads a bit into a byte at position pos.\n *)\n\nIF VAL THEN\n\tBIT_LOAD_B := in OR SHL(dat,pos);\nELSE\n\tBIT_LOAD_B := in AND (NOT SHL(dat,pos));\nEND_IF;\n\n\n(* revision history\nhm\t29. feb 2008\trev 1.0\n\toriginal version\n\nhm\t16. mar 2008\trev 1.1\n\tchange input bit to val for compatibility reasons\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "BIT_LOAD_B2.st", - "source": "FUNCTION BIT_LOAD_B2 : BYTE\nVAR_INPUT\n\tI : BYTE;\n\tD : BOOL;\n\tP : INT;\n\tN : INT;\nEND_VAR\n\n\n(*\nversion 1.0 18. oct. 2008\nprogrammer \thugo\ntested by\ttobias\n\nthis function loads N bits of D at pos P in Byte I\n\n*)\n\nIF D THEN\n\tBIT_LOAD_B2 := ROL(SHR(BYTE#255, 8 - N) OR ROR(i, P), P);\nELSE\n\tBIT_LOAD_B2 := ROL(SHL(BYTE#255, N) AND ROR(I, P), P);\nEND_IF;\n\n\n\n(* revision history\nhm\t18. oct. 2008\trev 1.0\n\toriginal version\n\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "BIT_LOAD_DW.st", - "source": "FUNCTION BIT_LOAD_DW : DWORD\nVAR_INPUT\n\tIN : DWORD;\n\tVAL : BOOL;\n\tPOS : INT;\nEND_VAR\nVAR CONSTANT\n\tdat : DWORD := 1;\nEND_VAR\n\n(*\nversion 1.1\t16. mar 2008\nprogrammer \thugo\ntested by\ttobias\n\nthis function loads a bit into a DWord at position pos.\n *)\n\nIF val THEN\n\tBIT_LOAD_DW := in OR SHL(dat,pos);\nELSE\n\tBIT_LOAD_DW := in AND (NOT SHL(dat,pos));\nEND_IF;\n\n\n(* revision history\nhm\t29. feb 2008\trev 1.0\n\toriginal version\n\nhm\t16. mar 2008\trev 1.1\n\tchange input bit to val for compatibility reasons\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "BIT_LOAD_DW2.st", - "source": "FUNCTION BIT_LOAD_DW2 : DWORD\nVAR_INPUT\n\tI : DWORD;\n\tD : BOOL;\n\tP : INT;\n\tN : INT;\nEND_VAR\n\n\n(*\nversion 1.0 18. oct. 2008\nprogrammer \thugo\ntested by\ttobias\n\nthis function loads N bits of D at pos P in DWORD I\n\n*)\n\nIF D THEN\n\tBIT_LOAD_DW2 := ROL(SHR(DWORD#4294967295, 32 - N) OR ROR(i, P), P);\nELSE\n\tBIT_LOAD_DW2 := ROL(SHL(DWORD#4294967295, N) AND ROR(I, P), P);\nEND_IF;\n\n\n\n(* revision history\nhm\t18. oct. 2008\trev 1.0\n\toriginal version\n\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "BIT_LOAD_W.st", - "source": "FUNCTION BIT_LOAD_W : WORD\nVAR_INPUT\n\tIN : WORD;\n\tVAL : BOOL;\n\tPOS : INT;\nEND_VAR\nVAR CONSTANT\n\tdat : WORD := 1;\nEND_VAR\n\n(*\nversion 1.1\t16. mar 2008\nprogrammer \thugo\ntested by\ttobias\n\nthis function loads a bit into a Word at position pos.\n *)\n\nIF val THEN\n\tBIT_LOAD_W := in OR SHL(dat,pos);\nELSE\n\tBIT_LOAD_W := in AND (NOT SHL(dat,pos));\nEND_IF;\n\n\n(* revision history\nhm\t29. feb 2008\trev 1.0\n\toriginal version\n\nhm\t16. mar 2008\trev 1.1\n\tchange input bit to val for compatibility reasons\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "BIT_LOAD_W2.st", - "source": "FUNCTION BIT_LOAD_W2 : WORD\nVAR_INPUT\n\tI : WORD;\n\tD : BOOL;\n\tP : INT;\n\tN : INT;\nEND_VAR\n\n\n(*\nversion 1.0 18. oct. 2008\nprogrammer \thugo\ntested by\ttobias\n\nthis function loads N bits of D at pos P in WORD I\n\n*)\n\nIF D THEN\n\tBIT_LOAD_W2 := ROL(SHR(WORD#65535, 16 - N) OR ROR(i, P), P);\nELSE\n\tBIT_LOAD_W2 := ROL(SHL(WORD#65535, N) AND ROR(I, P), P);\nEND_IF;\n\n\n\n(* revision history\nhm\t18. oct. 2008\trev 1.0\n\toriginal version\n\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "BIT_OF_DWORD.st", - "source": "FUNCTION BIT_OF_DWORD : BOOL\nVAR_INPUT\n\tin : DWORD;\n\tN : INT;\nEND_VAR\n\n\n(*\nversion 1.2\t6. jun. 2008\nprogrammer \thugo\ntested by\ttobias\n\nthis function extracts a single bit from the nth position from right (right is lowest bit)\nthe lowest Bit (Bit0 from in) is selected with N=0.\n *)\n\nBIT_OF_DWORD := (SHR(in,N) AND 16#00000001) > 0;\n\n\n(* old code used before rev 1.1\ntemp := SHR(in,n);\nBit_of_Dword := temp.0;\n*)\n\n\n(* revision history\nhm\t4. aug. 2006\trev 1.0\n\toriginal version\n\nhm\t29. feb 2008\trev 1.1\n\timproved performance\n\nhm\t6. jun. 2008\trev 1.2\n\tchanges type of input N from byte to int\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "BIT_TOGGLE_B.st", - "source": "FUNCTION BIT_TOGGLE_B : BYTE\nVAR_INPUT\n\tIN : BYTE;\n\tPOS : INT;\nEND_VAR\n\n\n(*\nversion 1.0 18. oct. 2008\nprogrammer \thugo\ntested by\ttobias\n\nthis function toggles a bit of a BYTE at position pos.\n\n*)\n\nBIT_TOGGLE_B := SHL(BYTE#1, POS) XOR IN;\n\n\n\n\n(* revision history\nhm\t18. oct. 2008\trev 1.0\n\toriginal version\n\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "BIT_TOGGLE_DW.st", - "source": "FUNCTION BIT_TOGGLE_DW : DWORD\nVAR_INPUT\n\tIN : DWORD;\n\tPOS : INT;\nEND_VAR\n\n\n(*\nversion 1.0 18. oct. 2008\nprogrammer \thugo\ntested by\ttobias\n\nthis function toggles a bit of a WORD at position pos.\n\n*)\n\nBIT_TOGGLE_DW := SHL(DWORD#1, POS) XOR IN;\n\n\n\n(* revision history\nhm\t18. oct. 2008\trev 1.0\n\toriginal version\n\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "BIT_TOGGLE_W.st", - "source": "FUNCTION BIT_TOGGLE_W : WORD\nVAR_INPUT\n\tIN : WORD;\n\tPOS : INT;\nEND_VAR\n\n\n(*\nversion 1.0 18. oct. 2008\nprogrammer \thugo\ntested by\ttobias\n\nthis function toggles a bit of a WORD at position pos.\n\n*)\n\nBIT_TOGGLE_W := SHL(WORD#1, POS) XOR IN;\n\n\n\n(* revision history\nhm\t18. oct. 2008\trev 1.0\n\toriginal version\n\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "BUFFER_COMP.st", - "source": "FUNCTION BUFFER_COMP : INT\nVAR_INPUT\n\tPT1 : POINTER TO ARRAY[0..32767] OF BYTE;\n\tSIZE1 : INT;\n\tPT2 : POINTER TO ARRAY[0..32767] OF BYTE;\n\tSIZE2 : INT;\n\tSTART : INT;\nEND_VAR\nVAR\n\ti, j, end : INT;\n\tfirstbyte: BYTE;\nEND_VAR\n\n(*\nversion 1.1\t12. nov. 2009\nprogrammer \thugo\ntested by\toscat\n\n\n \n*)\n\n(* search for first character match *)\nIF size2 <= size1 THEN\n\tend := size1 - size2;\n\tfirstbyte := PT2^[0];\n\tFOR i := START TO end DO\n\t\tIF PT1^[i] = firstbyte THEN\n\t\t\t(* first character matches, now compare rest of array *)\n\t\t\tj := 1;\n\t\t\tWHILE j < size2 DO\n\t\t\t\tIF pt2^[j] <> pt1^[j+i] THEN EXIT; END_IF;\n\t\t\t\tj := j + 1;\n\t\t\tEND_WHILE;\n\t\t\t(* when J > size2 a match was found return the position i in buffer1 *)\n\t\t\tIF j = size2 THEN\n\t\t\t\tBUFFER_COMP := i;\n\t\t\t\tRETURN;\n\t\t\tEND_IF;\n\t\tEND_IF;\n\tEND_FOR;\nEND_IF;\nBUFFER_COMP := -1;\n\n\n(*\nhm 14. nov. 2008\trev 1.0\n\toriginal version\n\nhm\t12. nov. 2009\trev 1.1\n\tperformance increase\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "BUFFER_SEARCH.st", - "source": "FUNCTION BUFFER_SEARCH : INT\nVAR_INPUT\n\tPT : POINTER TO ARRAY[0..32767] OF BYTE;\n\tSIZE : INT;\n\tSTR : STRING(STRING_LENGTH);\n\tPOS : INT;\n\tIGN : BOOL;\nEND_VAR\nVAR\n\tps : POINTER TO ARRAY[0..STRING_LENGTH] OF BYTE;\n\tchx : BYTE;\n\ti: INT;\n\tend: INT;\n\tk: INT;\n\tlx: INT;\nEND_VAR\n\n\n(*\nversion 1.4\t25. jan 2011\nprogrammer \thugo\ntested by\toscat\n\nthis function will search for a string STR in an array of byte starting at position pos.\nthe function needs to be called: buffer_search(adr(\"array\"),sizeof(\"array\"), STR, POS, IGN);\nbecause this function works with pointers its very time efficient and it needs no extra memory.\nThe function returns the position of the first character of the string in the array if found.\na -1 is returned if the string is not found in the array.\nwhen IGN = TRUE, STR must be in capital letters and the search is case insensitv.\n\n*)\n\nps := ADR(STR);\nlx := LEN(STR);\nend := MIN(SIZE - lx, SIZE - 1);\nlx := lx - 1;\nFOR i := pos TO end DO\n\tFOR k := 0 TO lx DO\n\t\tIF IGN THEN chx := TO_UPPER(pt^[i+k]); ELSE chx := pt^[i+k]; END_IF;\n\t\tIF ps^[k] <> chx THEN EXIT; END_IF;\n\tEND_FOR;\n\tIF k > lx THEN\n\t\tBUFFER_SEARCH := i;\n\t\tRETURN;\n\tEND_IF;\nEND_FOR;\nBUFFER_SEARCH := -1;\n\n\n(* revision History\n\nhm 5. mar. 2008\trev 1.0\n\toriginal version\n\nhm\t16. mar. 2008\trev 1.1\n\tchaged type of input size to uint\n\nhm\t13. may. 2008\trev 1.2\n\tchanged type of pointer to array[1..32767]\n\tchanged size of string to STRING_LENGTH\n\nhm\t12. nov. 2009\trev 1.3\n\tlimit end to array size\n\nhm\t25. jan. 2011\trev 1.4\n\tign = True will now ignore case\n\treturn -1 if nothing found\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "BUFFER_TO_STRING.st", - "source": "FUNCTION BUFFER_TO_STRING : STRING(STRING_LENGTH)\nVAR_INPUT\n\tPT : POINTER TO ARRAY[0..32767] OF BYTE;\n\tSIZE : UINT;\n\tSTART : UINT;\n\tSTOP : UINT;\nEND_VAR\nVAR\n\tps : POINTER TO BYTE;\n\ti : UINT;\n\tstp: UINT;\n\tsta: UINT;\nEND_VAR\n\n\n(*\nversion 1.5\t12. nov. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nthis function will retrieve a string from an array of byte starting at position start and stop at position stop.\nthe function needs to be called:\tbuffer_TO_String(adr(\"array\"),sizeof(\"array\"), start, stop);\nbecause this function works with pointers its very time efficient and it needs no extra memory.\n\n*)\n\nps := ADR(BUFFER_TO_STRING);\nIF size = 0 THEN RETURN; END_IF;\nsta := MIN(start, size -1);\nstp := MIN(stop, size -1);\n\n(* check for maximum string_length *)\nIF UINT_TO_INT(stp - sta + 1) >= STRING_LENGTH THEN\n\tstp := sta + INT_TO_UINT(STRING_LENGTH) - 1;\nEND_IF;\n\nFOR i := sta TO stp DO\n\tps^ := pt^[i];\n\tps := ps + 1;\nEND_FOR;\n\n(* terminate the string *)\n\nps^ := 0;\n\n\n\n(* revision History\nhm \t5. mar. 2008\trev 1.0\n\toriginal version\n\nhm\t16. mar. 2008\trev 1.1\n\tchanged type of input size to uint\n\nhm\t13. may. 2008\trev 1.2\n\tchanged type of pointer to array[0..32767]\n\tchanged size of string to STRING_LENGTH\n\nhm\t12. jun. 2008\trev 1.3\n\tcheck for pointer overrun\n\tchange input start and stop to uint\n\tadded type conversions to avoid warnings under codesys 3.0\n\nhm\t23. mar. 2009\trev 1.4\n\tavoid writing to input stop\n\nhm\t12. nov. 2009 rev 1.5\n\tlimit start and stop to size -1\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "BYTE_OF_BIT.st", - "source": "FUNCTION BYTE_OF_BIT : BYTE\nVAR_INPUT\n\tB0:BOOL;\n\tB1:BOOL;\n\tB2:BOOL;\n\tB3:BOOL;\n\tB4:BOOL;\n\tB5:BOOL;\n\tB6:BOOL;\n\tB7:BOOL;\nEND_VAR\n\n\n(*\nversion 1.1\t 18. feb 2006\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function creates a byte from 8 individual bits\n\n*)\n\nByte_of_bit := SHL(SHL(SHL(SHL(SHL(SHL(SHL(BOOL_TO_BYTE(B7),1) OR BOOL_TO_BYTE(B6),1) OR BOOL_TO_BYTE(B5),1) OR BOOL_TO_BYTE(B4),1)\n\tOR BOOL_TO_BYTE(B3),1) OR BOOL_TO_BYTE(B2),1) OR BOOL_TO_BYTE(B1),1) OR BOOL_TO_BYTE(B0);\n\n\n(* revision history\n\nhm\t4. aug 2006\t\trev 1.0\n\toriginal version\n\nhm\t18. feb. 2008\trev 1.1\n\timproved performance\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "BYTE_OF_DWORD.st", - "source": "FUNCTION BYTE_OF_DWORD : BYTE\nVAR_INPUT\n\tin : DWORD;\n\tN : BYTE;\nEND_VAR\n\n\n(*\nversion 1.2\t30. oct. 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function extracts a single byte from the nth position from right (right is lowest byte) \nthe lower byte (starting with Bit0 from in) is selected with N=0.\n*)\n\nBYTE_OF_DWORD := DWORD_TO_BYTE(SHR(in,SHL(n,3)));\n\n(* revision history\nhm\t17. jan 2007\trev 1.0\n\toriginal version\n\nhm\t2. jan 2008\t\trev 1.1\n\timproved performance\n\nhm\t30. oct. 2008\trev 1.2\n\timproved performance\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "BYTE_TO_BITS.st", - "source": "FUNCTION_BLOCK BYTE_TO_BITS\nVAR_INPUT\n\tIN: BYTE;\nEND_VAR\nVAR_OUTPUT\n\tB0: BOOL;\n\tB1: BOOL;\n\tB2: BOOL;\n\tB3: BOOL;\n\tB4: BOOL;\n\tB5: BOOL;\n\tB6: BOOL;\n\tB7: BOOL;\nEND_VAR\n\n\n(*\nversion 1.1\t16. mar. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nthis Function Block extracts the 8 Bits from a byte\n\n\n*)\n\nB0 := IN.0;\nB1 := IN.1;\nB2 := IN.2;\nB3 := IN.3;\nB4 := IN.4;\nB5 := IN.5;\nB6 := IN.6;\nB7 := IN.7;\n\n(* revision history\nhm\t\t4. aug 2006\trev 1.0\n\toriginal version\n\nhm\t\t16. mar 2008\trev 1.1\n\trenamed from byte_to_bit to byte_to_bits for compatibility reasons\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "BYTE_TO_GRAY.st", - "source": "FUNCTION BYTE_TO_GRAY : BYTE\nVAR_INPUT\n\tIN : BYTE;\nEND_VAR\n\n\n(*\nversion 1.0\t9. nov. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nthis function converts a binary to gray code\n\n*)\n\nBYTE_TO_GRAY := IN XOR SHR(IN,1);\n\n(* revision history\nhm\t9. nov. 2009\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "BYTE_TO_RANGE.st", - "source": "FUNCTION BYTE_TO_RANGE : REAL\nVAR_INPUT\n\tX : BYTE;\n\tlow : REAL;\n\thigh : REAL;\nEND_VAR\n\n\n(*\nversion 1.0\t9. jan 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nByte_to_Range converts a Byte into a real between low and high.\n\n*)\n\nBYTE_TO_RANGE := (high - low) * X / 255.0 + low;\n\n\n(* revision history\nhm\t9. jan 2008\t\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "BYTE_TO_STRB.st", - "source": "FUNCTION BYTE_TO_STRB : STRING(8)\nVAR_INPUT\n\tIN : BYTE;\nEND_VAR\nVAR\n\ti: INT;\n\tpt : POINTER TO BYTE;\nEND_VAR\n\n(*\nversion 1.3\t20. jun. 2008\nprogrammer \thugo\ntested by\toscat\n\nBYTE_TO_STRINGB converts a Byte to a String of Bits represented by '0' and '1' s.\nThe lowest order bit will be on the right and the high order bit on the left.\n\n*)\n\n(* pointer für die ausgabe ermitteln *)\npt := ADR(BYTE_TO_STRB);\n(* die 8 ausgabecharacter ermitteln und schreiben *)\nFOR i := 1 TO 8 DO\n\tpt^ := BOOL_TO_BYTE(in.7) + 48;\n\tin := SHL(in,1);\n\tpt := pt + 1;\nEND_FOR;\n\n(* der ausgabestring muss noch mit 0 abgeschlossen werden *)\npt^ := 0;\n\n(* code before rev 1.1\nFOR i := 1 TO 8 DO\n\tIF in.0 = 0 THEN temp := CONCAT('0', temp); ELSE temp := CONCAT('1', temp); END_IF;\n\tin := SHR(in, 1);\nEND_FOR;\nBYTE_TO_STRB := temp;\n*)\n\n\n(* revision history\n\nhm\t\t9.6.2007\trev 1.0\t\t\n\toriginal version \n\nhm\t15. dec 2007\trev 1.1\n\tinprooved code for higher performance\n\nhm\t29. mar. 2008\trev 1.2\n\tchanged STRING to STRING(8)\n\nhm\t20. jun. 2008\trev 1.3\n\tperformance improvement\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "BYTE_TO_STRH.st", - "source": "FUNCTION BYTE_TO_STRH : STRING(2)\nVAR_INPUT\n\tIN : BYTE;\nEND_VAR\nVAR\n\ttemp : BYTE;\n\tPT : POINTER TO BYTE;\nEND_VAR\n\n(*\nversion 1.3\t29 mar. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nBYTE_TO_STRINGH converts a Byte to a String of Hexadecimal represented by '0' .. '9' and 'A' .. 'F'.\nThe lowest order Character will be on the right and the high order Character on the left.\n\n*)\n\n(* read pointer to output string *)\nPT := ADR(BYTE_TO_STRH);\n(* calculate high order hex value *)\ntemp := SHR(in,4);\n(* convert value to hex character *)\nIF temp <= 9 THEN temp := temp + 48; ELSE temp := temp + 55; END_IF;\n(* write friat character to output string *)\nPT^ := temp;\n(* calculate low order hex value *)\ntemp := in AND 2#00001111;\nIF temp <= 9 THEN temp := temp + 48; ELSE temp := temp + 55; END_IF;\n(* increment pointer and wirte low order character *)\npt := pt + 1;\npt^ := temp;\n(* set pointer at the end of the output string and close the string with 0 *)\npt := pt + 1;\npt^:= 0;\n\n\n(* code before rev 1.2\nFOR i := 1 TO 2 DO\n\tX := in AND 2#1111;\n\tIF X <= 9 THEN X := X + 48; ELSE X := X + 55; END_IF;\n\tCx := CHR(X);\n\ttemp := CONCAT(Cx, temp);\n\tin := SHR(in,4);\nEND_FOR;\nBYTE_TO_STRH := temp;\n*)\n\n(* revision history\n\nhm\t9.6.2007\t\trev 1.0\t\t\n\toriginal version \n\nhm\t11.9.2007\t\trev 1.1\t\t\n\tchanged coding for compatibility with twincat, under twincat concat cannot have a function as argument.\t\n\nhm\t15 dec 2007\t\tREV 1.2\n\tchanged code for higher performance\n\nhm\t29. mar. 2008\trev 1.3\n\tchanged STRING to STRING(2)\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "B_TRIG.st", - "source": "FUNCTION_BLOCK B_TRIG\nVAR_INPUT\n\tCLK : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\nEND_VAR\nVAR\n\tedge : BOOL;\nEND_VAR\n\n(*\nversion 1.0\t4. aug. 2006\nprogrammer \thugo\ntested by\t\ttobias\n\nthis block is similar to R_trig and F_trig but it generates a pulse on rising and falling edge.\n\n*)\n\nQ := clk XOR edge;\nedge := CLK;\n\n\n(* revision history\nhm\t\t4. aug. 2006\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "CABS.st", - "source": "FUNCTION CABS : REAL\nVAR_INPUT\n\tX : complex;\nEND_VAR\n\n\n(*\nversion 1.0\t21 feb 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function the aboslute value of a complex number\n\n*)\n\nCABS := HYPOT(x.re, x.im);\n\n\n(* revision history\nhm\t21. feb 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CACOS.st", - "source": "FUNCTION CACOS : complex\nVAR_INPUT\n\tX : complex;\nEND_VAR\nVAR\n\tY : complex;\nEND_VAR\n\n(*\nversion 1.0\t21 feb 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function calculates the arcus cosinus function of a complex number\n\n*)\n\ny := CACOSH(x);\nCACOS.re := y.im;\nCACOS.im := -y.re;\n\n\n\n(* revision history\nhm\t21. feb 2008\trev 1.0\n\toriginal version\n\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CACOSH.st", - "source": "FUNCTION CACOSH : complex\nVAR_INPUT\n\tX : complex;\nEND_VAR\nVAR\n\tY : complex;\nEND_VAR\n\n(*\nversion 1.0\t21 feb 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function calculates the hyperbolic arcus cosinus function of a complex number\n\n*)\n\ny.re := (X.re - X.im)*(X.re + X.im) - 1.0;\ny.im := 2.0 * X.re * X.im;\ny := CSQRT(y);\ny.re := y.re + x.re;\ny.im := y.im + x.im;\nCACOSH := CLOG(y);\n\n\n\n(* revision history\nhm\t21. feb 2008\trev 1.0\n\toriginal version\n\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CADD.st", - "source": "FUNCTION CADD : complex\nVAR_INPUT\n\tX, Y : complex;\nEND_VAR\n\n\n(*\nversion 1.0\t21 feb 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function add two complex numbers\n\n*)\n\nCADD.re := x.re + y.re;\nCADD.im := x.im + y.im;\n\n\n(* revision history\nhm\t21. feb 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CALENDAR.st", - "source": "TYPE CALENDAR :\nSTRUCT\n\tUTC : DT;\t\t\t\t\t(* world time UTC *)\n\tLOCAL_DT : DT;\t\t\t\t\t(* local time *)\n\tLOCAL_DATE : DATE;\t\t\t\t(* local date *)\n\tLOCAL_TOD : TOD;\t\t\t\t\t(* local time of day *)\n\tYEAR : INT;\t\t\t\t\t(* year of LDATE *)\n\tMONTH : INT;\t\t\t\t(* month of LDATE *)\n\tDAY : INT;\t\t\t\t\t(* day of LDATE *)\n\tWEEKDAY : INT;\t\t\t\t(* weekday of LDATE *)\n\tOFFSET : INT;\t\t\t\t(* Time Zone Offset for Local time in minutes *)\n\tDST_EN : BOOL;\t\t\t\t(* daylight savings time enable *)\n\tDST_ON : BOOL;\t\t\t\t(* true when daylight savings time os on *)\n\tNAME : STRING(5);\t\t\t(* name of time zone *)\n\tLANGUAGE : INT;\t\t\t(* location number pls see location setup *)\n\tLONGITUDE : REAL;\t\t\t(* longitude of current location *)\n\tLATITUDE : REAL;\t\t\t(* latitude of current location *)\n\tSUN_RISE : TOD;\t\t\t\t(* sun_rise for current location *)\n\tSUN_SET : TOD;\t\t\t\t(* sun_set for current location *)\n\tSUN_MIDDAY : TOD;\t\t\t(* worldtime when sun stands at south position *)\n\tSUN_HEIGTH : REAL\t;\t\t(* suns heigth at midday, south position *)\n\tSUN_HOR : REAL;\t\t\t(* sun angle horizontal 0 = north in degrees *)\n\tSUN_VER : REAL;\t\t\t(* sun angle vertical above horizon in degrees *)\n\tNIGHT : BOOL;\t\t\t\t(* true between sun_set and sun_rise *)\n\tHOLIDAY : BOOL;\t\t\t(* true when holiday *)\n\tHOLY_NAME : STRING(30);\t(* name of holiday *)\n\tWORK_WEEK : INT;\t\t\t(* current work week *)\nEND_STRUCT\nEND_TYPE\n" - }, - { - "fileName": "CALENDAR_CALC.st", - "source": "FUNCTION_BLOCK CALENDAR_CALC\nVAR_INPUT\n\tSPE : BOOL;\n\tH : REAL := -0.83333333333;\nEND_VAR\nVAR_IN_OUT\n\tXCAL : CALENDAR;\n\tHOLIDAYS : ARRAY[0..29] OF HOLIDAY_DATA;\nEND_VAR\nVAR\n\tlast : DT;\n\tlast_day : DINT;\n\tholy : HOLIDAY;\n\tsun : SUN_TIME;\n\tlast_hour: INT;\n\tutod: TOD;\n\tpos : SUN_POS;\n\tplast: DT;\nEND_VAR\nVAR_TEMP\n\tdtemp : DINT;\n\ttmp : INT;\nEND_VAR\n\n\n(*\nversion 1.7\t3. Feb. 2021\nprogrammer \thugo\ntested by\t\toscat\n\ncalendar_calc liest die weltzeit .UTC aus einer CALENDAR Struktur und berechnet die restlichen Werte der Struktur.\ncalendar_calc stellt sicher das die Werte fortlaufend aktualisiert werden und dabei funktionen nur dann aufgerufen werden wenn dies nötig ist.\ncalendar_calc will calculate sun position data when SPE = TRUE;\n\n*)\n\nIF xcal.UTC <> last THEN\n\t(* run once per second *)\n\t(* update utc last calculated *)\n\tlast := XCAL.UTC;\n\tutod := DT_TO_TOD(xcal.UTC);\n\n\t(* calculate ltc from utc *)\n\tXCAL.LOCAL_DT := UTC_TO_LTIME(XCAL.UTC, XCAL.DST_EN, XCAL.OFFSET);\n\tXCAL.LOCAL_DATE := DT_TO_DATE(XCAL.LOCAL_DT);\n\tXCAL.LOCAL_TOD := DT_TO_TOD(XCAL.LOCAL_DT);\n\tdtemp := DAY_OF_DATE(XCAL.LOCAL_DATE);\n\txcal.night := XCAL.LOCAL_TOD < XCAL.SUN_RISE OR XCAL.LOCAL_TOD > XCAL.SUN_SET;\n\n\t(* run once per hour *)\n\ttmp := HOUR(xcal.LOCAL_TOD);\n\tIF tmp <> last_hour THEN\n\t\tXCAL.DST_ON := DST(XCAL.UTC) AND xcal.DST_EN;\n\t\tlast_hour := tmp;\n\tEND_IF;\n\n\t(* run once per day *)\n\tIF dtemp <> last_day THEN\n\t\tlast_day := dtemp;\n\t\t(* a new day has started, recalculate daily events *)\n\t\tXCAL.YEAR := YEAR_OF_DATE(XCAL.LOCAL_DATE);\n\t\tXCAL.MONTH := MONTH_OF_DATE(XCAL.LOCAL_DATE);\n\t\tXCAL.DAY := DAY_OF_MONTH(XCAL.LOCAL_DATE);\n\t\tXCAL.WEEKDAY := DAY_OF_WEEK(XCAL.LOCAL_DATE);\n\t\tHOLY(date_in := XCAL.LOCAL_DATE, LANGU := xcal.LANGUAGE, HOLIDAYS := HOLIDAYS);\n\t\tXCAL.HOLIDAY := HOLY.Y;\n\t\tXCAL.HOLY_NAME := HOLY.NAME;\n\t\tsun(latitude := XCAL.LATITUDE, longitude := xcal.LONGITUDE, utc := DT_TO_DATE(xcal.UTC), H := H);\n\t\tXCAL.SUN_RISE := DINT_TO_TOD(TOD_TO_DINT(sun.sun_rise) + XCAL.OFFSET * 60000 + SEL(XCAL.DST_ON,DINT#0,3600000));\n\t\tXCAL.SUN_SET := DINT_TO_TOD(TOD_TO_DINT(sun.sun_set) + XCAL.OFFSET * 60000 + SEL(XCAL.DST_ON,DINT#0,3600000));\n\t\tXCAL.SUN_MIDDAY := DINT_TO_TOD(TOD_TO_DINT(sun.MIDDAY) + XCAL.OFFSET * 60000 + SEL(XCAL.DST_ON,DINT#0,3600000));\n\t\tXCAL.SUN_HEIGTH := sun.sun_declination;\n\t\tXCAL.WORK_WEEK := WORK_WEEK(XCAL.LOCAL_DATE);\n\tEND_IF;\n\n\t(* calculate the suns position every 10 seconds when SPE = TRUE *)\n\tIF SPE AND xcal.UTC - plast >= t#25s THEN\n\t\tplast := last;\n\t\tpos(latitude := xcal.LATITUDE, longitude := xcal.LONGITUDE, utc := xcal.UTC);\n\t\txcal.SUN_HOR := pos.B;\n\t\txcal.SUN_VER := pos.HR;\n\tEND_IF;\nEND_IF;\n\n\n\n(* revision history\n\nhm 23. oct. 2008\trev 1.0\n\toriginal version\n\nhm\t8. feb. 2009\trev 1.1\n\tnight was calculated wrong\n\tadded sun position data\n\nhm\t10. mar. 2009\trev 1.2\n\tadded work_week, sun_midday, sun_heigth\n\tsun_position will only be calculated evey 25 seconds\n\tdst will only become true when dst_en = true\n\nhm\t23. jan 2010\trev 1.3\n\tsun_rise, sun_set and sun_midday are now calculated in local time\n\nhm\t18. jan. 2011\trev 1.4\n\tadded input holidays to specify local holidays\n\tchanged call for function sun_time\n\nhm\t2. feb. 2011\trev 1.5\n\tadded input H to specify twilight\n\nhm\t6. apr. 2011\trev 1.6\n\tnight was calculated wrong\n\nHM 3. Feb 2021 rev 1.7\n chaged LDT >> LOCAL_DT, LDATE >> LOCAL_DT, LTOD >> LOCAL_TOD\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "CALIBRATE.st", - "source": "FUNCTION_BLOCK CALIBRATE\nVAR_INPUT\n\tX : REAL;\n\tCO : BOOL;\n\tCS : BOOL;\nEND_VAR\nVAR_INPUT CONSTANT\n\tY_Offset : REAL;\n\tY_Scale : REAL;\nEND_VAR\nVAR_OUTPUT\n\tY : REAL;\nEND_VAR\nVAR RETAIN\n\toffset : REAL;\n\tScale : REAL := 1.0;\nEND_VAR\n\n(*\n\tversion 1.3\t11. mar. 2009\n\tprogrammer \thugo\n\ttested BY\t\thans\n\nCalibrate allows for offset and scale calibration of an analog input.\noffset is calibrated to a stored reference Y_offset while CO is true.\nafter the offset is calibrated, scale can be calibrated to a reference value Y_scale while CS is true.\n*)\n\n(* check for calibration *)\nIF CO THEN\n\tOFFSET := Y_Offset - X;\nELSIF CS THEN\n\tSCALE := Y_scale / (X + OFFSET);\nEND_IF;\n(* calculate output *)\nY := (X + OFFSET) * SCALE;\n\n\n(* revision history\nhm 22.2.2007\t\trev 1.2\n\tchanged VAR RETAIN PERSISTENT to VAR RETAIN for better compatibility\n\twago lon contollers do not support persisitent\n\nhm\t11. mar. 2009\trev 1.3\n\tchanged real constants to use dot syntax\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "CAPITALIZE.st", - "source": "FUNCTION CAPITALIZE : STRING(STRING_LENGTH)\nVAR_INPUT\n\tstr : STRING(STRING_LENGTH);\nEND_VAR\nVAR\n\tPT : POINTER TO BYTE;\n\tpos : INT;\n\tL : INT;\n\tfirst : BOOL := TRUE;\nEND_VAR\n\n(*\nversion 1.2\t20. jun. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\ncapitalize returns str with all first letters after a blank or beginning of the string are converted to uppercase.\n\n*)\n\nPT := ADR(CAPITALIZE);\nCAPITALIZE := str;\nL := LEN(str);\nFOR pos := 1 TO l DO\n\tIF first THEN pt^ := TO_UPPER(pt^);\tEND_IF;\n\t(* remember in first if the next char needs to capitalized *)\n\tfirst := pt^= 32;\n\tPT := pt + 1;\nEND_FOR;\n\n(* revision histroy\nhm\t\t4. mar 2008\trev 1.0\n\toriginal release\n\nhm\t29. mar. 2008\trev 1.1\n\tchanged STRING to STRING(STRING_LENGTH)\n\nhm\t20. jun. 2008\trev 1.2\n\timproved performance\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CARG.st", - "source": "FUNCTION CARG : REAL\nVAR_INPUT\n\tX : complex;\nEND_VAR\n\n\n(*\nversion 1.1\t20. apr. 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function calculates the phase angle (argument) of a complex number\n\n*)\n\nCARG := ATAN2(X.im, X.re);\n\n\n\n(* revision history\nhm\t21. feb. 2008\trev 1.0\n\toriginal version\n\nhm\t20. apr. 2008\trev 1.1\n\tuse ATAN2 instead of ATAN\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CASIN.st", - "source": "FUNCTION CASIN : complex\nVAR_INPUT\n\tX : complex;\nEND_VAR\nVAR\n\tY : complex;\nEND_VAR\n\n(*\nversion 1.0\t21 feb 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function calculates the arcus sinus function of a complex number\n\n*)\n\ny.re := -x.im;\ny.im := x.re;\ny := CASINH(y);\nCASIN.re := y.im;\nCASIN.im := -y.re;\n\n\n\n(* revision history\nhm\t21. feb 2008\trev 1.0\n\toriginal version\n\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CASINH.st", - "source": "FUNCTION CASINH : complex\nVAR_INPUT\n\tX : complex;\nEND_VAR\nVAR\n\tY : complex;\nEND_VAR\n\n(*\nversion 1.0\t21 feb 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function calculates the hyperbolic arcus sinus function of a complex number\n\n*)\n\ny.re := (X.re - X.im)*(X.re + X.im) + 1.0;\ny.im := 2.0 * X.re * X.im;\ny := CSQRT(y);\ny.re := y.re + x.re;\ny.im := y.im + x.im;\nCASINH := CLOG(y);\n\n\n\n(* revision history\nhm\t21. feb 2008\trev 1.0\n\toriginal version\n\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CATAN.st", - "source": "FUNCTION CATAN : complex\nVAR_INPUT\n\tX : complex;\nEND_VAR\nVAR\n\tr2: REAL;\n\tnum, den : REAL;\nEND_VAR\n\n(*\nversion 1.0\t21 feb 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function calculates the complex arcus tangens\n\n*)\n\nr2 := x.re * x.re;\nden := 1.0 - r2 - x.im * x.im;\nCATAN.re := 0.5 * ATAN(2.0 * x.re / den);\nnum := x.im + 1.0;\nnum := r2 + num * num;\nden := x.im - 1.0;\nden := r2 + den * den;\nCATAN.im := 0.25 * (LN(num)-LN(den));\n\n(* revision history\nhm\t21. feb 2008\trev 1.0\n\toriginal version\n\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CATANH.st", - "source": "FUNCTION CATANH : complex\nVAR_INPUT\n\tX : complex;\nEND_VAR\nVAR\n\ti2: REAL;\n\tnum, den : REAL;\nEND_VAR\n\n(*\nversion 1.0\t21 feb 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function calculates the complex arcus hyperbolic tangens\n\n*)\n\ni2 := x.im * x.im;\nnum := 1.0 + x.re;\nnum := i2 + num * num;\nden := 1.0 - x.re;\nden := i2 + den * den;\nCATANH.re := 0.25 * (LN(num) - LN(den));\nden := 1 - x.re * x.re - i2;\nCATANH.im := 0.5 * ATAN(2.0 * x.im / den);\n\n(* revision history\nhm\t21. feb 2008\trev 1.0\n\toriginal version\n\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CAUCHY.st", - "source": "FUNCTION CAUCHY : REAL\nVAR_INPUT\n\tX : REAL;\n\tT : REAL;\n\tU : REAL;\nEND_VAR\nVAR\n\ttmp: REAL;\nEND_VAR\n\n\n(*\nversion 1.0\t26. oct. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the Cauchy distribution function\n\n*)\n\ntmp := x - t;\nCAUCHY := math.PI_INV * U / (U*U + tmp*tmp);\n\n\n\n(* revision hisdtory\nhm\t26. oct. 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CAUCHYCD.st", - "source": "FUNCTION CAUCHYCD : REAL\nVAR_INPUT\n\tX : REAL;\n\tT : REAL;\n\tU : REAL;\nEND_VAR\n\n\n(*\nversion 1.0\t26. oct. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the Cauchy distribution function\n\n*)\n\nCAUCHYCD := 0.5 + math.PI_INV * ATAN((X - T) / U);\n\n\n\n(* revision hisdtory\nhm\t26. oct. 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CCON.st", - "source": "FUNCTION CCON : complex\nVAR_INPUT\n\tX : complex;\nEND_VAR\n\n\n(*\nversion 1.0\t21 feb 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function calcucates the conjugation of a complex number\n\n*)\n\nCCON.re := x.re;\nCCON.im := -x.im;\n\n\n(* revision history\nhm\t21. feb 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CCOS.st", - "source": "FUNCTION CCOS : complex\nVAR_INPUT\n\tX : complex;\nEND_VAR\n\n\n(*\nversion 1.0\t21 feb 2008\nprogrammer \thugo\ntested by\t\toscat\n\nthis function calculates the cosinus function of a complex number\n\n*)\n\nCCOS := CCOSH(CSET(-X.im, X.re));\n\n\n(* revision history\nhm\t21. feb 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CCOSH.st", - "source": "FUNCTION CCOSH : complex\nVAR_INPUT\n\tX : complex;\nEND_VAR\n\n\n(*\nversion 1.0\t21 feb 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function calculates the arcus tangens function of a complex number\n\n*)\n\nCCOSH.re := cosH(x.re) * COS(x.im);\nCCOSH.im := sinH(x.re) * SIN(x.im);\n\n\n(* revision history\nhm\t21. feb 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CDIV.st", - "source": "FUNCTION CDIV : complex\nVAR_INPUT\n\tX, Y : complex;\nEND_VAR\nVAR\n\tTemp : REAL;\nEND_VAR\n\n(*\nversion 1.0\t21 feb 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function divides two complex numbers\n\n*)\n\ntemp := Y.re * Y.re + Y.im * Y.im;\nCDIV.re := (X.re * Y.re + X.im * Y.im) / temp;\nCDIV.im := (X.im * Y.re - X.re * Y.im) / temp;\n\n(* revision history\nhm\t21. feb 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CEIL.st", - "source": "FUNCTION CEIL : INT\nVAR_INPUT\n\tX : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t21. mar. 2008\nprogrammer \thugo\ntested by\ttobias\n\nThis is a rounding function which returns the smallest possible integer which is greater or equal to X.\nceil(3.14) = 4\nceil(-3.14) = -3\n\n*)\n\nCEIL := REAL_TO_INT(x);\nIF CEIL < X THEN\n\tCEIL := CEIL + 1;\nEND_IF;\n\n\n(* revision history\nhm\t7. feb. 2007\trev 1.0\n\toriginal version\n\nhm\t21. mar. 2008\trev 1.1\n\tuse REAL_TO_INT instead of trunc for compatibility reasons\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CEIL2.st", - "source": "FUNCTION CEIL2 : DINT\nVAR_INPUT\n\tX : REAL;\nEND_VAR\n\n\n(*\nversion 1.3\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nThis is a rounding function which returns the smallest possible integer which is greater or equal to X.\nceil2(3.14) = 4\nceil2(-3.14) = -3\n\n*)\n\nCEIL2 := REAL_TO_DINT(X);\nIF DINT_TO_REAL(CEIL2) < X THEN\n\tCEIL2 := CEIL2 + 1;\nEND_IF;\n\n\n(* revision history\nhm\t21. mar. 2008\trev 1.0\n\toriginal version\n\nhm\t4. apr. 2008\trev 1.1\n\tadded type conversion to avoid warnings under codesys 3.0\n\nhm\t30. jun. 2008\trev 1.2\n\tadded type conversion to avoid warnings under codesys 3.0\n\nhm\t10. mar. 2009\trev 1.3\n\tuse correct statement real_to_DINT\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CEXP.st", - "source": "FUNCTION CEXP : complex\nVAR_INPUT\n\tX : complex;\nEND_VAR\nVAR\n\tTemp : REAL;\nEND_VAR\n\n(*\nversion 1.0\t21 feb 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function calculates the complex exponent\n\n*)\n\ntemp := EXP(X.re);\nCEXP.re := temp * COS(X.im);\nCEXP.im := temp * SIN(X.im);\n\n\n(* revision history\nhm\t21. feb 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CHARCODE.st", - "source": "FUNCTION CHARCODE : BYTE\nVAR_INPUT\n\tSTR : STRING(10);\nEND_VAR\nVAR\n\tfound: STRING(1);\n\tsearch : STRING(10);\n\tpos: INT;\n\ti: INT;\nEND_VAR\n\n(*\nversion 1.2\t\t24. oct. 2008\nprogrammer \t\thugo\ntested by\t\thugo\n\nCHARCODE converts a HTML Character NAME INTO ITS code\n'äuml' is convterted to ä\n'euro' is converted to €\n\n*)\n\nIF LEN(str) = 1 THEN\n\tCHARCODE := CODE(STR, 1);\nELSIF str <> '' THEN\n\t(* construct search string *)\n\tsearch := CONCAT('&', str);\n\tsearch := CONCAT(search, ';');\n\tWHILE pos = 0 AND (i < 4) DO\n\t\ti := i + 1;\n\t\tpos := FIND(setup.CHARNAMES[i], search);\n\tEND_WHILE;\n\tfound := MID(setup.CHARNAMES[i], 1, pos - 1);\n\tCHARCODE := CODE(found, 1);\nEND_IF;\n\n\n\n\n(* revision history\nhm\t13. may. 2008\trev 1.0\n\toriginal version\n\nhm\t19. oct. 2008\trev 1.1\n\tchanged setup constants\n\nhm\t24. oct. 2008\trev 1.2\n\toptimized code\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CHARNAME.st", - "source": "FUNCTION CHARNAME : STRING(10)\nVAR_INPUT\n\tC : BYTE;\nEND_VAR\nVAR\n\tpos: INT;\n\ti : INT;\nEND_VAR\n\n(*\nversion 1.4\t\t17. dec. 2008\nprogrammer \t\thugo\ntested by\t\toscat\n\nCHARNAME converts a Character code into its HTML character name\nä is convterted to 'äuml'\n€ is converted to 'euro'\nthe character itself is returned if no name is available for the character\n\n*)\n\nIF C <> 0 THEN\n\t(* construct search string from code followed by $ sign, also clear charname string*)\n\tCHARNAME := CHR_TO_STRING(C);\n\tCHARNAME := CONCAT(CHARNAME,'&');\n\tCHARNAME := CONCAT(';', CHARNAME);\n\tWHILE pos = 0 AND (i < 4) DO\n\t\ti := i + 1;\n\t\tpos := FIND(setup.CHARNAMES[i], CHARNAME);\n\tEND_WHILE;\n\tIF pos > 0 THEN\n\t\tCHARNAME := MID(setup.CHARNAMES[i], 10, pos + 3);\n\t\t(* search for end of name and truncate *)\n\t\tpos := FIND(CHARNAME, ';');\n\t\tCHARNAME := LEFT(CHARNAME,pos - 1);\n\tELSE\n\t\tCHARNAME := CHR_TO_STRING(C);\n\tEND_IF;\nELSE\n\tCHARNAME := '';\nEND_IF;\n\n\n\n\n(* revision history\nhm\t13. may. 2008\trev 1.0\n\toriginal version\n\nhm\t16. jun. 2008\trev 1.1\n\tchanged nested call of concat for better compatibility\n\nhm\t19. oct. 2008\trev 1.2\n\tchanges setup constants\n\nhm\t24. oct. 2008\trev 1.3\n\tnew code for high performance\n\nhm\t17. dec. 2008\trev 1.4\n\tchanged function chr to chr_to_string\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CHECK_PARITY.st", - "source": "FUNCTION CHECK_PARITY : BOOL\nVAR_INPUT\n\tin : DWORD;\n\tp : BOOL;\nEND_VAR\n\n\n(*\nversion 1.3\t18 feb 2008\nprogrammer \thugo\ntested by\ttobias\n\nthis function checks for an even partity for a dword and partity bit.\n\n*)\n\nCHECK_PARITY := NOT p;\nWHILE in > 0 DO\n\tCHECK_PARITY := CHECK_PARITY XOR in.0 XOR in.1 XOR in.2 XOR in.3;\n\tin := SHR(in,4);\nEND_WHILE;\n\n(* code before rev 1.2\nWHILE in > 0 DO\n\tIF in.0 THEN cnt := cnt + 1; END_IF;\n\tin := SHR(in,1);\nEND_WHILE;\ncheck_parity := even(cnt) XOR P;\n*)\n\n\n(* revision history\n\nrev 1.0 HM 1.oct.2006\n\nrev 1.1 hm\t10.sep.2007\n\tchanged algorithm to improove performance\n\nrev 1.2\thm\t8 dec 2007\n\tchanged algorithm to improove performance\n\nrev 1.3 hm\t18. feb 2008\n\tchanged algorithm to improove performance\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CHK_REAL.st", - "source": "FUNCTION CHK_REAL : BYTE\nVAR_INPUT\n\tX : REAL;\nEND_VAR\nVAR\n\tpt : POINTER TO DWORD;\n\ttmp : DWORD;\nEND_VAR\n\n\n(*\nversion 1.0\t20. jan. 2011\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function checks a floating point variable of type real (IEEE754-32Bits) for NAN and infinity\nRETURN values: #0 = normal value, #20 = +infinity, #40 = -infinty, #80 = NAN\n\n*)\n\npt := ADR(X);\t\t\t\t(* move real to dword, real_to_dword does not work becasze it treats dword as a number on many systems *)\ntmp := ROL(pt^,1);\t\t\t(* rotate left foir easy checking, sign will be at lease significant digit *)\nIF tmp < 16#FF000000 THEN\n\tCHK_REAL := 16#00;\t\t(* normalized and denormalized numbers *)\nELSIF tmp = 16#FF000000 THEN\n\tCHK_REAL := 16#20;\t\t(* X is +infinity see IEEE754 *)\nELSIF tmp = 16#FF000001 THEN\n\tCHK_REAL := 16#40;\t\t(* X is -infinity see IEEE754 *)\nELSE\n\tCHK_REAL := 16#80;\t\t(* X is NAN see IEEE754 *)\nEND_IF;\n\n\n(* revision history\nhm\t 20. jan. 2011\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CHR_TO_STRING.st", - "source": "FUNCTION CHR_TO_STRING : STRING(1)\nVAR_INPUT\n\tC : BYTE;\nEND_VAR\nVAR\n\tPT : POINTER TO BYTE;\nEND_VAR\n\n(*\nversion 1.3\t17. dec. 2008\nprogrammer \thugo\ntested by\toscat\n\nCHR creates a character from a byte input and stuffs it in a one character length string.\n\n*)\n\nPT := ADR(CHR_TO_STRING);\nPT^ := C;\npt := pt + 1;\npt^ := 0;\n\n(* revision history\nhm\t16 jan 2007\t\trev 1.0\n\toriginal version\n\nhm\t4. feb. 2008\trev 1.1\n\treturn string would not be terminated properly\n\nhm\t29. mar. 2008\trev 1.2\n\tchanged STRING to STRING(1)\n\nhm\t17. dec. 2008\trev 1.3\n\tchanged name of function from chr to chr_to_string\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CINV.st", - "source": "FUNCTION CINV : complex\nVAR_INPUT\n\tX : complex;\nEND_VAR\nVAR\n\ttemp : REAL;\nEND_VAR\n\n(*\nversion 1.0\t21 feb 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function calculates the inverse of a complex numbers (1 / X)\n\n*)\n\ntemp := X.re * X.re + X.im * X.im;\nCINV.re := X.re / temp;\nCINV.im := -X.im / temp;\n\n(* revision history\nhm\t21. feb 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CIRCLE_A.st", - "source": "FUNCTION CIRCLE_A : REAL\nVAR_INPUT\n\trx : REAL;\n\tax : REAL;\nEND_VAR\n\n\n(*\nversion 1.2\t22. feb 2008\nprogrammer \thugo\ntested by\t\ttobias\n\ncircle_A calculates the Area of a circle segement if ax = 360 the whole circle is calculated\n\n\n*)\n\ncircle_A := Rx * RX * 8.726646E-3 * Ax;\n\n(* revision histroy\nhm\t16. oct 2007\trev 1.0\n\toriginal version\n\nhm\t4. dec 2007\t\trev 1.1\n\tchanged code for better performance\n\nhm\t22. feb 2008\trev 1.2\n\timproved performance\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CIRCLE_C.st", - "source": "FUNCTION CIRCLE_C : REAL\nVAR_INPUT\n\tRx : REAL;\n\tAx : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t22 feb 2008\nprogrammer \thugo\ntested by\t\ttobias\n\ncircle_C calculates the Circumference of a circle if ax = 360 the whole circle is calculated\n\n*)\n\ncircle_C := 1.7453293E-2 * Rx * Ax;\n\n(* revision histroy\nhm\t16. oct 2007\trev 1.0\n\toriginal version\n\nhm\t22. feb 2008\trev 1.1\n\timproved performance\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CIRCLE_SEG.st", - "source": "FUNCTION CIRCLE_SEG : REAL\nVAR_INPUT\n\tRX : REAL;\n\tHX : REAL;\nEND_VAR\n\n\n(*\nversion 1.0\t10. Mar 2010\nprogrammer \thugo\ntested by\t\ttobias\n\nCIRCLE_SEG calculates the Area of a circle segement enclosed between a sectant line and the circumference.\n\n\n*)\n\nIF RX > 0.0 THEN\n\tCIRCLE_SEG := 2.0 * ACOS(1.0 - LIMIT(0.0, HX / RX, 2.0));\n\tCIRCLE_SEG := (CIRCLE_SEG - SIN(CIRCLE_SEG)) *RX * RX / 2.0;\nEND_IF;\n\n\n(* revision histroy\nhm\t10. mar 2010\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CLEAN.st", - "source": "FUNCTION CLEAN : STRING(STRING_LENGTH)\nVAR_INPUT\n\tIN : STRING(STRING_LENGTH);\n\tCX : STRING(80);\nEND_VAR\nVAR\n\tpos: INT := 1;\n\tstop: INT;\nEND_VAR\n\n\n(*\nversion 1.0\t18. jun. 2008\nprogrammer \thugo\ntested by\toscat\n\nClean deletes all characters from a string except the ones specified in CX.\n\n*)\n\n(* copy input string *)\nCLEAN := IN;\nstop := LEN(in);\nWHILE pos <= stop DO\n\tIF FIND(cx, MID(CLEAN, 1, pos)) > 0 THEN\n\t\t(* charcter found skip to next one *)\n\t\tpos := pos + 1;\n\tELSE\n\t\t(* wrong chracter needs to be deleted *)\n\t\tCLEAN := DELETE(CLEAN, 1, pos);\n\t\tstop := stop - 1;\t(* the string is one character shorter now *)\n\tEND_IF;\nEND_WHILE;\n\n\n\n(* revision history\n\nhm\t\t18. jun. 2008\trev 1.0\t\t\n\toriginal version \n\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CLICK_CNT.st", - "source": "FUNCTION_BLOCK CLICK_CNT\nVAR_INPUT\n\tIN : BOOL;\n\tN : INT;\n\tTC : TIME;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\nEND_VAR\nVAR\n\ttx : TP;\n\tedge: BOOL;\n\tcnt: INT := -1;\nEND_VAR\n\n(*\nversion 1.0\t16. jul. 2008\nprogrammer \thugo\ntested by\toscat\n\nthis Module decodes a specified number of clicks.\nthe output trig is high for one cycle if N clicks are present within a specified time TC.\n\n*)\n\n(* Q shall only be active for one cycle only *)\nQ := FALSE;\n\nIF in AND NOT edge AND NOT tx.q THEN\n\t(* a rising edge on in sets the counter to 0 *)\n\tcnt := 0;\nELSIF tx.Q AND NOT IN AND edge THEN\n\t(* count falling edges when tp.q is true *)\n\tcnt := cnt + 1;\nELSIF NOT tx.Q THEN\n\tQ := cnt = N;\n\tcnt := -1;\nEND_IF;\n\n(* remember the status of IN *)\nedge := IN;\ntx(in := IN, pt := TC);\n\n\n(* revision history\n\nhm \t16. jul. 2008\trev 1.0\n\toriginal version released\n\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "CLICK_DEC.st", - "source": "FUNCTION_BLOCK CLICK_DEC\nVAR_INPUT\n\tIN : BOOL;\n\tTC : TIME;\nEND_VAR\nVAR_OUTPUT\n\tQ0, Q1, Q2, Q3 : BOOL;\nEND_VAR\nVAR\n\ttx : TP;\n\tedge: BOOL;\n\tcnt: INT := -1;\nEND_VAR\n\n(*\nversion 1.1\t14. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nthis Module detects a rising edge on In and decodes the amount of falling edges (Pulses) within a specified time TC.\nthe outputs Q0..Q3 will go true for one cycle and the amount of clicks within a specified time TC.\nif only a rising egde is detected within TC Q0 will respond, Q1 for 1 pulse and so on..\n\n*)\n\n(* Q shall only be active for one cycle only *)\nIF in = FALSE THEN\n\tQ0 := FALSE;\n\tQ1 := FALSE;\n\tQ2:= FALSE;\n\tQ3 := FALSE;\nEND_IF;\n\nIF in AND NOT edge AND NOT tx.q THEN\n\t(* a rising edge on in sets the counter to 0 *)\n\tcnt := 0;\nELSIF tx.Q AND NOT IN AND edge THEN\n\t(* count falling edges when tp.q is true *)\n\tcnt := cnt + 1;\nELSIF NOT tx.Q THEN\n\tCASE cnt OF\n\t\t0 : Q0 := TRUE;\n\t\t1 : Q1 := TRUE;\n\t\t2 : Q2 := TRUE;\n\t\t3 : Q3 := TRUE;\n\tEND_CASE;\n\tcnt := -1;\nEND_IF;\n\n(* remember the status of IN *)\nedge := IN;\ntx(in := IN, pt := TC);\n\n\n\n(* revision history\n\nhm 17. jul. 2008\trev 1.0\n\toriginal version released\n\nhm\t14. mar. 2009\trev 1.1\n\tremoved double assignments\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "CLK_DIV.st", - "source": "FUNCTION_BLOCK CLK_DIV\nVAR_INPUT\n\tclk : BOOL;\n\trst: BOOL;\nEND_VAR\nVAR_OUTPUT\n\tQ0 : BOOL;\n\tQ1 : BOOL;\n\tQ2 : BOOL;\n\tQ3 : BOOL;\n\tQ4 : BOOL;\n\tQ5 : BOOL;\n\tQ6 : BOOL;\n\tQ7 : BOOL;\nEND_VAR\nVAR\n\tcnt: BYTE;\nEND_VAR\n\n(*\nversion 1.1\t2 jan 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nthis is a clock divider\neach output divides the signal by 2\nQ0 = clk / 2 , Q1 = Q0 / 2 and so on.\nthe outputs have a 50% duty cycle each.\n\n\n*)\n\nIF rst THEN\n\tcnt:= 0;\n\tQ0 := 0;\n\tQ1 := 0;\n\tQ2 := 0;\n\tQ3 := 0;\n\tQ4 := 0;\n\tQ5 := 0;\n\tQ6 := 0;\n\tQ7 := 0;\nELSIF clk THEN\n\tcnt:= cnt +1;\n\tQ0 := cnt.0;\n\tQ1 := cnt.1;\n\tQ2 := cnt.2;\n\tQ3 := cnt.3;\n\tQ4 := cnt.4;\n\tQ5 := cnt.5;\n\tQ6 := cnt.6;\n\tQ7 := cnt.7;\nEND_IF;\n\n(* revision history\nhm\t4. aug. 2006\trev 1.0\n\toriginal version\n\nhm\t2. jan 2008\t\trev 1.1\n\timproved performance\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "CLK_N.st", - "source": "FUNCTION_BLOCK CLK_N\nVAR_INPUT\n\tN : INT;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\nEND_VAR\nVAR\n\tedge : BOOL;\n\tstime: DWORD;\n\tclk: BOOL;\nEND_VAR\n\n(*\nversion 1.0\t17 sep 2007\nprogrammer \thugo\ntested by\t\ttobias\n\nclk_N uses the internal sps time to generate one pulse every N ms\nevery pulse is only valid for one cycle so that a edge trigger is not necessary\nclk_N generates pulses depending on the accuracy of the system clock.\nThe input N controlls the period time of the clock.\nN=0 equals 1ms, N=1 equals 2ms, N=2 equals 4ms, N=3 equals 8ms ....\n\nbe careful, 1ms clocks will only work on very powerful sps cpu's\n*)\n\nstime := SHR(T_PLC_MS(),N);\nclk := stime.0;\nQ := clk XOR edge;\nedge := CLK;\n\n(* revision history\nhm\t16. dec 2007\t\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "CLK_PRG.st", - "source": "FUNCTION_BLOCK CLK_PRG\nVAR_INPUT\n\tPT : TIME := t#10ms;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\nEND_VAR\nVAR\n\tinit : BOOL;\n\tlast : TIME;\n\ttx: TIME;\nEND_VAR\n\n(*\nversion 1.3\t25. oct. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nclk_prg uses the internal sps time to generate a clock with programmable period time.\nthe first cycle after start is a clk pulse and then depending on the programmed period time a delay.\nevery pulse is only valid for one cycle.\nthe accuracy of clk_prg is depending on the accuracy of the system clock.\n\n*)\n\n(* read system time *)\ntx := DWORD_TO_TIME(T_PLC_MS());\n\n(* initialize on startup *)\nIF NOT init THEN\n\tinit := TRUE;\n\tlast := tx - pt;\nEND_IF;\n\n(* generate output pulse when next_pulse is reached *)\nQ := tx - last >= pt;\nIF Q THEN last := tx; END_IF;\n\n\n(* revision hiostory\n\nhm 25 feb 2007\trev 1.1\n\trewritten code for higher performance\n\tpt can now be changed during runtime\n\nhm\t17. sep 2007\trev 1.2\n\treplaced time() with t_plc_ms() for compatibility reasons\n\nhm\t25. oct. 2008\trev 1.3\n\toptimized code\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "CLK_PULSE.st", - "source": "FUNCTION_BLOCK CLK_PULSE\nVAR_INPUT\n\tPT : TIME;\n\tN : INT;\n\tRST : BOOL ;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\n\tCNT : INT;\n\tRUN : BOOL;\nEND_VAR\nVAR\n\ttx, tn: DWORD;\n\tinit: BOOL;\nEND_VAR\n\n(*\nversion 1.2\t\t16 feb 2011\nprogrammer \thugo\ntested by\t\toscat\n\nclk_pulse uses the internal sps time to generate a clock with programmable period time.\nthe period time is defined for 10ms .. 65s.\npulse generation is continuous if N = 0 and for n pulses otherwise.\nthe first cycle after start is a clk pulse and then depending on the programmed period time a delay.\nevery pulse is only valid for one cycle so that a edge trigger is not necessary\nclk_prg depending on the accuracy of the system clock.\n\n*)\n\ntx := T_PLC_MS();\t\t(* read system *)\nQ := FALSE;\t\t\t\t(* reset Q we generate pulses only for one cycle *)\nRUN := CNT < N;\n\nIF NOT init OR RST THEN\n\tinit := TRUE;\n\tCNT := 0;\n\ttn := tx - TIME_TO_DWORD(PT);\n\tRUN := FALSE;\nELSIF (cnt < N OR N = 0) AND tx - tn >= TIME_TO_DWORD(PT) THEN\t\t(* generate a pulse *)\n\tCNT := CNT + 1;\n\tQ := TRUE;\n\ttn := tn + TIME_TO_DWORD(PT);\nEND_IF;\n\n\n\n(* revision history\nhm\t\t4. aug 2006\t\trev 1.0\n\toriginal version\n\nhm\t\t17. sep 2007\trev 1.1\n\treplaced time() with T_PLC_S() for compatblity reasons\n\nhm\t\t16. feb. 2011\trev 1.2\n\tfixed an error when timer overflows \n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "CLOG.st", - "source": "FUNCTION CLOG : complex\nVAR_INPUT\n\tX : complex;\nEND_VAR\n\n\n(*\nversion 1.1\t20. apr. 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function calculates the complex natural (base e) logarithm\n\n*)\n\nCLOG.re := LN(HYPOT(X.re, X.im));\nCLOG.im := ATAN2(X.im, X.re);\n\n\n(* revision history\nhm\t21. feb 2008\trev 1.0\n\toriginal version\n\nhm\t20. apr. 2008\trev 1.1\n\tuse ATAN2 instead of ATAN\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CMP.st", - "source": "FUNCTION CMP : BOOL\nVAR_INPUT\n\tX,Y : REAL;\n\tN : INT;\nEND_VAR\nVAR\n\ttmp : REAL;\nEND_VAR\n\n\n(*\n\tversion 1.1\t10. mar. 2009\n\tprogrammer \thugo\n\ttested by\t\ttobias\n\nthis function checks two inputs x and y if they are identical with the first N digits\nexample : cmp(3.141516,3.141517,6 is true.\n\n*)\n\ntmp := ABS(x);\nIF tmp > 0.0 THEN\n\ttmp := EXP10(INT_TO_REAL(FLOOR(LOG(tmp))-N+1));\nELSE\n\ttmp := EXP10(tmp);\nEND_IF;\nCMP := ABS(X - Y) < tmp;\n\n\n(* revision history\nhm\t12. mar. 2008\trev 1.0\n\toriginal version\n\nhm\t10. mar. 2009\trev 1.1\n\tadded type conversion for compatibility reasons\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CMUL.st", - "source": "FUNCTION CMUL : complex\nVAR_INPUT\n\tX, Y : complex;\nEND_VAR\n\n\n(*\nversion 1.0\t21 feb 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function multiplies two complex numbers\n\n*)\n\nCMUL.re := X.re * Y.re - X.im * Y.im;\nCMUL.im := X.re * Y.im + X.im * Y.re;\n\n(* revision history\nhm\t21. feb 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CODE.st", - "source": "FUNCTION CODE : BYTE\nVAR_INPUT\n\tSTR : STRING(STRING_LENGTH);\n\tPOS : INT;\nEND_VAR\nVAR\n\tPT : POINTER TO BYTE;\nEND_VAR\n\n(*\nversion 1.1\t29. mar. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\ncode extracts the code of a character at position POS of a string STR.\n\n*)\n\nIF pos < 1 OR pos > LEN(str) THEN\n\tCODE := 0;\n\tRETURN;\nELSE\n\tPT := ADR(STR) + INT_TO_DWORD(pos - 1);\n\tCODE := pt^;\nEND_IF;\n\n(* revision history\nhm\t9. mar. 2008\trev 1.0\n\toriginal version\n\nhm\t29. mar. 2008\trev 1.1\n\tchanged STRING to STRING(STRING_LENGTH)\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "COMPLEX.st", - "source": "TYPE COMPLEX :\nSTRUCT\n\tre : REAL;\n\tim : REAL;\nEND_STRUCT\nEND_TYPE\n" - }, - { - "fileName": "CONE_V.st", - "source": "FUNCTION CONE_V : REAL\nVAR_INPUT\n\trx : REAL;\n\thx : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t4 dec 2007\nprogrammer \thugo\ntested by\t\ttobias\n\ncone_V calculates the Volume of a cone\n\n*)\n\ncone_V := 1.047197551 * RX * RX * hx;\n\n(* revision histroy\nhm\t17. oct 2007\trev 1.0\n\toriginal version\n\nhm\t4. dec 2007\t\trev 1.1\n\tchanged code for better performance\n\nhm\t22. feb 2008\trev 1.2\n\tchanged code for better performance\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CONSTANTS_LANGUAGE.st", - "source": "TYPE CONSTANTS_LANGUAGE :\nSTRUCT\n\t(* Language Setup *)\n\tDEFAULT : INT := 1; (* 1=english, 2=german 3=french *)\n\tLMAX : INT := 3;\n\tWEEKDAYS : ARRAY[1..3, 1..7] OF STRING(10) :=\t'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi', 'Dimanche';\n\tWEEKDAYS2 : ARRAY[1..3, 1..7] OF STRING(2) :=\t'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'Lu', 'Ma', 'Me', 'Je', 'Ve', 'Sa', 'Di';\n\tMONTHS : ARRAY[1..3, 1..12] OF STRING(10) :=\t'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'Janvier', 'Février', 'mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Decembre';\n\tMONTHS3 : ARRAY[1..3, 1..12] OF STRING(3) :=\t'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'Jan', 'Feb', 'Mrz', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'Jan', 'Fev', 'Mar', 'Avr', 'Mai', 'Jun', 'Jul', 'Aou', 'Sep', 'Oct', 'Nov', 'Dec';\n\tDIRS : ARRAY[1..3,0..15] OF STRING(3) :=\t\t'N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'N', 'NNO', 'NO', 'ONO', 'O', 'OSO', 'SO', 'SSO', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'N', 'NNO', 'NO', 'ONO', 'O', 'OSO', 'SO', 'SSO', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW';\nEND_STRUCT\nEND_TYPE\n" - }, - { - "fileName": "CONSTANTS_LOCATION.st", - "source": "TYPE CONSTANTS_LOCATION :\nSTRUCT\n\t(* location setup *)\n\tDEFAULT : INT := 1; (* 1=germany, 2=austria 3=france 4=belgium-german 5= italien-Südtirol *)\n\tLMAX : INT := 5;\n\n\t(* language spoken in the location *)\n\tLANGUAGE : ARRAY[1..5] OF INT := 2, 2, 3, 2, 2;\n\nEND_STRUCT\nEND_TYPE\n" - }, - { - "fileName": "CONSTANTS_MATH.st", - "source": "TYPE CONSTANTS_MATH :\nSTRUCT\n\tPI : REAL := \t3.14159265358979323846264338327950288;\t\t(* Kreiszahl PI *)\n\tPI2 : REAL := \t6.28318530717958647692528676655900576;\t(* PI * 2 *)\n\tPI4 : REAL := 12.56637061435917295385057353311801152;\t(* PI * 4 *)\n\tPI05 : REAL := 1.5707963267949;\t\t\t\t\t\t\t(* PI / 2 *)\n\tPI025 : REAL := 0.785398163397448;\t\t\t\t\t\t\t(* PI / 4 *)\n\tPI_INV : REAL := 0.318309886183791;\t\t\t\t\t\t(* 1 / PI *)\n\tE : REAL := \t2.71828182845904523536028747135266249;\t\t(* Euler constant e *)\n\tE_INV : REAL := 0.367879441171442;\t\t\t\t\t\t\t(* 1 / e *)\n\tSQ2 : REAL :=\t1.4142135623731;\t\t\t\t\t\t\t(* Wurzel von 2 *)\n\tFACTS : ARRAY[0..12] OF DINT := 1,1,2,6,24,120,720,5040,40320,362880,3628800,39916800,479001600;\nEND_STRUCT\nEND_TYPE\n" - }, - { - "fileName": "CONSTANTS_PHYS.st", - "source": "TYPE CONSTANTS_PHYS :\nSTRUCT\n\tC : REAL := 299792458.0;\t\t\t\t(* Lichtgeschwindigkeit in m/s *)\n\tE : REAL := 1.60217653E-19;\t\t\t\t(* elementarladung in Colomb = A * s *)\n\tG : REAL := 9.80665; \t\t\t\t\t\t(* Erdbeschleunigung in m / s² *)\n\tT0 : REAL := -273.15;\t\t\t\t\t\t(* absoluter Nullpunkt in °C *)\n\tRU : REAL := 8.314472; \t\t\t\t\t(* Universelle Gaskonstante in J / (mol · K) *)\n\tPN : REAL := 101325.0;\t\t\t\t\t(* NormalDruck in Pa *)\nEND_STRUCT\nEND_TYPE\n" - }, - { - "fileName": "CONSTANTS_SETUP.st", - "source": "TYPE CONSTANTS_SETUP :\nSTRUCT\n\t(* setup Parameters *)\n\tEXTENDED_ASCII : BOOL := TRUE;\n\tCHARNAMES : ARRAY[1..4] OF STRING(253) := ';\""&&<<>>€€  ¡¡¢¢££¤¤¥¥¦¦§§¨¨©©ªª««¬¬­­®®¯¯°°±±²²³³´´µµ¶¶··¸¸¹¹ºº»»¼¼ÛÛ',\n\t\t';¾¾¿¿ÀÀÁÁÂÂÃÃÄÄÅÅÆÆÇÇÈÈÉÉÊÊËËÌÌÍÍÎÎÏÏÐÐÑÑÒÒÓÓÔÔÕÕÖÖ×רØÙÙÚÚ½½',\n\t\t';ÜÜÝÝÞÞßßààááââããääååææççèèééêêëëììííîîïïððññòòóóôôõõöö÷÷øøùù',\n\t\t';úúûûüüýýþþÿÿ';\n\tMTH_OFS : ARRAY[1..12] OF INT := 0,31,59,90,120,151,181,212,243,273,304,334;\n\tDECADES : ARRAY[0..8] OF REAL := 1.0,10.0,100.0,1000.0,10000.0,100000.0,1000000.0,10000000.0,100000000.0;\nEND_STRUCT\nEND_TYPE\n" - }, - { - "fileName": "CONTROL_SET1.st", - "source": "FUNCTION_BLOCK CONTROL_SET1\nVAR_INPUT\n\tKt : REAL;\n\tTt : REAL;\n\tPI : BOOL;\n\tPID : BOOL;\nEND_VAR\nVAR_INPUT CONSTANT\n\tP_K : REAL := 0.5;\n\tPI_K : REAL := 0.45;\n\tPI_TN : REAL := 0.83;\n\tPID_K : REAL := 0.6;\n\tPID_TN : REAL := 0.5;\n\tPID_TV : REAL := 0.125;\nEND_VAR\nVAR_OUTPUT\n\tKP : REAL;\n\tTN : REAL;\n\tTV : REAL;\n\tKI : REAL;\n\tKD : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t11. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\ntakahashi calculates controller parameters for P, PI and PID controllers based on the ziegler nichols method.\n\n*)\n\nIF pi AND PID THEN\n\tKP := 0.0;\n\tTN := 0.0;\n\tTV := 0.0;\nELSIF PID THEN\n\tKP := PID_K * Kt;\n\tTN := PID_TN * Tt;\n\tTV := PID_TV * Tt;\nELSIF PI THEN\n\tKP := PI_K * Kt;\n\tTN := PI_TN * Tt;\nELSE\n\tKP := P_K * Kt;\nEND_IF;\n\n(* KI and KD are calculated *)\nIF tn > 0.0 THEN KI := KP / TN; ELSE KI := 0.0; END_IF;\nKD := KP * TV;\n\n(* revision history\nhm\t4. nov 2007\trev 1.0\n\toriginal version\n\nhm\t11. mar. 2009\trev 1.1\n\treal constants updated to new systax using dot\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "CONTROL_SET2.st", - "source": "FUNCTION_BLOCK CONTROL_SET2\nVAR_INPUT\n\tKS : REAL;\n\tTU : REAL;\n\tTG : REAL;\n\tPI : BOOL;\n\tPID : BOOL;\nEND_VAR\nVAR_INPUT CONSTANT\n\tP_K : REAL := 1.0;\n\tPI_K : REAL := 0.9;\n\tPI_TN : REAL := 3.33;\n\tPID_K : REAL := 1.2;\n\tPID_TN : REAL := 2.0;\n\tPID_TV : REAL := 0.5;\nEND_VAR\nVAR_OUTPUT\n\tKP : REAL;\n\tTN : REAL;\n\tTV : REAL;\n\tKI : REAL;\n\tKD : REAL;\nEND_VAR\nVAR\n\tTX : REAL;\nEND_VAR\n\n(*\nversion 1.1\t11. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\ntakahashi calculates controller parameters for P, PI and PID controllers based on the ziegler nichols method.\n\n*)\n\nIF TU > 0.0 AND KS > 0.0 THEN TX := TG / TU / KS; END_IF;\nIF pi AND PID THEN\n\tKP := 0.0;\n\tTN := 0.0;\n\tTV := 0.0;\nELSIF PID THEN\n\tKP := PID_K * TX;\n\tTN := PID_TN * TU;\n\tTV := PID_TV * TU;\nELSIF PI THEN\n\tKP := PI_K * TX;\n\tTN := PI_TN * TU;\nELSE\n\tKP := P_K * TX;\nEND_IF;\n\n(* KI and KD are calculated *)\nIF TN > 0.0 THEN KI := KP / TN; ELSE KI := 0.0; END_IF;\nKD := KP * TV;\n\n(* revision history\nhm\t4. nov 2007\trev 1.0\n\toriginal version\n\nhm\t11. mar. 2009\trev 1.1\n\treal constants updated to new systax using dot\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "COSH.st", - "source": "FUNCTION COSH : REAL\nVAR_INPUT\n\tX : REAL;\nEND_VAR\nVAR\n\tt: REAL;\nEND_VAR\n\n\n(*\nversion 1.3\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the cos hyperbolicus\n\n*)\n\nT := EXP(X);\nCOSH := (1.0 / T + T) * 0.5;\n\n(* revision histroy\nhm\t12.1.2007\trev 1.0\n\toriginal version\n\nhm\t1.12.2007\trev 1.1\n\tchanged code to improve performance\n\nhm\t5. jan 2008\trev 1.2\n\tfurther performance improvement\n\nhm\t10. mar. 2009\trev 1.3\n\treal constants updated to new systax using dot\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "COTH.st", - "source": "FUNCTION COTH : REAL\nVAR_INPUT\n\tX : REAL;\nEND_VAR\n\n\n(*\nversion 1.4\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the cotangens hyperbolicus\n\n*)\n\nIF X > 20.0 THEN\n\tCOTH :=1.0;\nELSIF X < -20.0 THEN\n\tCOTH := -1.0;\nELSE\n\tCOTH := 1.0 + 2.0 / (EXP(X * 2.0) - 1.0);\nEND_IF;\n\n\n(* revision histroy\nhm\t\t12.1.2007\trev 1.0\n\toriginal version\n\nhm\t1.12.2007\t\trev 1.1\n\tchanged code to improve performance\n\nhm\t8. jan 2008\trev 1.2\n\tfurther improvement in performance\n\nhm\t10. mar 2008\trev 1.3\n\textended range of valid inputs to +/- INV\n\tchanged formula for better accuracy\n\nhm\t10. mar. 2009\trev 1.4\n\treal constants updated to new systax using dot\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "COUNT_BR.st", - "source": "FUNCTION_BLOCK COUNT_BR\nVAR_INPUT\n\tSET : BOOL;\n\tIN : BYTE;\n\tUP : BOOL;\n\tDN : BOOL;\n\tSTEP : BYTE := 1;\n\tMX : BYTE := 255;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tCNT : BYTE;\nEND_VAR\nVAR\n\tlast_up: BOOL;\n\tlast_dn: BOOL;\nEND_VAR\n\n(*\n\tversion 1.0\t16 jan 2008\n\tprogrammer \thugo\n\ttested BY\ttobias\n\nCount_BR is a byte counter with independen up and dn inputs. the counter counts from 0 to mx and continues at 0 after is has reached mx\na step input sets the counters stepping width.\n\n*)\n\nIF rst THEN\n\tcnt := 0;\nELSIF set THEN\n\tcnt := LIMIT(0,in,mx);\nELSIF up AND NOT last_up THEN\n\tcnt := INT_TO_BYTE(INC(cnt,step,mx));\nELSIF dn AND NOT last_dn THEN\n\tcnt := INT_TO_BYTE(inc(cnt,-step,mx));\nEND_IF;\nlast_up := up;\nlast_dn := dn;\n\n(* revision history\nhm\t16. jan 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "COUNT_CHAR.st", - "source": "FUNCTION COUNT_CHAR : INT\nVAR_INPUT\n\tstr : STRING(STRING_LENGTH);\n\tchr : BYTE;\nEND_VAR\nVAR\n\tl: INT;\n\tpt : POINTER TO BYTE;\n\tpos: INT;\nEND_VAR\n\n\n(*\nversion 1.1\t29. mar. 2008\nprogrammer \t\tkurt\ntested by\t\thugo\n\nCOUNT_CHAR counts how often a character CHAR occurs within a string STR.\n\n*)\n\nPT := ADR(str);\nl := LEN(str);\nCOUNT_CHAR := 0;\nFOR pos := 1 TO l DO\n\tIF pt^ = CHR THEN COUNT_CHAR := COUNT_CHAR + 1; END_IF;\n PT := PT + 1;\nEND_FOR;\n\n\n(* revision history\nhm\t29. feb 2008\trev 1.0\n\toriginal version\n\nhm\t29. mar. 2008\trev 1.1\n\tchanged STRING to STRING(STRING_LENGTH)\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "COUNT_DR.st", - "source": "FUNCTION_BLOCK COUNT_DR\nVAR_INPUT\n\tSET : BOOL;\n\tIN : DWORD;\n\tUP : BOOL;\n\tDN : BOOL;\n\tSTEP : DWORD := 1;\n\tMX : DWORD := 16#FFFFFFFF;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tCNT : DWORD;\nEND_VAR\nVAR\n\tlast_up: BOOL;\n\tlast_dn: BOOL;\nEND_VAR\n\n(*\n\tversion 1.1\t20. jan. 2011\n\tprogrammer \thugo\n\ttested BY\t\ttobias\n\nCount_DR is a DWORD counter with independen up and dn inputs. the counter counts from 0 to mx and continues at 0 after is has reached mx\na step input sets the counters stepping width.\n\n*)\n\nIF rst THEN\n\tcnt := 0;\nELSIF set THEN\n\tcnt := LIMIT(0,in,mx);\nELSIF up AND NOT last_up THEN\n\tIF STEP > MX - CNT THEN\n\t\tCNT := CNT - MX + STEP - 1;\n\tELSE\n\t\tCNT := CNT + STEP;\n\tEND_IF;\nELSIF dn AND NOT last_dn THEN\n\tIF STEP > CNT THEN\n\t\tCNT := CNT - STEP + MX + 1;\n\tELSE\n\t\tCNT := CNT - STEP;\n\tEND_IF;\nEND_IF;\nlast_up := up;\nlast_dn := dn;\n\n(* revision history\nhm\t12. jun 2008\trev 1.0\n\toriginal version\n\nhm\t20. jan. 2011\trev 1.1\n\tcorrected init value of MX to 16#FFFFFFFF\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "COUNT_SUBSTRING.st", - "source": "FUNCTION COUNT_SUBSTRING : INT\nVAR_INPUT\n SEARCH : STRING;\n STR : STRING;\nEND_VAR\nVAR\n pos : INT;\n size : INT;\nEND_VAR\n\n(*\nversion 1.0\t20. jan. 2011\nprogrammed\tkurt\ntested by\t\ttobias\n\ncount_substring returns the number of occurences of a substring in a string\n\n*)\n\nCOUNT_SUBSTRING := 0;\nsize := LEN(SEARCH);\nREPEAT\n pos := FIND(STR,SEARCH);\n IF pos > 0 THEN\n STR := REPLACE(STR, '', size,pos);\n COUNT_SUBSTRING := COUNT_SUBSTRING + 1;\n END_IF;\nUNTIL pos = 0\nEND_REPEAT;\n\n\n(* revision history\nks\t20. jan. 2011\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CPOL.st", - "source": "FUNCTION CPOL : complex\nVAR_INPUT\n\tL : REAL;\n\tA : REAL;\nEND_VAR\n\n\n(*\nversion 1.0\t21 feb 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function creates a complex numbers for the polar form with the inputs L (length) an A for Angle.\n\n*)\n\nCPOL.re := L * COS(A);\nCPOL.im := L * SIN(A);\n\n\n(* revision history\nhm\t21. feb 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CPOW.st", - "source": "FUNCTION CPOW : complex\nVAR_INPUT\n\tX : complex;\n\tY : Complex;\nEND_VAR\n\n\n(*\nversion 1.0\t21 feb 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function calculates the complex power function x to the power of y\n\n*)\n\nCPOW := CEXP(CMUL(Y,CLOG(X)));\n\n\n(* revision history\nhm\t21. feb 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CRC_GEN.st", - "source": "FUNCTION CRC_GEN : DWORD\n\nVAR_INPUT\n\tPT : POINTER TO ARRAY[0..32000] OF BYTE;\n\tSIZE : INT;\n\tPL : INT;\n\tPN : DWORD;\n\tINIT : DWORD;\n\tREV_IN : BOOL;\n\tREV_OUT : BOOL;\n\tXOR_OUT : DWORD;\nEND_VAR\nVAR\n\tpos : INT;\n\tshift : INT;\n\tdx: BYTE;\n\tbits: INT;\nEND_VAR\n\n(*\nversion 2.1\t3. feb. 2021\nprogrammer \thugo\ntested by\t\ttobias\n\nCRC_GEN generates a CRC checksum from a block of data and returns the checksum in a DWORD to be connected to the data for transmission.\nthe CRC Polynom is specified with the config variable PN and the length of the Polynom is specified by PL\nA Polynom x4 + X + 1 is represented by 0011 with length 4, the highest order bit is not specified at all..\nThe input data is an array of byte of any size, the function is called by CRC_GEN(ADR(array),SIZEOF(array), ....).\n\n*)\n\n(* align polygon *)\nshift := 32 - PL;\nPN := SHL(PN, shift);\n\n(* load first 4 bytes into register minimum message size is 4 bytes\n\tfor smaller messages fill with 0#s at the beginning*)\nFOR pos := 0 TO 3 DO\n\tIF REV_IN THEN CRC_GEN := SHL(CRC_GEN, 8) OR REVERSE(PT^[pos]); ELSE CRC_GEN := SHL(CRC_GEN, 8) OR PT^[pos]; END_IF;\nEND_FOR;\npos := 4;\n\n(* xor with init value *)\nCRC_GEN := CRC_GEN XOR SHL(init, shift);\n\n(* calculate CRC for each byte *)\nWHILE pos < size DO\n\tIF REV_IN THEN DX := REVERSE(PT^[pos]); ELSE DX := PT^[pos]; END_IF;\n\tpos := pos + 1;\n\t(* crc calculation for one byte *)\n\tFOR bits := 0 TO 7 DO\n\t\tIF CRC_GEN.31 THEN\n\t\t\tCRC_GEN := (SHL(CRC_GEN, 1) OR BOOL_TO_DWORD(DX.7)) XOR PN;\n\t\tELSE\n\t\t\tCRC_GEN := SHL(CRC_GEN, 1) OR BOOL_TO_DWORD(DX.7);\n\t\tEND_IF;\n\t\tdx := SHL(dx, 1);\n\tEND_FOR;\nEND_WHILE;\n\n(* all bytes are processed, need to finish the registers 32 bits *)\nFOR bits := 0 TO 31 DO\n\tIF CRC_GEN.31 THEN\n\t\tCRC_GEN := (SHL(CRC_GEN, 1) ) XOR PN;\n\tELSE\n\t\tCRC_GEN := SHL(CRC_GEN, 1);\n\tEND_IF;\nEND_FOR;\n\n(* final XOR *)\nCRC_GEN := SHR(CRC_GEN, shift) XOR XOR_OUT;\n\n(* reverse the crc_out put if necessary *)\nIF REV_OUT THEN CRC_GEN := REFLECT(CRC_GEN, PL); END_IF;\n\n(* suggested optimization by deninis klopke\ndie betreffs genannte Funktion kann folgendermaßen optimiert werden:\nIn Zeilen 33 und 35 des Implementierungsteils kann jeweils der Teil „OR BOOL_TO_DWORD(DX.7)“ entfallen, da nach 8maligem Linksshift von „DX“ in Zeile 26 der Wert von DX = BYTE#0 ist. Eine weitere Veroderung mit diesem Wert hat keine Auswirkungen auf das Ergebnis mehr.\n*)\n\n(* typical crc polynoms\n\nCRC-4-ITU \t\t\tx4 + x + 1 \t\t\t\t\t(ITU G.704, p. 12) \t0x3 or 0xC (0x9)\nCRC-5-ITU \t\t\tx5 + x4 + x2 + 1 \t\t\t(ITU G.704, p. 9) \t0x15 or 0x15 (0x0B) Bluetooth\nCRC-5-USB \t\t\tx5 + x2 + 1 \t\t\t\t(use: USB token packets) \t0x05 or 0x14 (0x9)\nCRC-6-ITU \t\t\tx6 + x + 1 \t\t\t\t\t(ITU G.704, p. 3) \t0x03 or 0x30 (0x21)\nCRC-7 \t\t\t\tx7 + x3 + 1 \t\t\t\t(use: telecom systems, MMC) \t0x09 or 0x48 (0x11)\nCRC-8-ATM \t\t\tx8 + x2 + x + 1 \t\t\t\t(use: ATM HEC) \t0x07 or 0xE0 (0xC1)\nCRC-8-CCITT \t\tx8 + x7 + x3 + x2 + 1 \t\t(use: 1-Wire bus) \t0x8D or 0xB1 (0x63)\nCRC-8-Dallas/Maxim \tx8 + x5 + x4 + 1 \t\t\t(use: 1-Wire bus) \t0x31 or 0x8C (0x19)\nCRC-8 \t\t\t\tx8 + x7 + x6 + x4 + x2 + 1 \t0xD5 or 0xAB (0x57)\nCRC-8-SAE J1850 \tx8 + x4 + x3 + x2 + 1 \t\t0x1D or 0xB8\nCRC-10 \t\t\t\tx10 + x9 + x5 + x4 + x + 1 \t0x233 or 0x331 (0x263)\nCRC-12 \t\t\t\tx12 + x11 + x3 + x2 + x + 1 (use: telecom systems) \t0x80F or 0xF01 (0xE03)\nCRC-15-CAN \t\t\tx15 + x14 + x10 + x8 + x7 + x4 + x3 + 1 \t0x4599 or 0x4CD1 (0x19A3)\nCRC-16-Fletcher \tNot a CRC; see Fletcher's checksum \tUsed in Adler-32 A & B CRCs\nCRC-16-CCITT \tx16 + x12 + x5 + 1 (XMODEM,X.25, V.41, Bluetooth, PPP, IrDA; known as \"CRC-CCITT\") \t0x1021 or 0x8408 (0x0811)\nCRC-16-IBM \tx16 + x15 + x2 + 1 (USB, many others; also known as \"CRC-16\") \t0x8005 or 0xA001 (0x4003)\nCRC-24-Radix-64 \tx24 + x23 + x18 + x17 + x14 + x11 + x10 + x7 + x6 + x5 + x4 + x3 + x + 1 \t0x864CFB or 0xDF3261 (0xBE64C3)\nCRC-32-Adler \tNot a CRC; see Adler-32 \tSee Adler-32\nCRC-32-MPEG2 \tx32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1 \t0x04C11DB7 or 0xEDB88320 (0xDB710641) Also used in IEEE 802.3\nCRC-32-IEEE 802.3 \tx32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1 (V.42) \t0x04C11DB7 or 0xEDB88320 (0xDB710641)\nCRC-32C (Castagnoli) \tx32 + x28 + x27 + x26 + x25 + x23 + x22 + x20 + x19 + x18 + x14 + x13 + x11 + x10 + x9 + x8 + x6 + 1 \t0x1EDC6F41 or 0x82F63B78 (0x05EC76F1)\nCRC-64-ISO \tx64 + x4 + x3 + x + 1 (use: ISO 3309) \t0x000000000000001B or 0xD800000000000000 (0xB000000000000001)\nCRC-64-ECMA-182 \tx64 + x62 + x57 + x55 + x54 + x53 + x52 + x47 + x46 + x45 + x40 + x39 + x38 + x37 + x35 + x33 + x32 + x31 + x29 + x27 + x24 + x23 + x22 + x21 + x19 + x17 + x13 + x12 + x10 + x9 + x7 + x4 + x + 1\n(as described in ECMA-182 p.63) \t0x42F0E1EBA9EA3693 or 0xC96C5795D7870F42 (0x92D8AF2BAF0E1E85)\n*)\n\n\n\n(* revision history\n\nhm\t9.6.2007\t\trev 1.0\t\t\n\toriginal version \n\nhm\t11.9.2007\t\trev 1.1\n\tdeleted unused variable i\n\nhm\t9. oct 2007 \trev 1.2\n\tadded init code for crc and xor_out\n\tadded refelct in and reflect_out (rev_in und Rev_out)\n\nhm\t2. jan 2008\trev 1.3\n\tsmall changes for performance improvements\n\nhm\t16. mar. 2008\trev 1.4\n\tchanged type of input size to uint\n\nhm\t10. mar. 2009\trev 1.5\n\tremoved nested comments\n\nhm\t16. jan. 2011\trev 2.0\n\tnew version\n\ndk 3. feb 2021\t\trev 2.1\n\timproved code by dennis koepke\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CSET.st", - "source": "FUNCTION CSET : complex\nVAR_INPUT\n\tRE : REAL;\n\tIM : REAL;\nEND_VAR\n\n\n(*\nversion 1.0\t21 feb 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function creates a complex number from two real inputs\n\n*)\n\nCSET.re := RE;\nCSET.im := IM;\n\n(* revision history\nhm\t21. feb 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CSIN.st", - "source": "FUNCTION CSIN : complex\nVAR_INPUT\n\tX : complex;\nEND_VAR\n\n\n(*\nversion 1.0\t21 feb 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function calculates the sinus function of a complex number\n\n*)\n\nCSIN.re := cosH(X.im) * SIN(X.re);\nCSIN.im := sinH(X.im) * COS(X.re);\n\n\n(* revision history\nhm\t21. feb 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CSINH.st", - "source": "FUNCTION CSINH : complex\nVAR_INPUT\n\tX : complex;\nEND_VAR\n\n\n(*\nversion 1.0\t21 feb 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function calculates the sinus function of a complex number\n\n*)\n\nCSINH.re := sinH(X.re) * COS(X.im);\nCSINH.im := cosH(X.re) * SIN(X.im);\n\n\n(* revision history\nhm\t21. feb 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CSQRT.st", - "source": "FUNCTION CSQRT : complex\nVAR_INPUT\n\tX : complex;\nEND_VAR\nVAR\n\ttemp : REAL;\nEND_VAR\n\n(*\nversion 1.0\t21 feb 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function calculates the complex sqare root\n\n*)\n\ntemp := HYPOT(x.re, x.im);\nCSQRT.re := SQRT(0.5 * (temp + x.re));\nCSQRT.im := sgn(x.im) * SQRT(0.5 * (temp - x.re));\n\n\n(* revision history\nhm\t21. feb 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CSUB.st", - "source": "FUNCTION CSUB : complex\nVAR_INPUT\n\tX, Y : complex;\nEND_VAR\n\n\n(*\nversion 1.0\t21 feb 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function subtracts two complex numbers\n\n*)\n\nCSUB.re := X.re - Y.re;\nCSUB.im := X.im - Y.im;\n\n(* revision history\nhm\t21. feb 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CTAN.st", - "source": "FUNCTION CTAN : complex\nVAR_INPUT\n\tX : complex;\nEND_VAR\nVAR\n\ttemp : REAL;\n\txi2: REAL;\n\txr2: REAL;\nEND_VAR\n\n(*\nversion 1.1\t10. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nthis function calculates the tangens function of a complex number\n\n*)\n\nxi2 := 2.0 * x.im;\nxr2 := 2.0 * x.re;\ntemp := 1.0 / (COS(xr2) + COSH( xi2));\nCTAN.re := temp * SIN(xr2);\nCTAN.im := temp * SINH(xi2);\n\n\n(* revision history\nhm\t21. feb 2008\trev 1.0\n\toriginal version\n\nhm\t10. mar 2009\trev 1.1\n\tfaster code\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CTANH.st", - "source": "FUNCTION CTANH : complex\nVAR_INPUT\n\tX : complex;\nEND_VAR\nVAR\n\ttemp : REAL;\n\txi2: REAL;\n\txr2: REAL;\nEND_VAR\n\n(*\nversion 1.1\t10. mar. 2009\nprogrammer \thugo\ntested by\toscat\n\nthis function calculates the complex hyperbolictangens\n\n*)\n\nxi2 := 2.0 * x.im;\nxr2 := 2.0 * x.re;\ntemp := 1.0 / (COSH(xr2) + COS(xi2));\nCTANH.re := temp * SINH(xr2);\nCTANH.im := temp * SIN(xi2);\n\n\n(* revision history\nhm\t21. feb 2008\trev 1.0\n\toriginal version\n\nhm\t10. mar. 2009\trev 1.1\t\n\tnew faster code\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CTRL_IN.st", - "source": "FUNCTION CTRL_IN : REAL\nVAR_INPUT\n\tSET_POINT, ACTUAL, NOISE : REAL;\nEND_VAR\n\n\n(*\nversion 1.0\t2. jun 2008\nprogrammer \thugo\ntested by\t\ttobias\n\n\n*)\n\n(* calculate the process error DIFF *)\nCTRL_IN := DEAD_ZONE(SET_POINT - ACTUAL, NOISE);\n\n\n(* revision history\nhm \t2. jun. 2008 \trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "CTRL_OUT.st", - "source": "FUNCTION_BLOCK CTRL_OUT\nVAR_INPUT\n\tCI, OFFSET, MAN_IN, LIM_L, LIM_H : REAL;\n\tMANUAL : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tY : REAL;\n\tLIM : BOOL;\nEND_VAR\n\n\n(*\nversion 1.1\t5. nov 2008\nprogrammer \thugo\ntested by\toscat\n\n\n*)\n\nY := SEL(MANUAL, CI, MAN_IN) + OFFSET;\n\n(* Limit the output *)\nIF Y > LIM_L AND Y < LIM_H THEN\n\tLIM := FALSE;\nELSE\n\tY := LIMIT(LIM_L, Y, LIM_H);\n\tLIM := TRUE;\nEND_IF;\n\n\n\n(* revision history\nhm \t2. jun. 2008 \trev 1.0\n\toriginal version\n\nhm\t5. nov. 2008\trev 1.1\n\toptimized code\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "CTRL_PI.st", - "source": "FUNCTION_BLOCK CTRL_PI\nVAR_INPUT\n\tACT, SET, SUP, OFS, M_I : REAL;\n\tMAN : BOOL;\n\tRST : BOOL;\n\tKP : REAL := 1.0;\n\tKI : REAL := 1.0;\n\tLL : REAL := -1000.0;\n\tLH : REAL := 1000.0;\nEND_VAR\nVAR_OUTPUT\n\tY : REAL;\n\tDIFF : REAL;\n\tLIM : BOOL;\nEND_VAR\nVAR\n\tpi : FT_PIWL;\n\tco : CTRL_OUT;\nEND_VAR\n\n(*\nversion 2.0\t30. jun 2008\nprogrammer \thugo\ntested by\toscat\n\nFT_PI is a PI controller with manual functionality.\nThe PID controller works according to the fomula Y = e *(KP+ KI * INTEG(e) ) + offset, while e = set_point - actual.\na rst will reset all internal data, while a switch to manual will cause the controller to follow the function Y = manual_in + offset.\nlimit_h and Limit_l set the possible output range of Y.\nthe output flags lim will signal that the output limits are active and overflow will signal that the integrator has reached its limits.\n\nsince rev 1.1 the \"trapezregel is used for more accuracy.\nrev 1.2 added selective integratin which means the integrative component is only active within a small range of the target value \nthis avoids the integrator to go to limits while an input setpoint change happened and is only causing overshoots.\nthe int_band is by default 100 which means the int is active all the time and if set to for example to 0.1 the integrator is only active\nwhile the input is between 0.9 and 1.1 of the set_point value.\n\ndefault values for KP = 1, TN = 1, TV = 1, LIMIT_L = -1000, LIMIT_H = +1000.\n*)\n\nDIFF := CTRL_IN(SET, ACT, SUP);\npi(in := DIFF, kp := KP, ki := KI, lim_l := LL, lim_h := LH, rst := RST);\nco(ci := pi.Y, OFFSET := OFS, man_in := M_I, lim_l := LL, lim_h := LH, MANUAL := MAN);\nY := co.Y;\nLIM := co.LIM;\n\n\n(* revision history\nhm \t31.10.2007 \t\trev 1.0\n\toriginal version\n\nhm\t3.11.2007\t\trev 1.1\n\tadded noise input to filter noise\n\tadded output diff\n\tset limit output false when output is within limits\n\toverfolw was not set correctly\n\nhm\t5. jan 2008\t\trev 1.2\n\timproved performance\n\nhm\t20. jun. 2008\trev 2.0\n\trewritten using new modular approach\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "CTRL_PID.st", - "source": "FUNCTION_BLOCK CTRL_PID\nVAR_INPUT\n\tACT, SET, SUP, OFS, M_I : REAL;\n\tMAN : BOOL;\n\tRST : BOOL;\n\tKP : REAL := 1.0;\n\tTN : REAL := 1.0;\n\tTV : REAL := 1.0;\n\tLL : REAL := -1000.0;\n\tLH : REAL := 1000.0;\nEND_VAR\nVAR_OUTPUT\n\tY : REAL;\n\tDIFF : REAL;\n\tLIM : BOOL;\nEND_VAR\nVAR\n\tpid : FT_PIDWL;\n\tco : CTRL_OUT;\nEND_VAR\n\n\n\n(*\nversion 2.0\t30. jun. 2008\nprogrammer \thugo\ntested by\toscat\n\nFT_PI is a PI controller with manual functionality.\nThe PID controller works according to the fomula Y = e *(KP+ KI * INTEG(e) ) + offset, while e = set_point - actual.\na rst will reset all internal data, while a switch to manual will cause the controller to follow the function Y = manual_in + offset.\nlimit_h and Limit_l set the possible output range of Y.\nthe output flags lim will signal that the output limits are active.\n\n*)\n\nDIFF := CTRL_IN(SET, ACT, SUP);\npid(in := DIFF, kp := KP, tn := TN, tv := TV, lim_l := LL, lim_h := LH, rst := RST);\nco(ci := pid.Y, OFFSET := OFS, man_in := M_I, lim_l := LL, lim_h := LH, MANUAL := MAN);\nY := co.Y;\nLIM := co.LIM;\n\n\n\n(* revision history\n\nhm 1.12.2006\t \trev 1.1\n\tchanged algorithm to trapezregel for higher accuracy.\n\nhm 3.1.2007\t\trev 1.2\n\tadded integ_band to select when the integrator is active.\n\nhm\t3.3.2007\t\trev 1.3\n\tadded default values to inputs KP, TN, TV, LIMIT_L und LIMIT_H.\n\nhm 31.oct 2007\trev 1.4\n\ttotal rewrite of the module to avoid failures when one of the limits is 0\n\nhm\t3.11.2007\trev 1.5\n\tadded noise input to filter noise\n\tadded output diff\n\tset limit output false when output is within limits\n\toverfolw was not set correctly\n\nhm\t5. jan 2008\trev 1.6\n\timproved code for better performance\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "CTRL_PWM.st", - "source": "FUNCTION_BLOCK CTRL_PWM\nVAR_INPUT\n\tCI, MAN_IN : REAL;\n\tMANUAL : BOOL;\n\tF : REAL;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\nEND_VAR\nVAR\n\tPW : PWM_DC;\nEND_VAR\n\n(*\nversion 1.1\t21. oct. 2008\nprogrammer \thugo\ntested by\toscat\n\n\n*)\n\nPW(F := F, DC := SEL(MANUAL,CI,MAN_IN));\nQ := PW.Q;\n\n\n(* revision history\nhm 3. jun. 2008 \trev 1.0\n\toriginal version\n\nhm\t21. oct. 2008\trev 1.1\n\toptimized code\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "CYCLE_4.st", - "source": "FUNCTION_BLOCK CYCLE_4\nVAR_INPUT\n\tE : BOOL := TRUE;\n\tT0, T1, T2, T3 : TIME;\n\tS0 : BOOL;\n\tSX : INT;\n\tSL : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tSTATE : INT;\nEND_VAR\nVAR\n\ttx : TIME;\n\tlast : TIME;\n\tinit: BOOL;\nEND_VAR\n\n\n(*\nversion 1.0\t\nprogrammer \thugo\ntested by\toscat\n\n\n \n*)\n\n(* read system timer *)\ntx := DWORD_TO_TIME(T_PLC_MS());\n(* init on first cycle *)\nIF NOT init THEN\n\tinit := TRUE;\n\tlast := tx;\nEND_IF;\n\nIF E THEN\n\tIF SL THEN\n\t\t(* when sx > 0 then the state sx is forced to start *)\n\t\tstate:= LIMIT(0,SX,3);\n\t\tlast := tx;\n\t\t(* this is to avoid to reset sx from the calling programm it does work fine on codesys but i am not sure about other systems, because we are writing to an input *)\n\t\tSL := FALSE;\n\tELSE\n\t\tCASE state OF\n\t\t\t0 :\t(* wait for T0 and switch to next cycle *)\n\t\t\t\tIF tx - last >= T0 THEN\n\t\t\t\t\tstate := 1;\n\t\t\t\t\tlast := tx;\n\t\t\t\tEND_IF;\n\t\t\t1 : (* wait for T1 over 1st cycle *)\n\t\t\t\tIF tx - last >= T1 THEN\n\t\t\t\t\tstate := 2;\n\t\t\t\t\tlast := tx;\n\t\t\t\tEND_IF;\n\t\t\t2 : (* wait for T1 over 1st cycle *)\n\t\t\t\tIF tx - last >= T2 THEN\n\t\t\t\t\tstate := 3;\n\t\t\t\t\tlast := tx;\n\t\t\t\tEND_IF;\n\t\t\t3 : (* wait for T2 over 2nd cycle *)\n\t\t\t\tIF tx - last >= T3 THEN\n\t\t\t\t\tIF S0 THEN State := 0; END_IF; (* if S0 is false, the sequence stops at state 3 *)\n\t\t\t\t\tlast := tx;\n\t\t\t\tEND_IF;\n\t\tEND_CASE;\n\tEND_IF;\nELSE\n\tstate := 0;\n\tlast := tx;\nEND_IF;\n\n\n\n(*\nhm\t3. nov. 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "CYCLE_TIME.st", - "source": "FUNCTION_BLOCK CYCLE_TIME\nVAR_INPUT\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tct_min : TIME;\n\tct_max : TIME;\n\tct_last : TIME;\n\tsystime : TIME;\n\tsysdays : INT;\n\tcycles : DWORD;\nEND_VAR\nVAR\n\tlast_cycle : TIME;\n\ttx: TIME;\n\tinit: BOOL;\nEND_VAR\n\n\n(*\n\tversion 1.2\t16 sep 2007\n\tprogrammer \thugo\n\ttested BY\t\thans\n\nthis function block measures the cycle time and displays the last, min and max cycle time of the current task.\nthe resolution is 1ms.\nthe cycles output is a dword counter which counts the cycles.\na rst pulse on the input will reset all data.\n\n\n*)\n\ntx := DWORD_TO_TIME(T_PLC_MS()) - last_cycle;\nIF rst THEN\n\tct_min := t#10h;\n\tct_max := t#0ms;\n\tcycles := 0;\nELSIF last_cycle > t#0s THEN\n\tIF tx < ct_min THEN ct_min := tx;\n\tELSIF tx > ct_max THEN ct_max := tx;\n\tEND_IF;\n\tct_last := tx;\nELSIF ct_min = t#0s THEN\n\tct_min := t#0s - t#1ms;\nEND_IF;\nIF init THEN\n\tsystime := systime + tx;\n\t\tIF systime >= t#1d THEN\n\t\t\tsystime := systime - t#1d;\n\t\t\tsysdays := sysdays + 1;\n\t\tEND_IF;\nEND_IF;\ninit := TRUE;\nlast_cycle := last_cycle + tx;\ncycles := cycles + 1;\n\n(*\trevision history\nhm 12.12.2006\t\trev 1.1\n\tadded cycles output, a dword cycle counter.\nhm 10.3.2007\t\t\trev 1.2\n\tchanged initialization of ct_min to t#10h for compatibility with siemens s7\n\nhm\t16.9.2007\t\trev 1.2\n\tchanged Time() in T_PLC_MS() for compatibility resons\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "C_TO_F.st", - "source": "FUNCTION C_TO_F : REAL\nVAR_INPUT\n\tcelsius : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t11. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function converts celsius to fahrenheit \n\n*)\n\nC_TO_F := celsius * 1.8 + 32.0;\n\n\n(* revision history\n\nhm\t4. aug. 2006\trev 1.0\n\toriginal version\n\nhm\t11. mar. 2009\trev 1.1\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "C_TO_K.st", - "source": "FUNCTION C_TO_K : REAL\nVAR_INPUT\n\tCelsius : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t19. aug 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function converts celsius to kelvin\n*)\n\nC_TO_K := Celsius - phys.T0;\n\n(* revision history\n\nhm\t4. aug 2006\trev 1.0\n\toriginal version\n\nhm\t19. aug 2009\trev 1.1\n\tfixed calculation error\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "DATE_ADD.st", - "source": "FUNCTION DATE_ADD : DATE\nVAR_INPUT\n\tIDATE : DATE;\n\tD : INT;\n\tW : INT;\n\tM : INT;\n\tY : INT;\nEND_VAR\nVAR\n\tmo: INT;\n\tyr : INT;\n\tdm: INT;\nEND_VAR\n\n\n(*\nversion 1.8\t\t22. mar. 2011\nprogrammer \thugo\ntested by\t\toscat\n\ndate_add adds days, weeks, month or years to a date.\nnegative inputs are allowed for subtraction.\n\n*)\n\nDATE_ADD := UDINT_TO_DATE(DATE_TO_UDINT(IDATE) + INT_TO_UDINT(D + W * 7) * UDINT#86400);\nyr := Y + YEAR_OF_DATE(DATE_ADD);\nmo := M + MONTH_OF_DATE(DATE_ADD);\ndm := DAY_OF_MONTH(DATE_ADD);\nWHILE mo > 12 DO\n\tmo := mo - 12;\n\tyr := yr + 1;\nEND_WHILE;\nWHILE mo < 1 DO\n\tmo := mo + 12;\n\tyr := yr - 1;\nEND_WHILE;\nDATE_ADD := SET_DATE(yr, mo, dm);\n\n\n(* revision history\n\nhm 27.12.2006\trev 1.0\n\tnrw module\n\nhm 12.4.2007\t\trev 1.1\n\tcorrected an error while date would be incorrect when year = 0\n\nhm\t1.11.2007\t\trev 1.2\n\tadded int_to_dword stetements to avoid possible overrun with möller ecp4\n\nhm\t22. mar. 2008\trev 1.3\n\tfixed some bugs when month was negative\n\nhm\t7. oct. 2008\trev 1.4\n\tchanged function year to year_of_date\n\tchanged function month to month_of_date\n\nhm\t29. mar. 2009\trev 1.5\n\timproved performance\n\nhm\t27. jan. 2011\trev 1.6\n\tfaster code\n\nhm\t2. feb. 2011\t\trev 1.7\n\tfixed an error, weeks not calculated\n\nhm\t22. mar. 2011\trev 1.8\n\tfixed an error in formula\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "DAYS_DELTA.st", - "source": "FUNCTION DAYS_DELTA : DINT\nVAR_INPUT\n\tdate_1 : DATE;\n\tdate_2 : DATE;\nEND_VAR\n\n\n(*\nversion 1.3\t\t25. jan. 2011\nprogrammer \t\thugo\ntested by\t\ttobias\n\ndays_delta calculates the days between two dates. the days are calculated date_2 - date_1.\n\n*)\n\nIF DATE_1 > DATE_2 THEN\n\tDAYS_DELTA := - DWORD_TO_DINT((DATE_TO_DWORD(date_1) - DATE_TO_DWORD(date_2)) / 86400);\nELSE\n\tDAYS_DELTA := DWORD_TO_DINT((DATE_TO_DWORD(date_2) - DATE_TO_DWORD(date_1)) / 86400);\nEND_IF;\n\n(* revision history\nhm\t27. dec 2006\trev 1.0\n\toriginal version\n\nhm\t16.9.2007\t\trev 1.1\n\tcoorected an error in formula and changed algorithm to show positive and negative delta\n\nhm\t22. mar. 2008\trev 1.2\n\tchanged output from int to dint because the total date range is 49710 days\n\nhm\t25. jan. 2011\trev 1.3\n\timproved performance\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "DAYS_IN_MONTH.st", - "source": "FUNCTION DAYS_IN_MONTH : INT\nVAR_INPUT\n\tIDATE : DATE;\nEND_VAR\n\n\n(*\nversion 1.0\t27. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nreturs the total days of the current month. e.g. 31 for january.\nthe function works for dates from 1970 - 2099\n\n*)\n\nDAYS_IN_MONTH := DAY_OF_YEAR(IDATE);\nIF LEAP_OF_DATE(IDATE) THEN\n\tCASE DAYS_IN_MONTH OF\n\t\t32..60\t:\tDAYS_IN_MONTH := 29;\n\t\t92..121 :\tDAYS_IN_MONTH := 30;\n\t\t153..182:\tDAYS_IN_MONTH := 30;\n\t\t245..274:\tDAYS_IN_MONTH := 30;\n\t\t306..335:\tDAYS_IN_MONTH := 30;\n\tELSE\n\t\tDAYS_IN_MONTH := 31;\n\tEND_CASE;\nELSE\n\tCASE DAYS_IN_MONTH OF\n\t\t32..59\t:\tDAYS_IN_MONTH := 28;\n\t\t91..120 :\tDAYS_IN_MONTH := 30;\n\t\t152..181:\tDAYS_IN_MONTH := 30;\n\t\t244..273:\tDAYS_IN_MONTH := 30;\n\t\t305..334:\tDAYS_IN_MONTH := 30;\n\tELSE\n\t\tDAYS_IN_MONTH := 31;\n\tEND_CASE;\nEND_IF;\n\n\n\n(* revision history\nhm\t27. mar. 2009\t\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "DAYS_IN_YEAR.st", - "source": "FUNCTION DAYS_IN_YEAR : INT\nVAR_INPUT\n\tIDATE : DATE;\nEND_VAR\n\n\n(*\nversion 1.0\t27. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nreturs the total days of the year.\nthe function retruns 366 for leap years and 365 otherwise.\nthe function works for dates from 1970 - 2099\n\n\n*)\n\nIF LEAP_OF_DATE(IDATE) THEN\n\tDAYS_IN_YEAR := 366;\nELSE\n\tDAYS_IN_YEAR := 365;\nEND_IF;\n\n\n(* revision history\nhm\t27. mar. 2009\t\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "DAY_OF_DATE.st", - "source": "FUNCTION DAY_OF_DATE : DINT\nVAR_INPUT\n\tidate : DATE;\nEND_VAR\n\n\n(*\n\tversion 1.3\t7. apr. 2008\n\tprogrammer \toscat\n\ttested BY\toscat\n\nDAY_OF_DATE returns the days since 1.1.1970\n\n*)\n\nDAY_OF_DATE := DWORD_TO_DINT(DATE_TO_DWORD(idate) / 86400);\n\n\n(* revision history\nhm\t\t16.9.2007\t\trev 1.0\n\toriginal version\n\nhm\t\t1. okt 2007\t\trev 1.1\n\tadded step7 compatibility\n\nhm\t\t22. mar. 2008\trev 1.2\n\tchanged output from int to Dint because the total date range is 49710 days\n\nhm\t\t7. apr. 2008\trev 1.3\n\tdeleted unused step7 code\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "DAY_OF_MONTH.st", - "source": "FUNCTION DAY_OF_MONTH : INT\nVAR_INPUT\n\tIDATE : DATE;\nEND_VAR\nVAR\n\tleap: INT;\nEND_VAR\n\n(*\nversion 2.1\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nreturns the day OF month for any DATE\n\n*)\n\n(* calculate the day in the year *)\nDAY_OF_MONTH := DAY_OF_YEAR(idate);\n(* leap will be set to one for a leap year *)\nleap := BOOL_TO_INT(LEAP_OF_DATE(idate));\n(* if leap year deduct one from the days of the year *)\nDAY_OF_MONTH := DAY_OF_MONTH - leap;\n(* search if we are in month december to march ? *)\nIF DAY_OF_MONTH > setup.MTH_OFS[9] THEN\n\tIF DAY_OF_MONTH > setup.MTH_OFS[11] THEN\n\t\tIF DAY_OF_MONTH > setup.mth_ofs[12] THEN\n\t\t\tDAY_OF_MONTH := DAY_OF_MONTH - setup.MTH_OFS[12];\n\t\tELSE\n\t\t\tDAY_OF_MONTH := DAY_OF_MONTH - setup.MTH_OFS[11];\n\t\tEND_IF;\n\tELSE\n\t\tIF DAY_OF_MONTH > setup.mth_ofs[10] THEN\n\t\t\tDAY_OF_MONTH := DAY_OF_MONTH - setup.MTH_OFS[10];\n\t\tELSE\n\t\t\tDAY_OF_MONTH := DAY_OF_MONTH - setup.MTH_OFS[9];\n\t\tEND_IF;\n\tEND_IF;\nELSIF DAY_OF_MONTH > setup.MTH_OFS[5] THEN\n\tIF DAY_OF_MONTH > setup.MTH_OFS[7] THEN\n\t\tIF DAY_OF_MONTH > setup.mth_ofs[8] THEN\n\t\t\tDAY_OF_MONTH := DAY_OF_MONTH - setup.MTH_OFS[8];\n\t\tELSE\n\t\t\tDAY_OF_MONTH := DAY_OF_MONTH - setup.MTH_OFS[7];\n\t\tEND_IF;\n\tELSE\n\t\tIF DAY_OF_MONTH > setup.mth_ofs[6] THEN\n\t\t\tDAY_OF_MONTH := DAY_OF_MONTH - setup.MTH_OFS[6];\n\t\tELSE\n\t\t\tDAY_OF_MONTH := DAY_OF_MONTH - setup.MTH_OFS[5];\n\t\tEND_IF;\n\tEND_IF;\nELSIF DAY_OF_MONTH > setup.MTH_OFS[3] THEN\n\tIF DAY_OF_MONTH > setup.MTH_OFS[4] THEN\n\t\tDAY_OF_MONTH := DAY_OF_MONTH - setup.MTH_OFS[4];\n\tELSE\n\t\tDAY_OF_MONTH := DAY_OF_MONTH - setup.MTH_OFS[3];\n\tEND_IF;\nELSE\n\t(* since now we must be in february or january we need to add leap again *)\n\tDAY_OF_MONTH := DAY_OF_MONTH + leap;\n\tIF DAY_OF_MONTH > setup.MTH_OFS[2] THEN DAY_OF_MONTH := DAY_OF_MONTH - setup.mth_ofs[2]; END_IF;\n\t(* since nothing was true before, day_of_month must already be good *)\nEND_IF;\n\n\n(*\nRevision history\n\nhm 22.1.2007\t\trev 1.1\n\tdeleted unused variable day_in_year and day_in_year_begin\n\nhm\t1. okt 2007\trev 1.2\n\tchanged code to use day_of_year and leap_of_date\n\tadded compatibility to STEP7\n\nhm\t8. oct 2007\trev 1.3\n\tdeleted unused variable yr\n\nhm\t8. jan 2008\trev 1.4\n\timproved performance\n\nhm\t25. oct. 2008\trev 2.0\n\tnew code using setup constants\n\nhm\t10. mar. 2009\trev 2.1\n\tremoved nested comments\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "DAY_OF_WEEK.st", - "source": "FUNCTION DAY_OF_WEEK : INT\nVAR_INPUT\n\tIDATE : DATE;\nEND_VAR\n\n\n(*\nversion 1.4\t7. oct. 2008\nprogrammer \thugo\ntested by\ttobias\n\ncalculates the weekday of a week according to ISO8601 \nmonday = 1 ..... sunday = 7 \n\n*)\n\nDAY_OF_WEEK := DWORD_TO_INT((DATE_TO_DWORD(idate) / 86400 + 3) MOD 7) + 1;\n\n\n(* revision history\nhm \t21.8.06 \t\trev 1.1\n\tcorrected a miscalculation\n\nhm\t23.12.2007\t\trev 1.2\n\tcorrection for step7\n\nhm\t7. apr. 2008\trev 1.3\n\tdeleted unused step7 code\n\nhm\t7. oct. 2008\trev 1.4\n\tchanged name of function from weekday to day_of_week\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "DAY_OF_YEAR.st", - "source": "FUNCTION DAY_OF_YEAR : INT\nVAR_INPUT\n\tIDATE : DATE;\nEND_VAR\n\n\n(*\nversion 1.4\t\t28. jan. 2011\nprogrammer \thugo\ntested by\t\toscat\n\ncalculates the day of the year\n\n*)\n\nDAY_OF_YEAR := UDINT_TO_INT((DATE_TO_UDINT(idate) / UDINT#86400) MOD UDINT#1461);\nIF DAY_OF_YEAR > 729 THEN\n\tIF DAY_OF_YEAR > 1095 THEN DAY_OF_YEAR := DAY_OF_YEAR - 1095; ELSE DAY_OF_YEAR := DAY_OF_YEAR - 729; END_IF;\nELSIF DAY_OF_YEAR > 364 THEN\n\tDAY_OF_YEAR := DAY_OF_YEAR - 364;\nELSE\n\tDAY_OF_YEAR := DAY_OF_YEAR + 1;\nEND_IF;\n\n\n(*\nDAY_OF_YEAR := DWORD_TO_INT((DATE_TO_DWORD(idate) - DATE_TO_DWORD(YEAR_BEGIN(YEAR_OF_DATE(idate)))) / 86400) + 1;\n*)\n\n\n(* revivision history\nhm\t4. aug. 2007\t\trev 1.0\n\toriginal version\n\nhm\t1. oct. 2007\t\trev 1.1\n\tadded compatibility to STEP7\n\nhm\t4. jan. 2008\t\trev 1.2\n\tchanged code for better performance\n\nhm\t7. oct. 2008\t\trev 1.3\n\tchanged name of function year to year_of_date\n\nhm\t28. jan. 2011\trev 1.4\n\timproved code\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "DAY_TO_TIME.st", - "source": "FUNCTION DAY_TO_TIME : TIME\nVAR_INPUT\n\tIN : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t24. feb. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nconverts an amount of days in real to time \n*)\n\nDAY_TO_TIME := DWORD_TO_TIME(REAL_TO_DWORD(IN * 86400000.0));\n\n\n(* revision history\nhm\t4. aug. 2006\trev 1.0\n\toriginal release\n\nhm\t24. feb. 2009\trev 1.1\n\trenamed input to IN\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "DCF77.st", - "source": "FUNCTION_BLOCK DCF77\nVAR_INPUT\n\tREC : BOOL;\n\tSET : BOOL;\n\tSDT : DT;\n\tDSI : BOOL;\nEND_VAR\nVAR_INPUT CONSTANT\n\tSYNC_TIMEOUT : TIME := t#2m;\n\tTIME_OFFSET : INT := 1;\n\tDST_EN : BOOL := TRUE;\nEND_VAR\nVAR_OUTPUT\n\tTP : BOOL;\n\tDS : BOOL;\n\tWDAY : INT;\n\tERROR : BOOL := TRUE;\n\tRTC : DT;\n\tRTC1 : DT;\n\tMSEC : INT;\n\tSYNC : BOOL;\nEND_VAR\nVAR\n\tmez : DT;\n\tutc : DT;\n\tstate : INT;\n\tedge: BOOL;\n\ttx : TIME;\n\tty: TIME;\n\tlast : TIME;\n\tbits : ARRAY[0..58] OF BOOL;\n\tcnt : INT;\n\ti : INT;\n\told_time : DT;\n\tminute : INT;\n\thour : INT;\n\tday : INT;\n\tmonth : INT;\n\tyear : INT;\n\tlast_sync: TIME;\n\tt1: TIME;\n\ttz: TIME;\n\tinit: BOOL;\nEND_VAR\n\n\n(*\nversion 1.10\t7. oct. 2008\nprogrammer \thugo\ntested by\toscat\n\nthis is a decoder for a DCF77 signal.\nthe decoder decodes the DCF77 signal and checks for a valid Date_Time.\nsince the dcf77 signal is only secured with a simple parity the decoder waits for two consecutive valid transmissions before it sets the output signals.\ngiven a valid reception by the receiver the decoder can take up to 3 minutes to start its clocks the first time.\nafter a valid signal is detected the error output goes low and dignals a valid dcf signal from the receiver.\na tp is only valid for one program cycle to allow for external rtc setting.\nafter a valid signal is detected two independent internal clocks are started (RTC and RTC1), the seconds of these clocks are generated by software since the dcf signal is only valid for minutes.\nrtc is always utc ( world time) and rtc1 can be set to any time zone by setting the time_zone_offset and enabling dst for automatic summertime.\na sync output signals the the rtc and rtc1 are in sync with the dcf77 signal, if the dcf77 signal is lost for more then the sync time the sync output goes low\nbut the rtc and rtc1 outputs keep running based on software timing until a valid dcf77 signal is received again and triggers the clock.\nin addition a millisecond output gives further resolutionof the clocks.\na dst output shows if daylight saving time is enables and the weekday output shows which day of week currently is ( 1= monday ... 7= sunday).\n\n*)\n\n(* if tp was set it should only be active for 1 cycle *)\nTP := FALSE;\n\n(* read system time *)\nt1 := DWORD_TO_TIME(T_PLC_MS());\ntx := t1 - last;\n\nIF rec XOR edge THEN\n\tedge := rec;\n\tIF NOT rec AND tx > t#1700ms AND tx < t#2000ms THEN\n\t\t(* start condition reached *)\n\t\tstate := 0;\n\t\ttp := NOT error;\n\tELSIF NOT rec AND tx > t#700ms AND tx < t#1000ms THEN\n\t\t(* second switch detected *)\n\t\tIF state < 58 THEN state := state +1; ELSE state := 0; END_IF;\n\tELSIF rec AND tx < t#120ms THEN\n\t\t(* bit 0 detected *)\n\t\tbits[state] := 0;\n\tELSIF rec AND tx > t#120ms AND tx < t#250ms THEN\n\t\t(* bit 1 detected *)\n\t\tbits[state] := 1;\n\tELSE\n\t\t(* error condition received signal is not valid *)\n\t\terror := TRUE;\n\t\tstate := 0;\n\tEND_IF;\n\tlast := last + tx;\n\tIF rec AND state = 58 THEN\n\t\terror := FALSE;\n\n\t\t(* decode the bits and check for possible errors *)\n\t\tIF bits[0] OR NOT (bits[17] XOR bits[18]) OR NOT bits[20] THEN error := TRUE; END_IF;\n\t\t(* decode minute *)\n\t\tMINUTE := 0;\n\t\tMINUTE.0 := bits[21];\n\t\tMINUTE.1 := bits[22];\n\t\tMINUTE.2 := bits[23];\n\t\tMINUTE.3 := bits[24];\n\t\tIF bits[25] THEN MINUTE := MINUTE + 10; END_IF;\n\t\tIF bits[26] THEN MINUTE := MINUTE + 20; END_IF;\n\t\tIF bits[27] THEN MINUTE := MINUTE + 40; END_IF;\n\t\tIF MINUTE > 59 OR (bits[21] XOR bits[22] XOR bits[23] XOR bits[24] XOR bits[25] XOR bits[26] XOR bits[27] XOR bits[28]) THEN error := TRUE; END_IF;\n\n\t\t(* decode hour *)\n\t\tHOUR := 0;\n\t\tHOUR.0 := bits[29];\n\t\tHOUR.1 := bits[30];\n\t\tHOUR.2 := bits[31];\n\t\tHOUR.3 := bits[32];\n\t\tIF bits[33] THEN HOUR := HOUR + 10; END_IF;\n\t\tIF bits[34] THEN HOUR := HOUR +20; END_IF;\n\t\tIF HOUR > 23 OR (bits[29] XOR bits[30] XOR bits[31] XOR bits[32] XOR bits[33] XOR bits[34] XOR bits[35]) THEN error := TRUE; END_IF;\n\n\t\t(* decode day of month *)\n\t\tday := 0;\n\t\tday.0 := bits[36];\n\t\tday.1 := bits[37];\n\t\tday.2 := bits[38];\n\t\tday.3 := bits[39];\n\t\tIF bits[40] THEN day := day + 10; END_IF;\n\t\tIF bits[41] THEN day := day + 20; END_IF;\n\t\tIF day > 31 THEN error := TRUE; END_IF;\n\n\t\t(* decode day of week *)\n\t\twday := 0;\n\t\twday.0 := bits[42];\n\t\twday.1 := bits[43];\n\t\twday.2 := bits[44];\n\t\tIF wday > 7 OR wday < 1 THEN error := TRUE; END_IF;\n\n\t\t(* decode month *)\n\t\tMONTH := 0;\n\t\tMONTH.0 := bits[45];\n\t\tMONTH.1 := bits[46];\n\t\tMONTH.2 := bits[47];\n\t\tMONTH.3 := bits[48];\n\t\tIF bits[49] THEN MONTH := MONTH +10; END_IF;\n\t\tIF MONTH > 12 THEN error := TRUE; END_IF;\n\n\t\t(* decode year *)\n\t\tYEAR := 0;\n\t\tYEAR.0 := bits[50];\n\t\tYEAR.1 := bits[51];\n\t\tYEAR.2 := bits[52];\n\t\tYEAR.3 := bits[53];\n\t\tIF bits[54] THEN YEAR := YEAR + 10; END_IF;\n\t\tIF bits[55] THEN YEAR := YEAR + 20; END_IF;\n\t\tIF bits[56] THEN YEAR := YEAR + 40; END_IF;\n\t\tIF bits[57] THEN YEAR := YEAR + 80; END_IF;\n\n\t\t(* check parity for bits 36 to 58 *)\n\t\tcnt := 0;\n\t\tFOR i := 36 TO 58 DO IF bits[i] THEN cnt := cnt + 1; END_IF; END_FOR;\n\t\tIF NOT EVEN(cnt) THEN error := TRUE; END_IF;\n\n\t\t(* time must be valid for two cycles to clear error flag *)\n\t\tIF NOT error THEN\n\t\t\t(* set outputs *)\n\t\t\told_time := mez;\n\t\t\tIF YEAR >= 70 THEN YEAR := YEAR + 1900; ELSE YEAR := YEAR + 2000; END_IF;\n\t\t\tmez := SET_DT(YEAR,MONTH,day,HOUR,MINUTE,0);\n\t\t\tDS := bits[17];\n\t\t\tIF DS THEN\n\t\t\t\tUTC := DWORD_TO_DT(DT_TO_DWORD(mez) - 7200);\n\t\t\tELSE\n\t\t\t\tUTC := DWORD_TO_DT(DT_TO_DWORD(mez) - 3600);\n\t\t\tEND_IF;\n\n\t\t\t(* set trigger signal only if the receiver has received 2 successive minutes *)\n\t\t\tIF mez <> old_time + t#1m THEN error := TRUE ; END_IF;\n\t\tEND_IF;\n\tEND_IF;\nEND_IF;\n\n(* this portion implements a free running clock which is triggered by the dcf77 signal *)\ntz := DWORD_TO_TIME(INT_TO_DWORD(ABS(time_offset))* 3600000);\n\n(* input sdt is copied to utc at first power up *)\nIF NOT init OR SET THEN\n\tinit := TRUE;\n\tutc := sdt;\n\ttp := TRUE;\n\tDS := DSI;\nEND_IF;\n\nIF tp THEN\n\trtc := utc;\n\tIF DS AND dst_en THEN\n\t\tIF time_offset < 0 THEN\trtc1 := rtc - tz + t#1h; ELSE rtc1 := rtc + tz + t#1h; END_IF;\n\tELSE\n\t\tIF time_offset < 0 THEN rtc1 := rtc - tz; ELSE rtc1 := rtc + tz; END_IF;\n\tEND_IF;\n\tsync := TRUE;\n\tlast_sync := last;\n\tty := last;\nELSIF rtc > DWORD_TO_DT(0) AND T1 - ty >= t#1s THEN\n\trtc := rtc + t#1s;\n\trtc1 := rtc1 + t#1s;\n\tty := ty + t#1s;\n\tsync := ty - last_sync < sync_timeout AND last_sync > DWORD_TO_TIME(0);\n\twday := DAY_OF_WEEK(DT_TO_DATE(rtc1));\n\tDS := dst_en AND DST(utc);\nEND_IF;\nmsec := TIME_TO_INT(t1 - ty);\n\n\n\n(* decode information\nbits\t\tcontent\n0\t\t\tBitwert immer 0\n1 bis 14\treserviert für Betriebsinformationen (nicht für DCF77-Nutzer bestimmt)\n15\t\t\tRufbit für Alarmierung der PTB-Mitarbeiter\n\t\t\t(bis Mai 2003: Bitwert = 0 falls normale Antenne in Verwendung; 1 = Backupantenne)\n16\t\t\tBitwert = 1 falls ein Wechsel von MEZ nach MESZ oder umgekehrt bevorsteht; Dauer der Anzeige: 1 Stunde\n17 + 18\tgültige Zeit = MEZ, falls Bit 17=0 und Bit 18=1\n\t\t\tgültige Zeit = MESZ, falls Bit 17=1 und Bit 18=0\n19\t\t\tBitwert = 1 falls innerhalb den nächsten 59 Minuten eine Schaltsekunde angeordnet ist. Beim Einfügen einer Schaltsekunde wird anstelle der 59. die 60. Sekundenmarke weggelassen und in der 58. erfolgt ausnahmsweise ein Trägerabfall.\n20\t\t\tStartbit für Zeitinformation (immer 1)\n21 - 27\t\t1, 2, 4, 8, 10, 20, 40 Minuten (bitweise Addition)\n28\t\t\tPrüfbit (gerade Parität) für die Bits 21-27\n29 - 34\t\t1, 2, 4, 8, 10, 20 Stunden (bitweise Addition)\n35\t\t\tPrüfbit (gerade Parität) für die Bits 29-34\n36 - 41\t\tTagesnummer im aktuellen Monat: 1, 2, 4, 8, 10, 20 (bitweise Addition)\n42 - 44\t\tTagesnummer in der aktuellen Woche: 1, 2, 4 (bitweise Addition)\n45 - 49\t\tMonatsnummer: 1, 2, 4, 8, 10 (bitweise Addition)\n50 - 57\t\tJahr (zweistellig): 1, 2, 4, 8, 10, 20, 40, 80 (bitweise Addition)\n58\t\t\tPrüfbit (gerade Parität) füR die Bits 36-57\n\n*)\n(* revision history\n\nhm 2.feb 2007\t\trev 1.1\n\tchange wday and dst outputs when there is no dcf reception\n\nhm\t26.feb 2007\t\trev 1.2\n\tchanged statements where t#1h would be substracted from DT.\n\tunder certain conditions the compiler would crash translating this statement\n\nhm\t17. sep 2007\trev 1.3\n\treplaced time() with T_PLC_MS() for compatibility reasons\n\nhm\t24. oct 2007\t\trev 1.4\n\tchanged dst calculation because function dst was upgraded no error in DCF77 only a change in DST\n\nhm\t12. nov 2007\t\trev 1.5\n\tchanged time_offset from time to integer to allow for negative offset time zones\n\nhm\t8. dec 2007\t\trev 1.6\n\tcorrected an error in time_zone calculation\n\nhm 23. jan 2008\t\trev 1.7\n\tadded sdt input which is used to initialize rtc and rtc1 during first cycle.\n\nhm 16. mar 2008\t\trev 1.8\n\tchanged output weekday to wday and dst to ds for compatibility reasons\n\nhm\t19. apr. 2008\trev 1.9\n\tadded input dsi to allow to set daylight savings time when SDT is TRUE.\n\tadded asynchronous SET input\n\nhm\t7. oct. 2008\trev 1.10\n\tchanged function weekday to day_of_week\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "DEAD_BAND.st", - "source": "FUNCTION DEAD_BAND : REAL\nVAR_INPUT\n\tX : REAL;\n\tL : REAL;\nEND_VAR\n\n\n(*\nversion 1.2\t18. jan. 2011\nprogrammer \thugo\ntested by\t\toscat\n\nDEAD_BAND ist eine lineare Übertragungsfunktion mit Totzone. Die Funktion verschiebt den positiven Teil der Kurve um +L und den negativen Teil der Kurve um -L.\nDEAD_BAND = X - L wenn X > L)\nDEAD_BAND = X + L wenn X < -L\nDEAD_BAND = 0 wenn Abs(X) <= L\n\n*)\n\nIF X > L THEN\n\tDEAD_BAND := X - L;\nELSIF X < -L THEN\n\tDEAD_BAND := X + L;\nELSE\n\tDEAD_BAND := 0.0;\nEND_IF;\n\n\n(* revision history\nhm\t2. nov. 2007\trev 1.0\n\toriginal version\n\nhm\t14. jun. 2008\trev 1.1\n\timproved performance\n\nhm\t18. jan. 2011\trev 1.2\n\tassign 0 before return\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "DEAD_BAND_A.st", - "source": "FUNCTION_BLOCK DEAD_BAND_A\nVAR_INPUT\n\tX : REAL;\n\tT : TIME;\n\tKL : REAL := 1.0;\n\tLM : REAL;\nEND_VAR\nVAR_OUTPUT\n\tY : REAL;\n\tL : REAL;\nEND_VAR\nVAR\n\ttp1 : FT_PT1;\n\ttp2 : FT_PT1;\nEND_VAR\n\n\n(*\nversion 1.1\t11. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nDEAD_BAND ist eine lineare Übertragungsfunktion mit Totzone. Die Funktion verschiebt den positiven Teil der Kurve um -L und den negativen Teil der Kurve um +L.\nDEAD_BAND = X wenn Abs(X) > L wenn Abs(X) > L\nDEAD_BAND = 0 wenn Abs(X) <= L\nDie Breite der Totzone wird automatisch aus dem Signalrauschen errechnet.\n\n*)\n\n(* filter the input signal *)\ntp1(in := X, T:= T);\n\n(* filter the HF portion to generate a stable L *)\ntp2(in := ABS(tp1.out - X), T := MULTIME(T, 4.0));\n\n(* now we determine L which is half the width of the dead band *)\nL := MIN(KL * tp2.out, LM);\n\nIF X > L THEN\n\tY := X - L;\nELSIF X < -L THEN\n\tY := X + L;\nELSE\n\tY := 0.0;\nEND_IF;\n\n\n(* revision history\nhm\t14. jun. 2008\trev 1.0\n\toriginal version\n\nhm\t11. mar. 2009\trev 1.1\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "DEAD_ZONE.st", - "source": "FUNCTION DEAD_ZONE : REAL\nVAR_INPUT\n\tX : REAL;\n\tL : REAL;\nEND_VAR\n\n\n(*\nversion 1.2\t11. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\ndead_zone2 is a linear transfer function which follows a linear function except for x is close to 0.\nY = X if abs(x) > L otherwise its 0.\n\n*)\n\nIF ABS(x) > L THEN\n\tdead_zone := X;\nELSE\n\tDEAD_ZONE := 0.0;\nEND_IF;\n\n(* revision history\nhm\t12. feb. 2007\trev 1.0\n\toriginal version\n\nhm\t14. jun. 2008\trev 1.1\n\timproved performance\n\nhm\t11. mar. 2009\trev 1.2\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "DEAD_ZONE2.st", - "source": "FUNCTION_BLOCK DEAD_ZONE2\nVAR_INPUT\n\tX : REAL;\n\tL : REAL;\nEND_VAR\nVAR_OUTPUT\n\tY: REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t11. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\ndead_zone2 is a linear transfer function which follows a linear function except for x is close to 0.\nY = X if abs(x) > L.\nfor values of 0 +/- L a hysteresis function will hold the output at + or - L.\n\n*)\n\nIF ABS(x) > L THEN\n\tY := X;\nELSIF Y > 0.0 THEN\n\tY := L;\nELSE\n\tY := -L;\nEND_IF;\n\n\n\n(* revision history\n\nhm\t12. feb. 2007\trev 1.0\n\toriginal version\n\nhm\t11. mar. 2009\trev 1.1\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "DEC1.st", - "source": "FUNCTION DEC1 : INT\nVAR_INPUT\n\tX : INT;\n\tN : INT;\nEND_VAR\n\n\n(*\nversion 1.1\t27. oct. 2008\nprogrammer \thugo\ntested by\toscat\n\nThis is a decrement function which decrements the variable X by 1 and if 0 is reached, it begins with N-1 again.\n_dec1(X,3) will generate 2,1,0,2,...\n\n*)\n\nIF X = 0 THEN\n\tDEC1 := N - 1;\nELSE\n\tDEC1 := X - 1;\nEND_IF;\n\n\n(* this is a very elegant version but 50% slower\nX := (X - 1 + N) MOD N;\n*)\n\n\n(* revision history\nhm\t13. oct. 2008\trev 1.0\n\toriginal version\n\nhm\t27. oct. 2008\trev 1.1\n\tadded statement to return value for compatibility reasons\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "DEC_2.st", - "source": "FUNCTION_BLOCK DEC_2\nVAR_INPUT\n\tD: BOOL;\n\tA: BOOL;\nEND_VAR\nVAR_OUTPUT\n\tQ0: BOOL;\n\tQ1: BOOL;\nEND_VAR\n\n\n(*\nversion 1.1\t3 Mar 2007\nprogrammer \thugo\ntested by\t\ttobias\n\na bit input will be decoded to the two outputs Q0 or Q1\ndependent on the value of A\nA=0 decodes to Q0 and A=1 decodes to Q1\n\n*)\n\nQ0 := D AND NOT A;\nQ1 := D AND A;\n\n(* revision history\nhm 3.3.2007\trev 1.1\n\trewritten in ST for better compatibility\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "DEC_4.st", - "source": "FUNCTION_BLOCK DEC_4\nVAR_INPUT\n\tD: BOOL;\n\tA0: BOOL;\n\tA1: BOOL;\nEND_VAR\nVAR_OUTPUT\n\tQ0: BOOL;\n\tQ1: BOOL;\n\tQ2: BOOL;\n\tQ3: BOOL;\nEND_VAR\n\n\n(*\nversion 1.1\t3 Mar 2007\nprogrammer \thugo\ntested by\t\ttobias\n\na bit input will be decoded to one of the 4 outputs\ndependent on the Adress on A0 and A1\n\nexecutioin TIME on wago 750-841 = 9us\n*)\n\nQ0 := D AND NOT A0 AND NOT A1;\nQ1 := D AND A0 AND NOT A1;\nQ2 := D AND NOT A0 AND A1;\nQ3 := D AND A0 AND A1;\n\n(* revision history\nhm 3.3.2007\trev 1.1\n\trewritten in ST for better compatibility\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "DEC_8.st", - "source": "FUNCTION_BLOCK DEC_8\nVAR_INPUT\n\tD: BOOL;\n\tA0: BOOL;\n\tA1: BOOL;\n\tA2: BOOL;\nEND_VAR\nVAR_OUTPUT\n\tQ0: BOOL;\n\tQ1: BOOL;\n\tQ2: BOOL;\n\tQ3: BOOL;\n\tQ4: BOOL;\n\tQ5: BOOL;\n\tQ6: BOOL;\n\tQ7: BOOL;\nEND_VAR\nVAR\n\tX : INT;\nEND_VAR\n\n(*\nversion 1.3\t28. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\na bit input will be decoded to one of the 8 outputs\ndependent on the Adress on A0, A1 and A2\n\n\n*)\n\nX.0 := A0; X.1 := A1; X.2 := A2;\n\nQ0 := FALSE;\nQ1 := FALSE;\nQ2 := FALSE;\nQ3 := FALSE;\nQ4 := FALSE;\nQ5 := FALSE;\nQ6 := FALSE;\nQ7 := FALSE;\n\nCASE X OF\n\t0 : Q0 := D;\n\t1 : Q1 := D;\n\t2 : Q2 := D;\n\t3 : Q3 := D;\n\t4 : Q4 := D;\n\t5 : Q5 := D;\n\t6 : Q6 := D;\n\t7 : Q7 := D;\nEND_CASE;\n\n\n\n(* revision history\nhm 3. mar. 2007\trev 1.1\n\trewritten in ST for better compatibility\n\nhm\t26. oct. 2008\trev 1.2\n\tcode optimized\n\nhm\t28. mar. 2009\trev 1.3\n\treplaced multiple assignments\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "DEC_TO_BYTE.st", - "source": "FUNCTION DEC_TO_BYTE : BYTE\nVAR_INPUT\n\tDEC : STRING(10);\nEND_VAR\nVAR\n\tpt : POINTER TO BYTE;\n\ti: INT;\n\tX: BYTE;\n\tstop: INT;\nEND_VAR\n\n(*\nversion 1.1\t30. sep 2008\nprogrammer \thugo\ntested by\t\toscat\n\nDEC_TO_byte converts a decimal string into a byte.\n\n*)\n\npt := ADR(dec);\nstop := LEN(DEC);\nFOR I := 1 TO stop DO\n\t(* read the first character and subtract 48 to get value in decimal 0 = 48 *)\n\tx := pt^;\n\t(* calculate the value of the digit *)\n\tIF X > 47 AND x < 58 THEN\n\t\tDEC_TO_BYTE := DEC_TO_BYTE * 10 + X - 48;\n\tEND_IF;\n\tpt := pt + 1;\nEND_FOR;\n\n\n\n(* revision histroy\nhm\t20. jun. 2008\trev 1.0\n\toriginal release\n\nhm\t30. sep.2008\trev 1.1\n\tchanged length of input string from 20 to 10\n\tcorrected an error where decoding of characters 8 and 9 would fail\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "DEC_TO_DWORD.st", - "source": "FUNCTION DEC_TO_DWORD : DWORD\nVAR_INPUT\n\tDEC : STRING(20);\nEND_VAR\nVAR\n\tpt : POINTER TO BYTE;\n\ti: INT;\n\tX: BYTE;\n\tstop: INT;\nEND_VAR\n\n(*\nversion 1.1\t30. sep. 2008\nprogrammer \thugo\ntested by\t\toscat\n\nDEC_TO_DWORD converts a decimal string into a DWORD.\n\n*)\n\npt := ADR(dec);\nstop := LEN(dec);\nFOR I := 1 TO stop DO\n\t(* read the first character and subtract 48 to get value in decimal 0 = 48 *)\n\tx := pt^;\n\t(* calculate the value of the digit *)\n\tIF X > 47 AND x < 58 THEN\n\t\tDEC_TO_DWORD := DEC_TO_DWORD * 10 + X - 48;\n\tEND_IF;\n\tpt := pt + 1;\nEND_FOR;\n\n\n\n(* revision histroy\nhm\t20. jun. 2008\trev 1.0\n\toriginal release\n\nhm\t30. sep. 2008\trev 1.1\n\tcorrected an error where decoding of characters 8 and 9 would fail\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "DEC_TO_INT.st", - "source": "FUNCTION DEC_TO_INT : INT\nVAR_INPUT\n\tDEC : STRING(10);\nEND_VAR\nVAR\n\tpt : POINTER TO BYTE;\n\ti: INT;\n\tX: BYTE;\n\tsign: BOOL;\n\tstop: INT;\nEND_VAR\n\n(*\nversion 1.1\t30. sep. 2008\nprogrammer \thugo\ntested by\toscat\n\nDEC_TO_INT converts a decimal string into an Integer.\n\n*)\n\npt := ADR(dec);\nstop := LEN(dec);\nFOR I := 1 TO stop DO\n\t(* read the first character and subtract 48 to get value in decimal 0 = 48 *)\n\tx := pt^;\n\t(* calculate the value of the digit *)\n\tIF X > 47 AND x < 58 THEN\n\t\tDEC_TO_INT := DEC_TO_INT * 10 + X - 48;\n\tELSIF X = 45 AND DEC_TO_INT = 0 THEN\n\t\tsign := TRUE;\n\tEND_IF;\n\tpt := pt + 1;\nEND_FOR;\nIF sign THEN DEC_TO_INT := -DEC_TO_INT; END_IF;\n\n\n(* revision histroy\nhm\t20. jun. 2008\trev 1.0\n\toriginal release\n\nhm\t30. sep. 2008\trev 1.1\n\tchanged length of input string from 20 to 10\n\tcorrected an error where decoding of characters 8 and 9 would fail\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "DEG.st", - "source": "FUNCTION DEG : REAL\nVAR_INPUT\n\trad : REAL;\nEND_VAR\n\n\n(*\nversion 1.2\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function converts degrees into Radiant\nexecution time on wago 750 - 841 = 10 us\n*)\n\nDEG := MODR(57.29577951308232 * RAD, 360.0);\n\n(* revision history\nhm\t4. aug 2006\trev 1.0\n\toriginal version\n\nhm 16. oct 2007\trev 1.1\n\tadded modr statement which prohibits deg to become bigger than 360\n\nhm\t10. mar. 2009\trev 1.2\n\treal constants updated to new systax using dot\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "DEG_TO_DIR.st", - "source": "FUNCTION DEG_TO_DIR : STRING(3)\nVAR_INPUT\n\tDEG : INT;\n\tN : INT;\n\tL : INT;\nEND_VAR\nVAR\n\tly: INT;\nEND_VAR\n\n\n(*\nversion 1.1\t22. oct. 2008\nprogrammer \thugo\ntested by\t\toscat\n\nthis function converts degrees in compass direction.\nthe function supports output in english (L=0) and german (L=1).\n\n*)\n\nIF L = 0 THEN ly := LANGUAGE.DEFAULT; ELSE ly := MIN(L, LANGUAGE.LMAX); END_IF;\nDEG_TO_DIR := LANGUAGE.DIRS[ly, ((SHL(DEG,N-1) + 45) / 90) MOD SHL(INT#2,N)*SHR(INT#8,N)];\n\n\n\n(*\nDIR := ((SHL(DEG,N-1) + 45) / 90) MOD SHL(INT#2,N);\nexplanation :\nDIR is calculated BY the following formula:\nDIR := ((DIR + 45) / 90) MOD 4 if N = 1 digit\nNorth = 0, East = 1 ....\nDIR := ((DIR + 22,5) / 45) MOD 8 if N = 2 digit\nconvert to integer calculation\nDIR := ((DIR*2 + 45) / 90) MOD 8\nN = 0, NE = 1 ....\nther above formula replaces 2^N with shift for performance\n*)\n\n\n\n(* revision histroy\nhm\t11. jun. 2008\trev 1.0\n\toriginal release\n\nhm\t22. oct. 2008\trev 1.1\n\tchanged size of string variables to 30\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "DELAY.st", - "source": "FUNCTION_BLOCK DELAY\nVAR_INPUT\n\tIN : REAL;\n\tN : INT;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tOUT : REAL;\nEND_VAR\nVAR\n\tbuf : ARRAY[0..31] OF REAL;\n\ti : INT;\n\tinit: BOOL;\n\tstop: INT;\nEND_VAR\n\n(*\nversion 1.5\t23. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nthis function block delays input values by each programm cycle\nafter N+1 cycles the in value has shifted to the out.\nN can be any alue from 0 .. 32\nif n = 0 the input will be present on the output without a delay.\nf N > 32 then the output will be delayed by 32 cycles.\nany high on rst will load the buffer with in.\n\n*)\n\nstop := LIMIT(0,N,32) - 1;\nIF rst OR NOT init THEN\n\tinit := TRUE;\n\tFOR i := 0 TO stop DO buf[i] := in; END_FOR;\n\tout := in;\n\ti := 0;\nELSIF stop < 0 THEN\n\tout := in;\nELSE\n\tout := buf[i];\n\tbuf[i] := in;\n\ti := INC1(i, N);\nEND_IF;\n\n\n\n(* revision history\nhm 1.10.2006\t\trev 1.1\n\tcorrected error in buffer management\n\nhm 19.1.2007\t\trev 1.2\n\tchanged reset to load the value of in instead of 0\n\nhm\t27. oct. 2008\trev 1.3\n\timproved performance\n\nhm\t23. feb.2009\trev 1.4\n\tcorrected an index problem\n\nhm\t23. mar. 2009\trev 1.5\n\tcorrected non standard write to input N\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "DELAY_4.st", - "source": "FUNCTION_BLOCK DELAY_4\nVAR_INPUT\n\tin : REAL;\nEND_VAR\nVAR_OUTPUT\n\tout1 : REAL;\n\tout2 : REAL;\n\tout3 : REAL;\n\tout4 : REAL;\nEND_VAR\nVAR\n\ttemp: REAL;\nEND_VAR\n\n(*\nversion 1.1\t19 jan 2007\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function block delays input values by each programm cycle\nafter 4 cycles the in value has shifted to the out 4 and will be discarded after the next cycle\nthe blocks can be cascaded.\n\n*)\n\nout4 := out3;\nout3 := out2;\nout2 := out1;\nout1 := temp;\ntemp := in;\n\n(* revision history\n\nhm 19.1.2007\trev 1.1\n\tadded variable temp to add 1 delay for q1\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "DEL_CHARS.st", - "source": "FUNCTION DEL_CHARS : STRING(STRING_LENGTH)\nVAR_INPUT\n\tIN : STRING(STRING_LENGTH);\n\tCX : STRING(80);\nEND_VAR\nVAR\n\tpos: INT := 1;\n\tstop: INT;\nEND_VAR\n\n\n(*\nversion 1.0\t18. jun. 2008\nprogrammer \thugo\ntested by\toscat\n\ndel_chars deletes all characters from a string which are specified in CX.\n\n*)\n\n(* copy input string *)\nDEL_CHARS := IN;\nstop := LEN(in);\nWHILE pos <= stop DO\n\tIF FIND(cx, MID(DEL_CHARS, 1, pos)) > 0 THEN\n\t\t(* wrong chracter needs to be deleted *)\n\t\tDEL_CHARS := DELETE(DEL_CHARS, 1, pos);\n\t\tstop := stop - 1;\t(* the string is one character shorter now *)\n\tELSE\n\t\t(* charcter not found skip to next one *)\n\t\tpos := pos + 1;\n\tEND_IF;\nEND_WHILE;\n\n\n\n(* revision history\n\nhm\t\t18. jun. 2008\trev 1.0\t\t\n\toriginal version \n\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "DIFFER.st", - "source": "FUNCTION DIFFER : BOOL\nVAR_INPUT\n\tin1 : REAL;\n\tin2 : REAL;\n\tX : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t16 mar 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function checks if in1 differs more then x from in2\nthe output is true if abs(in1-in2) > X\n\n*)\n\nDIFFER := ABS(in1 - in2) > X;\n\n(* revision history\nhm\t\t8. oct 2006\t\trev 1.0\n\toriginal version\n\nhm\t\t16. mar 2008\trev 1.1\n\timproverd code for performance\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "DIR_TO_DEG.st", - "source": "FUNCTION DIR_TO_DEG : INT\nVAR_INPUT\n\tDIR : STRING(3);\n\tL : INT;\nEND_VAR\nVAR\n\tly: INT;\n\ti : INT;\nEND_VAR\n\n(*\nversion 1.1\t22. oct. 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function converts compass directions to degrees\nit will recognize up to 3 letter directions in english and german writing.\n\n*)\n\nIF L = 0 THEN ly := LANGUAGE.DEFAULT; ELSE ly := MIN(L, LANGUAGE.LMAX); END_IF;\nFOR i := 0 TO 15 DO\n\tIF language.DIRS[ly, i] = DIR THEN EXIT; END_IF;\nEND_FOR;\nDIR_TO_DEG := SHR(i * 45 + 1, 1);\n\n\n\n\n\n\n(* revision histroy\nhm\t22. oct. 2008\trev 1.1\n\toriginal release\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "DRIVER_1.st", - "source": "FUNCTION_BLOCK DRIVER_1\nVAR_INPUT CONSTANT\n\tToggle_Mode : BOOL;\n\tTimeout : TIME;\nEND_VAR\nVAR_INPUT\n\tSET : BOOL;\n\tIN : BOOL;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\nEND_VAR\nVAR\n\toff : TON;\n\tedge: BOOL;\nEND_VAR\n\n(*\nversion 1.0\t2 jan 2008\nprogrammer \thugo\ntested by\t\ttobias\n\ndriver_1 is a multi purpose driver.\na rising edge on in sets the output high if toggle is flase. while toggle is true, a rising edge on in toggles the output Q.\nif a timeout is specified the output q will be reset to false automatically after the timeout has elapsed.\na asynchronous reset and set will force the output high or low respectively.\n\n*)\n\nIF off.Q THEN Q := FALSE; END_IF;\nIF rst THEN\n\tQ := FALSE;\nELSIF set THEN\n\tQ := TRUE;\nELSIF IN AND NOT edge THEN\n\tIF toggle_mode THEN q := NOT Q; ELSE q := TRUE; END_IF;\nEND_IF;\nedge := in;\nIF timeout > t#0s THEN off(in := Q, PT := Timeout); END_IF;\n\n\n(* revision history\nhm\t2. jan 2008\t\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "DRIVER_4.st", - "source": "FUNCTION_BLOCK DRIVER_4\nVAR_INPUT CONSTANT\n\tToggle_Mode : BOOL;\n\tTimeout : TIME;\nEND_VAR\nVAR_INPUT\n\tSET : BOOL;\n\tIN0, IN1, IN2, IN3 : BOOL;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tQ0, Q1, Q2, Q3 : BOOL;\nEND_VAR\nVAR\n\td0, d1, d2, d3 : DRIVER_1;\nEND_VAR\n\n(*\nversion 1.0\t2 jan 2008\nprogrammer \thugo\ntested by\t\ttobias\n\ndriver_4 is a 4 channel multi purpose driver.\na rising edge on in? sets the output Q? high if toggle_mode is flase. while toggle_mode is true, a rising edge on in? toggles the output Q?.\nif a timeout is specified the output Q? will be reset to false automatically after the timeout has elapsed.\na asynchronous reset and set will force the output high or low respectively.\nan asynchronous set will force all outputs high simultaneously\n\n*)\n\nD0(Set:=set, in:=in0, rst:=rst, toggle_mode:=toggle_mode, timeout:=timeout);\nD1(Set:=set, in:=in1, rst:=rst, toggle_mode:=toggle_mode, timeout:=timeout);\nD2(Set:=set, in:=in2, rst:=rst, toggle_mode:=toggle_mode, timeout:=timeout);\nD3(Set:=set, in:=in3, rst:=rst, toggle_mode:=toggle_mode, timeout:=timeout);\nQ0 := D0.Q;\nQ1 := D1.Q;\nQ2 := D2.Q;\nQ3 := D3.Q;\n\n\n(* revision history\nhm\t2. jan 2008\t\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "DRIVER_4C.st", - "source": "FUNCTION_BLOCK DRIVER_4C\nVAR_INPUT\n\tIN : BOOL;\n\tRST : BOOL;\nEND_VAR\nVAR_INPUT CONSTANT\n\tTimeout : TIME;\n\tSX : ARRAY[1..7] OF BYTE := 1,3,7,15;\nEND_VAR\nVAR_OUTPUT\n\tSN : INT;\n\tQ0 : BOOL;\n\tQ1 : BOOL;\n\tQ2 : BOOL;\n\tQ3 : BOOL;\nEND_VAR\nVAR\n\toff : TON;\n\tedge: BOOL;\nEND_VAR\n\n(*\nversion 1.0\t23. mar. 2009\nprogrammer \thugo\ntested by\ttobias\n\ndriver_4C is a multi purpose driver.\na rising edge on in switches from S0 state S1 and the next edge to state S2 and so on.\nin state S0 all outputs Q are FALSE.\nThe stet of the Outputs in any state S? is configurable with setup variables.\nThe variables S1..S5 define the states, while the sequence is terminated when a state Variable S? = 0.\nThe lower bits 0..3 of the state vars S? are corresponding to the Outputs Q0..Q3\n\n*)\n\nIF RST OR off.Q THEN\n\tSN := 0;\nELSIF IN AND NOT edge THEN\n\tSN := SN + 1;\n\tIF SN > 7 OR SX[SN] = 0 THEN SN := 0; END_IF;\nEND_IF;\nedge := in;\nIF SN > 0 THEN\n\tQ0 := SX[SN].0;\n\tQ1 := SX[SN].1;\n\tQ2 := SX[SN].2;\n\tQ3 := SX[SN].3;\nELSE\n\tQ0 := FALSE;\n\tQ1 := FALSE;\n\tQ2 := FALSE;\n\tQ3 := FALSE;\nEND_IF;\n\n(* maximaum timeout *)\nIF timeout > t#0s THEN off(in := SN > 0, PT := Timeout); END_IF;\n\n\n(* revision history\nhm\t23. mar. 2009\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "DST.st", - "source": "FUNCTION DST : BOOL\nVAR_INPUT\n\tUTC : DT;\nEND_VAR\nVAR\n\tyr : INT;\n\tyr4 : DWORD;\n\tltc: DWORD;\n\tidate : DWORD;\nEND_VAR\n\n(*\nversion 1.5\t24. jan. 2011\nprogrammer \thugo\ntested by\toscat\n\nthis functions returns TRUE IF dst TIME is active \nthe FUNCTION calculates automatically for any year betweek 1970 AND 2099 \nwheather daylight savings is on OR off \nthe summertime calculation is done according to european standards.\ndst will become TRUE AT 01:00 utc in the morning FOR the respective days \nAND it will become FALSE after daylight savings TIME is switched back end OF october at 01:00 utc\n\n*)\n\nyr := YEAR_OF_DATE(DT_TO_DATE(UTC));\nltc := DT_TO_DWORD(UTC);\nidate := DT_TO_DWORD(SET_DT(yr, 3, 31, 1, 0, 0));\nyr4 := SHR(5 * INT_TO_DWORD(yr), 2) + 1;\nDST := (idate - ((yr4 + 3) MOD 7) * 86400 <= ltc) AND (idate + (214 - (yr4) MOD 7) * 86400 > ltc);\n\n\n(*\nEquation used TO calculate the beginning OF European Summer TIME:\nSunday (31 - (5*y/4 + 4) mod 7) March at 01.00 UTC\n(valid through 2099, courtesy of Robert H. van Gent, EC).\n\nEuropean Summer Time ends (clocks go back) at 01.00 UTC on\n\n * 29 October 2006\n * 28 October 2007\n * 26 October 2008\n\nEquation used to calculate the end of European Summer Time:\nSunday (31 - (5*y/4 + 1) mod 7) October at 01.00 UTC\n(validity AND credits as above).\n\n*)\n\n\n\n(* revision history\nhm\t4. aug 2006\trev 1.0\n\toriginal version\n\nhm\t24. okt 2007\trev 1.1\n\tdeleted time_zone_offset input because dst is generally at 01:00 utc and not mesz\n\tuk starts 01:00 utc and also greece\n\nhm\t1. dec 2007\trev 1.2\n\tchanged code to improve performance\n\nhm\t16. mar. 2008\trev 1.3\n\tadded type conversion to avoid warnings under codesys 3.0\n\tcode improvement for better performance\n\nhm\t7. oct. 2008\trev 1.4\n\tchanged name of function year to year_of_date\n\nhm\t24. jan. 2011\trev 1.5\n\timproved performance\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "DT2_TO_SDT.st", - "source": "FUNCTION DT2_TO_SDT : SDT\nVAR_INPUT\n\tDI : DATE;\n\tTI : TOD;\nEND_VAR\n\n\n(*\nversion 1.0\t18. oct 2008\nprogrammer \thugo\ntested by\toscat\n\nconverts date and time of day to Structured date time (SDT)\n\n*)\n\nDT2_TO_SDT.YEAR := YEAR_OF_DATE(di);\nDT2_TO_SDT.MONTH := MONTH_OF_DATE(di);\nDT2_TO_SDT.DAY := DAY_OF_MONTH(di);\nDT2_TO_SDT.WEEKDAY := DAY_OF_WEEK(di);\nDT2_TO_SDT.MS := DWORD_TO_INT(TOD_TO_DWORD(ti) MOD 1000);\nDT2_TO_SDT.SECOND := DWORD_TO_INT((TOD_TO_DWORD(ti) / 1000) MOD 60);\nDT2_TO_SDT.MINUTE := DWORD_TO_INT((TOD_TO_DWORD(ti) / 60000) MOD 60);\nDT2_TO_SDT.HOUR := DWORD_TO_INT(TOD_TO_DWORD(ti) / 3600000);\n\n(* revision history\n\nhm 18. oct. 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "DT_SIMU.st", - "source": "FUNCTION_BLOCK DT_SIMU\nVAR_INPUT\n\tSTART : DT;\n\tSPEED : REAL := 1.0;\nEND_VAR\nVAR_OUTPUT\n\tDTS : DT;\nEND_VAR\nVAR\n\ttc : DWORD;\n\tinit: BOOL;\n\tlast: DWORD;\n\ttx: DWORD;\n\ttd: DWORD;\nEND_VAR\n\n(*\nversion 1.2\t8. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nDT_SIMU simulates a real time clock and can be adjusted to different speeds\nit can also be used in simulation to simulate a real time clock.\nthe peed of the clock can be increased or decreased to debug timers.\nwith the input start a start date-time can be specified.\n\n*)\n\n(* read system timer *)\ntx := T_PLC_MS();\ntc := REAL_TO_DWORD(DWORD_TO_REAL(tx - last) * speed);\n\nIF NOT init THEN\n\tinit := TRUE;\n\tDTS := Start;\n\ttc := 0;\n\tlast := tx;\nELSIF SPEED = 0.0 THEN\n\tDTS := DWORD_TO_DT(DT_TO_DWORD(DTS) + 1);\nELSIF tc >= 1000 THEN\n\ttd := (tc / 1000) * 1000;\n\tDTS := DTS + DWORD_TO_TIME(td);\n\tlast := last + REAL_TO_DWORD(DWORD_TO_REAL(td) / speed);\nEND_IF;\n\n(* revision history\nhm\t11. sep. 2008\trev 1.0\n\toriginal version\n\nhm\t16. nov\t2008\trev 1.1\n\tadded type conversions for compatibility reasons\n\nhm\t8.\tmar. 2009\trev 1.2\n\tadded increment by cycle mode\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "DT_TO_SDT.st", - "source": "FUNCTION DT_TO_SDT : SDT\nVAR_INPUT\n\tDTI : DT;\nEND_VAR\nVAR\n\ttmp : DATE;\n\ttdt : DWORD;\nEND_VAR\n\n\n(*\nversion 1.0\t18. oct 2008\nprogrammer \thugo\ntested by\toscat\n\nconverts date_time to Structured date time (SDT)\n\n*)\n\ntmp := DT_TO_DATE(dti);\ntdt := DT_TO_DWORD(dti) - DATE_TO_DWORD(tmp);\nDT_TO_SDT.YEAR := YEAR_OF_DATE(tmp);\nDT_TO_SDT.MONTH := MONTH_OF_DATE(tmp);\nDT_TO_SDT.DAY := DAY_OF_MONTH(tmp);\nDT_TO_SDT.WEEKDAY := DAY_OF_WEEK(tmp);\nDT_TO_SDT.SECOND := DWORD_TO_INT(tdt MOD 60);\nDT_TO_SDT.MINUTE := DWORD_TO_INT((tdt / 60) MOD 60);\nDT_TO_SDT.HOUR := DWORD_TO_INT(tdt / 3600);\n\n(* revision history\n\nhm 18. oct. 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "DT_TO_STRF.st", - "source": "FUNCTION DT_TO_STRF : STRING\nVAR_INPUT\n\tDTI : DT;\n\tMS : INT;\n\tFMT : STRING;\n\tLANG : INT;\nEND_VAR\nVAR CONSTANT\n\tFILL : STRING(1) := '0';\n\tBLANK : STRING(1) := ' ';\nEND_VAR\nVAR\n\tly : INT;\n\tdx: DATE;\n\tfs: STRING(10);\n\ttd: TOD;\n\ttmp : INT;\n\tpos : INT;\n\tf : INT;\nEND_VAR\n\n(*\nversion 1.1\t19. oct. 2008\nprogrammer \thugo\ntested by\toscat\n\nDT_TO_STRINGF converts a DATETIME input to a formatted string\n\n*)\n\nIF LANG < 1 THEN ly := language.DEFAULT; ELSE ly := MIN(language.LMAX, LANG); END_IF;\n\n(* decode date and time information *)\ndx := DT_TO_DATE(DTI);\ntd := DT_TO_TOD(DTI);\n\n(* parse the format string *)\nDT_TO_STRF := FMT;\npos := FIND(DT_TO_STRF, '#');\nWHILE pos > 0 DO\n\t(* retrieve format identifier *)\n\tf := CODE(DT_TO_STRF, pos + 1);\n\t(* generate the return string according to the format character *)\n\tfs := '';\n\tCASE f OF\n\t\t65 : (* letter A retunrs the year in 4 digits *)\n\t\t\tfs := INT_TO_STRING(YEAR_OF_DATE(dx));\n\t\t66 : (* letter B returns the year in exactly 2 digits *)\n\t\t\tfs := RIGHT(INT_TO_STRING(YEAR_OF_DATE(dx)),2);\n\t\t67 : (* letter C returns the month with 1 or 2 digits *)\n\t\t\tfs := INT_TO_STRING(MONTH_OF_DATE(dx));\n\t\t68 : (* letter D returns the month with exactly 2 digits *)\n\t\t\tfs := INT_TO_STRING(MONTH_OF_DATE(dx));\n\t\t\tIF LEN(fs) < 2 THEN fs := CONCAT('0', fs); END_IF;\n\t\t69 : (* letter E returns the month with 3 characters *)\n\t\t\tfs := MONTH_TO_STRING(MONTH_OF_DATE(dx), ly, 3);\n\t\t70 : (* letter F returns the month with all characters *)\n\t\t\tfs := MONTH_TO_STRING(MONTH_OF_DATE(dx), ly, 0);\n\t\t71 : (* letter G returns the day with up to 2 digits *)\n\t\t\tfs := INT_TO_STRING(DAY_OF_MONTH(dx));\n\t\t72 : (* letter H returns the day of the month with exactly 2 digits *)\n\t\t\tfs := INT_TO_STRING(DAY_OF_MONTH(dx));\n\t\t\tIF LEN(fs) < 2 THEN fs := CONCAT(FILL, fs); END_IF;\n\t\t73 : (* letter I returns the weekday as the number 1..7 1 = monday *)\n\t\t\tfs := INT_TO_STRING(DAY_OF_WEEK(dx));\n\t\t74 : (* letter J returns the weekday in 2 character writing *)\n\t\t\tfs := WEEKDAY_TO_STRING(DAY_OF_WEEK(dx), ly, 2);\n\t\t75 : (* letter K returns the weekday with all characters *)\n\t\t\tfs := WEEKDAY_TO_STRING(DAY_OF_WEEK(dx), ly, 0);\n\t\t76 : (* letter L returns AM or PM for the given DateTime *)\n\t\t\tIF td >= TOD#12:00 THEN fs := 'PM'; ELSE fs := 'AM'; END_IF;\n\t\t77 : (* letter M returns the hour in 1 or 2 digit form 0..24h *)\n\t\t\tfs := INT_TO_STRING(HOUR(td));\n\t\t78 : (* letter N returns the hour in exactly 2 digit form 0..24h *)\n\t\t\tfs := INT_TO_STRING(HOUR(td));\n\t\t\tIF LEN(fs) < 2 THEN fs := CONCAT(FILL, fs); END_IF;\n\t\t79 : (* letter O returns the hour in 1 or 2 digit form 0..12h *)\n\t\t\ttmp := HOUR(td) MOD 12;\n\t\t\tIF tmp = 0 THEN tmp := 12; END_IF;\n\t\t\tfs := INT_TO_STRING(tmp);\n\t\t80 : (* letter P returns the hour in exactly 2 digit form 0..12h *)\n\t\t\ttmp := HOUR(td) MOD 12;\n\t\t\tIF tmp = 0 THEN tmp := 12; END_IF;\n\t\t\tfs := INT_TO_STRING(tmp);\n\t\t\tIF LEN(fs) < 2 THEN fs := CONCAT(FILL, fs); END_IF;\n\t\t81 : (* letter Q returns the minute of the hour in 1 or two digit form *)\n\t\t\tfs := INT_TO_STRING(MINUTE(td));\n\t\t82 : (* letter R returns the minute of the hour in exactly two digit form *)\n\t\t\tfs := INT_TO_STRING(MINUTE(td));\n\t\t\tIF LEN(fs) < 2 THEN fs := CONCAT(FILL, fs); END_IF;\n\t\t83 : (* letter S returns the second of the minute in 1 or two digit form *)\n\t\t\tfs := INT_TO_STRING(REAL_TO_INT(SECOND(td)));\n\t\t84 : (* letter T returns the second of the minute in exactly two digit form *)\n\t\t\tfs := INT_TO_STRING(REAL_TO_INT(SECOND(td)));\n\t\t\tIF LEN(fs) < 2 THEN fs := CONCAT(FILL, fs); END_IF;\n\t\t85 : (* letter U returns the milliseconds in 1 to 3 digits *)\n\t\t\tfs := INT_TO_STRING(MS);\n\t\t86 : (* letter V returns the milliseconds in exactly 3 digit form *)\n\t\t\tfs := INT_TO_STRING(MS);\n\t\t\tfs := CONCAT('00',fs);\n\t\t\tfs := RIGHT(fs, 3);\n\t\t87 : (* letter W returns the day of the month with exactly 2 digits first digit is filled with blank if necessary *)\n\t\t\tfs := INT_TO_STRING(DAY_OF_MONTH(dx));\n\t\t\tIF LEN(fs) < 2 THEN fs := CONCAT(BLANK, fs); END_IF;\n\t\t88 : (* letter X returns the month with exactly 2 digits first digit is filled with blank if necessary *)\n\t\t\tfs := INT_TO_STRING(MONTH_OF_DATE(dx));\n\t\t\tIF LEN(fs) < 2 THEN fs := CONCAT(BLANK, fs); END_IF;\n\t\tEND_CASE;\n\tDT_TO_STRF := REPLACE(DT_TO_STRF, fs, 2, pos);\n\tpos := FIND(DT_TO_STRF, '#');\nEND_WHILE;\n\n\n(* revision history\nhm\t7. oct. 2008\trev 1.0\n\toriginal version\n\nhm\t19. oct. 2008\trev 1.1\n\tchanged language setup constants\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "DWORD_OF_BYTE.st", - "source": "FUNCTION DWORD_OF_BYTE : DWORD\nVAR_INPUT\n\tB3 : BYTE;\n\tB2 : BYTE;\n\tB1 : BYTE;\n\tB0 : BYTE;\nEND_VAR\n\n\n(*\nversion 1.3\t18. jul. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function creates a Dword from 4 individual bytes\n\n*)\n\nDWORD_OF_BYTE := SHL(SHL(SHL(BYTE_TO_DWORD(B3),8) OR BYTE_TO_DWORD(B2),8) OR BYTE_TO_DWORD(B1),8) OR BYTE_TO_DWORD(B0);\n\n\n(* revision history\nhm\t24. jan 2007\trev 1.0\n\toriginal version\n\nhm 2. jan 2008\trev 1.1\n\tinproved performance\n\nhm\t23. apr. 2008\trev 1.2\n\treverse order of inputs to be more logical\n\nhm\t18. jul. 2009\trev 1.3\n\tadded type conversions for compatibility reasons\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "DWORD_OF_WORD.st", - "source": "FUNCTION DWORD_OF_WORD : DWORD\nVAR_INPUT\n\tW1 : WORD;\n\tW0 : WORD;\nEND_VAR\n\n\n(*\nversion 1.0\t18. jul. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function creates a Dword from 2 individual Words\n\n*)\n\nDWORD_OF_WORD := SHL(WORD_TO_DWORD(W1),16) OR WORD_TO_DWORD(W0);\n\n\n(* revision history\n\nhm\t18. jul. 2009\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "DWORD_TO_STRB.st", - "source": "FUNCTION DWORD_TO_STRB : STRING(32)\nVAR_INPUT\n\tIN : DWORD;\nEND_VAR\nVAR\n\tpt : POINTER TO BYTE;\n\ti: INT;\nEND_VAR\n\n(*\nversion 1.3\t20. jun. 2008\nprogrammer \thugo\ntested by\toscat\n\nDWORD_TO_STRINGB converts a DWORD to a String of Bits represented by '0' and '1' s.\nThe lowest order bit will be on the right and the high order bit on the left.\n\n*)\n\n(* pointer für die ausgabe ermitteln *)\npt := ADR(DWORD_TO_STRB);\n(* die 8 ausgabecharacter ermitteln und schreiben *)\nFOR i := 1 TO 32 DO\n\tpt^:= BOOL_TO_BYTE(in.31) + 48;\n\tin := SHL(in,1);\n\tpt := pt + 1;\nEND_FOR;\n\n(* der ausgabestring muss nochg mit 0 abgeschlossen werden *)\npt^ := 0;\n\n(* revision history\nhm\t\t9.6.2007\trev 1.0\t\t\n\toriginal version\n\nhm\t\t15.dec 2007\trev 1.1\n\tchanged code for better performance\n\nhm\t29. mar. 2008\trev 1.2\n\tchanged STRING to STRING(32)\n\nhm\t20. jun. 2008\trev 1.3\n\tperformance improvement\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "DWORD_TO_STRF.st", - "source": "FUNCTION DWORD_TO_STRF : STRING(20)\nVAR_INPUT\n\tIN : DWORD;\n\tN : INT;\nEND_VAR\n\n\n(*\nversion 1.0\t26 jan 2007\nprogrammer \thugo\ntested by\t\ttobias\n\ndword_to_strF converts a DWORD, BYTE or Word to a fixed length String.\nthe string will be filled with leading zeroes to achieve the fixed length, or if too long, the lowest digits will be used.\nthe maximum allowed length is 20 mdigits.\n\nfor example:\tdword_to_strf(123,4) = '0123' \n\t\t\t\tdword_to_strf(123,2) = '23'\n*)\n\n(* limit N to max 20 characters *)\n(* convert dword to string first and cut to length N *)\nDWORD_TO_STRF := FIX(DWORD_TO_STRING(in),LIMIT(0,N,20),48,1);\n\n\n(* revision history\nhm\t26. jan.2007\trev 1.0\t\t\n\toriginal version\n\nhm\t29. mar. 2008\trev 1.1\n\tchanged STRING to STRING(20)\n\tlimit the output string to max 20 digits\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "DWORD_TO_STRH.st", - "source": "FUNCTION DWORD_TO_STRH : STRING(8)\nVAR_INPUT\n\tIN : DWORD;\nEND_VAR\nVAR\n\ti : INT;\n\ttemp : BYTE;\n\tpt : POINTER TO BYTE;\nEND_VAR\n\n(*\nversion 1.3\t29. mar. 2008\nprogrammer \thugo\ntested by\ttobias\n\nDWORD_TO_STRINGH converts a DWORD to a String of Hexadecimal represented by '0' .. '9' and 'A' .. 'F'.\nThe lowest order Character will be on the right and the high order Character on the left.\n\n*)\n\n(* read output adress to pointer *)\npt := ADR(DWORD_TO_STRH) + 8;\n(* wirte the closing byte for the string *)\npt^:= 0;\n\n(* write the 8 hex characters backwards *)\nFOR i := 1 TO 8 DO;\n\t(* decrement the pointer *)\n\tpt := pt - 1;\n\t(* read the lowest order hex value *)\n\ttemp := DWORD_TO_BYTE(in AND 16#0000000F);\n\t(* convert value to hex character *)\n\tIF temp <= 9 THEN temp := temp + 48; ELSE temp := temp + 55; END_IF;\n\t(* write character to output string *)\n\tPT^ := temp;\n\t(* shift in for nect hex character *)\n\tin := SHR(in,4);\nEND_FOR;\n\n\n(* code beofre rev 1.2\nFOR i := 1 TO 8 DO\n\tX := DWORD_TO_BYTE(in AND 2#1111);\n\tIF X <= 9 THEN X := X + 48; ELSE X := X + 55; END_IF;\n\tCx := CHR(X);\n\ttemp := CONCAT(Cx, temp);\n\tin := SHR(in,4);\nEND_FOR;\nDWORD_TO_STRH := temp;\n*)\n\n\n(* revision history\nhm\t9. jun. 2007\trev 1.0\t\t\n\toriginal version \n\nhm\t11. sep. 2007\trev 1.1\n\tchanged coding for compatibility with twincat, concat cannot support a function as an argument.\n\nhm\t15. dec. 2007\trev 1.2\n\tchanged code for better performance\n\nhm\t29. mar. 2008\trev 1.3\n\tchanged STRING to STRING(8)\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "DW_TO_REAL.st", - "source": "FUNCTION DW_TO_REAL : REAL\nVAR_INPUT\n\tX : DWORD;\nEND_VAR\nVAR\n\tpt : POINTER TO REAL;\nEND_VAR\n\n(*\nversion 1.0\t18. apr. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function converts a DWORD to REAL in a bitwise manner.\n*)\n\npt := ADR(X);\nDW_TO_REAL := pt^;\n\n(* revision history\nhm\t18. apr. 2008\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "D_TRIG.st", - "source": "FUNCTION_BLOCK D_TRIG\nVAR_INPUT\n\tin : DWORD;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\n\tX : DWORD;\nEND_VAR\nVAR\n\tlast_in : DWORD;\nEND_VAR\n\n(*\nversion 1.1\t19. feb 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nthis block is similar to the IEC Standard R_trig and F_trig but it monitors a DWORD, WORD or Byte Variable instead and generated an Output Pulse for one cycle only when the input has changed.\nan additional output x (Dword) will state the chage of the input.\nExample: the input has chaged from 0001 to 0010 then the output x will be 2.\n\n*)\n\nQ := in <> last_in;\nX := in - last_in;\nlast_in := in;\n\n\n(* revision history\n\nhm \t4.09.2007\t\trev 1.0\n\toriginal version released\n\nhm\t19. feb. 2008\trev 1.1\n\tperformance improvement\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "D_TRUNC.st", - "source": "FUNCTION D_TRUNC : DINT\nVAR_INPUT\n\tX : REAL;\nEND_VAR\n\n(*\nversion 1.2\t10. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nd_trunc truncates a real to a dint 1.5 will be 1 and -1.5 will be -1\nd_trunc is necessary because many systems do not offer a trunc to a dint\nalso real_to_dint will not deliver the same result on different systems\n\n*)\n\nD_TRUNC := REAL_TO_DINT(X);\nIF X > 0.0 THEN\n\tIF DINT_TO_REAL(D_TRUNC) > X THEN D_TRUNC := D_TRUNC - 1; END_IF;\nELSE\n\tIF DINT_TO_REAL(D_TRUNC) < X THEN D_TRUNC := D_TRUNC + 1; END_IF;\nEND_IF;\n\n\n(* for systems that support a dint truncation this routine can be replaced by trunc() *)\n\n\n(* revision history\nhm\t21. mar. 2008\trev 1.0\n\toriginal version\n\nhm\t31. oct. 2008\trev 1.1\n\toptimized performance\n\nhm\t10. mar. 2009\trev 1.2\n\treal constants updated to new systax using dot\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "EASTER.st", - "source": "FUNCTION EASTER : DATE\nVAR_INPUT\n\tyear : INT;\nEND_VAR\nVAR\n\tb,c: INT;\n\today: INT;\nEND_VAR\n\n(*\nversion 1.3\t7. apr. 2008\nprogrammer \thugo\ntested by\ttobias\n\neaster calculates the day of easter sunday for a given year.\nmost other catholic holidays are calculated in reference to easter sunday.\n\n*)\n\nb := (204 - 11 * (YEAR MOD 19)) MOD 30;\nIF b > 27 THEN b := b - 1; END_IF;\nc := (year + SHR(year,2) + b - 13) MOD 7;\noday := 28 + b - c;\nIF oday > 33 THEN\n\tEASTER := SET_DATE(year, 4, oday - 31);\nELSE\n\tEASTER := SET_DATE(year, 3, oday);\nEND_IF;\n\n\n\n\n(* alternativer algorithmus ueber das pasah fest\nexecution time roughly 200us\nDer sog. Passah-Vollmond wird berechnet, in dem das Jahr durch 19 ge-\nteilt wird und der Rest mit der folgenden Tabelle verglichen wird:\n \n 0: Apr 14 5: Apr 18 10: Mrz 25 15: Mrz 30\n 1: Apr 03 6: Apr 08 11: Apr 13 16: Apr 17\n 2: Mrz 23 7: Mrz 28 12: Apr 02 17: Apr 07\n 3: Apr 11 8: Apr 16 13: Mrz 22 18: Mrz 27\n 4: Mrz 31 9: Apr 05 14: Apr 10\n \nFaellt dieses Datum auf einen Sonntag, ist Ostern der naechste Sonntag!\n \nBeispiel: 1992 MOD 19 = 16, daraus folgt 17.04., der naechste Sonntag\n ist dann der 19. April (Ostersonntag)\n*)\n\n\n(* this algorithm is 180 us\na := year MOD 19;\nb := year / 100;\nc := year MOD 100;\nd := b / 4;\ne := b MOD 4;\nf := (b + 8) / 25;\ng := (b - f + 1) / 3;\nh := (19 * a + b - d -g + 15) MOD 30;\ni := C / 4;\nk := c MOD 4;\nl := (32 + 2*e + 2*i - h - k) MOD 7;\nm := (a + 11 * h + 22 * l) / 451;\nx := h + l - 7 * m + 114;\nn := X / 31;\no := x MOD 31 + 1;\n\neaster := set_Date(year,n,o);\n*)\n(*\nIm Magazin \"Nature\" vom 20. April 1876 veröffentlichte ein anonymer Autor eine Tabelle mit Regeln zur Berechnung des (Gregorianischen) Ostersonntages des Jahres J. In Formeln ausgedrückt erhält man das Folgende:\na\t=\tJ mod 19\nb\t=\tint(J / 100)\nc\t=\tJ mod 100\nd\t=\tint(b / 4)\ne\t=\tb mod 4\nf\t=\tint((b + 8) / 25)\ng\t=\tint((b - f + 1) / 3\nh\t=\t(19 · a + b - d - g + 15) mod 30\ni\t=\tint(c / 4)\nk\t=\tc mod 4\nl\t=\t(32 + 2 · e + 2 · i - h - k) mod 7\nm\t=\tint((a + 11 · h + 22 · l) / 451)\nn\t=\tint((h + l - 7 · m + 114) / 31)\no\t=\t(h + l - 7 · m + 114) mod 31\n\nn ist hierbei die Nummer des Monats, o + 1 die Nummer des Tages auf welchen der Ostersonntag im Jahr J fällt. Dieser Algorithmus kommt ohne Hilfszahlen aus.\n\n*)\n\n(* revision history\nhm\t27. dec 2006\trev 1.0\n\toriginal version\n\nhm\t15. dec 2007\trev 1.1\n\tmodified code for better performance\n\nhm\t3. feb 2008\t\trev 1.2\n\tmodified code for better performance\n\nhm\t7. apr. 2008\trev 1.3\n\timproved performance\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "ELLIPSE_A.st", - "source": "FUNCTION ELLIPSE_A : REAL\nVAR_INPUT\n\tR1 : REAL;\n\tR2 : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t18. oct. 2008\nprogrammer \thugo\ntested by\toscat\n\nellipse_A calculates the Area of an ellipe based on the two radians R1 and R2\n\n\n*)\n\nELLIPSE_A := math.PI * R1 * R2;\n\n(* revision histroy\nhm\t16. oct 2007\trev 1.0\n\toriginal version\n\nhm\t18. oct. 2008\trev 1.1\n\tusing math constants\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "ELLIPSE_C.st", - "source": "FUNCTION ELLIPSE_C : REAL\nVAR_INPUT\n\tR1 : REAL;\n\tR2 : REAL;\nEND_VAR\n\n\n(*\nversion 1.2\t10. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nellipse_C calculates the circumference of an ellipe based on the two radians R1 and R2\n\n*)\n\nELLIPSE_C := math.PI * (3.0 * (R1+R2) - SQRT((3.0 * r1 + R2) * (3.0 * r2 + r1)));\n\n(* revision histroy\nhm\t16. oct 2007\trev 1.0\n\toriginal version\n\nhm\t18. oct. 2008\trev 1.1\n\tusing math constants\n\nhm\t10. mar. 2009\trev 1.2\n\tchanged syntax of real constants to 0.0\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "ENERGY.st", - "source": "FUNCTION_BLOCK ENERGY\nVAR_INPUT\n\tJ : REAL;\n\tC : REAL;\n\tWh : REAL;\nEND_VAR\nVAR_OUTPUT\n\tYJ : REAL;\n\tYC : REAL;\n\tYWh : REAL;\nEND_VAR\n\n\n(*\nversion 1.2\t16. jan. 2010\nprogrammer \thugo\ntested by\t\toscat\n\nthis function converts different energy units\nany unused input can simply be left open.\ndifferent inputs connected at the same time will be added up.\n*)\n\nYJ := J + Wh * 3600.0 + C * 4.1868;\nYC := YJ * 0.238845896627496;\nYWh := YJ * 2.7777777778E-004;\n\n(*\nArbeit, Energie, Joule* J 1 J = 1 N · m = 1 W · s = (1/3,6) E–6 kW · h = 1 kg · m2/s2\nWärmemenge Kilowattstunde kW · h 1 kW · h = 3,6 MJ = 860 kcal\nElektronvolt eV 1 eV = 160,218 92 E–21 J\nErg erg 1 erg = 1E–7 J\nKalorie calorie 1 calalorie = 4,1868 J = 1,163 E–3 W · h\nTherm therm 1 therm = 105,50 · 106 J\n*)\n\n(* revision history\n\nhm\t27. mar. 2007\trev 1.0\n\toriginal version\n\nhm\t11. mar. 2009\trev 1.1\n\timproved code\n\nhm 16. jan 2010\trev 1.2\n\tavoid the string cal in comments for codesys import bug\n\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "ERF.st", - "source": "FUNCTION ERF : REAL\nVAR_INPUT\n\tX : REAL;\nEND_VAR\nVAR\n\tx2 : REAL;\n\tax2 : REAL;\nEND_VAR\n\n\n(*\nversion 1.3\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the erf (error) function.\n\n*)\n\nx2 := X*X;\nax2 := 0.147 * x2 + 1.0;\nERF := SQRT(1.0 - EXP(-X2 * ((0.27323954473516 + aX2)/(ax2)))) * SGN(x);\n\n\n\n\n(* revision history\nhm\t7. apr. 2008\trev 1.0\n\toriginal version\n\nhm\t30. jun. 2008\trev 1.1\n\tadded type conversions to avoid warnings under codesys 3.0\n\nhm\t25. oct. 2008\trev 1.2\n\tnew code using new algorithm\n\nhm\t10. mar. 2009\trev 1.3\n\treal constants updated to new systax using dot\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "ERFC.st", - "source": "FUNCTION ERFC : REAL\nVAR_INPUT\n\tX : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the inverse erf (error) function.\n\n*)\n\nERFC := 1.0 - ERF(X);\n\n(* revision history\nhm\t7. apr. 2008\trev 1.0\n\toriginal version\n\nhm\t10. mar. 2009\trev 1.1\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "ESR_COLLECT.st", - "source": "FUNCTION_BLOCK ESR_COLLECT\nVAR_INPUT\n\tESR_0, ESR_1, ESR_2, ESR_3, ESR_4, ESR_5, ESR_6, ESR_7 : ARRAY [0..3] OF esr_data;\n\trst : BOOL;\nEND_VAR\nVAR_IN_OUT\n\tpos : INT;\nEND_VAR\nVAR_OUTPUT\n\tESR_OUT : ARRAY[0..31] OF esr_data;\nEND_VAR\nVAR CONSTANT\n\tmax_in : INT := 3; (* max limit of input array *)\n\tmax_out : INT := 32; (* number of elements in array *)\nEND_VAR\nVAR\n\tcnt : INT := -1;\nEND_VAR\n\n(*\nversion 1.4\t1. dec. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nESR_collect collects esr data from up to 8 esr_mon modules and stroes them in an output array.\nthe output pos will display the position of the last element in the array. if the array is empty, pos = -1\nwhen to buffer is read by followon modules. pos has to be reset to -1\nif the array will be full, the buffer will be refilled starting at position 0.\n\n*)\n\nIF rst OR cnt < 0 THEN\n\tpos := -1;\nELSE\n\tFOR cnt := 0 TO max_in DO\n\tIF esr_0[cnt].typ > 0 THEN pos := INC1(pos, max_out); esr_out[pos] := esr_0[cnt]; END_IF;\n\tIF esr_1[cnt].typ > 0 THEN pos := INC1(pos, max_out); esr_out[pos] := esr_1[cnt]; END_IF;\n\tIF esr_2[cnt].typ > 0 THEN pos := INC1(pos, max_out); esr_out[pos] := esr_2[cnt]; END_IF;\n\tIF esr_3[cnt].typ > 0 THEN pos := INC1(pos, max_out); esr_out[pos] := esr_3[cnt]; END_IF;\n\tIF esr_4[cnt].typ > 0 THEN pos := INC1(pos, max_out); esr_out[pos] := esr_4[cnt]; END_IF;\n\tIF esr_5[cnt].typ > 0 THEN pos := INC1(pos, max_out); esr_out[pos] := esr_5[cnt]; END_IF;\n\tIF esr_6[cnt].typ > 0 THEN pos := INC1(pos, max_out); esr_out[pos] := esr_6[cnt]; END_IF;\n\tIF esr_7[cnt].typ > 0 THEN pos := INC1(pos, max_out); esr_out[pos] := esr_7[cnt]; END_IF;\n END_FOR;\nEND_IF;\n\n\n(* revision history\nhm\t26.jan 2007\trev 1.0\n\toriginal version\n\nhm\t8. dec 2007\trev 1.1\n\tadded reset input\n\nks\t27. oct. 2008\trev 1.2\n\toptimized code for performance\n\nks\t12. nov. 2009\trev 1.3\n\toutput pos was not pointing to last value\t\n\nhm\t1. dec. 2009\trev 1.4\n\tchanged pos to be I/O\n\treduced output array size to 32 elements\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "ESR_DATA.st", - "source": "TYPE ESR_DATA :\nSTRUCT\n\tTYP : BYTE;\n\tADRESS : STRING(10);\n\tDS : DT;\n\tTS : TIME;\n\tDATA : ARRAY[0..7] OF BYTE;\nEND_STRUCT\nEND_TYPE\n" - }, - { - "fileName": "ESR_MON_B8.st", - "source": "FUNCTION_BLOCK ESR_MON_B8\nVAR_INPUT\n\ts0, s1, s2, s3, s4, s5, s6, s7 : BOOL;\n\tDT_in : DT;\nEND_VAR\nVAR_INPUT CONSTANT\n\ta0, a1, a2, a3, a4, a5, a6, a7 : STRING(10);\nEND_VAR\nVAR_OUTPUT\n\tESR_Flag : BOOL;\nEND_VAR\nVAR_IN_OUT\n\tESR_Out: ARRAY [0..3] OF esr_data;\nEND_VAR\nVAR\n\tx0, x1, x2, x3, x4, x5, x6, x7 : BOOL;\n\ttx: TIME;\n\tcnt : INT;\nEND_VAR\n\n(*\nversion 1.3\t1. dec. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nESR_mon_B8 monitores up to 8 binary inputs and reports changes with time stamd and adress label.\nthe module checks 8 inputs for a change and reports all changes with time and adress stamp to the output.\n4 events maximum can be collected at once within the same cycle\n\n*)\n\n(* read system timer *)\ntx := DWORD_TO_TIME(T_PLC_MS());\n\nESR_Flag := FALSE;\nesr_out[3].typ := 0;\nesr_out[2].typ := 0;\nesr_out[1].typ := 0;\nesr_out[0].typ := 0;\ncnt := 0;\n\n\n(* check if inputs have chaged and fill buffer *)\nIF s0 <> X0 THEN\n\tesr_out[cnt].typ := 10 + BOOL_TO_BYTE(s0);\n\tesr_out[cnt].adress := a0;\n\tesr_out[cnt].DS := DT_in;\n\tesr_out[cnt].TS := TX;\n\tX0 := S0;\n\tcnt := cnt + 1;\n\tesr_flag := TRUE;\nEND_IF;\nIF s1 <> X1 THEN\n\tesr_out[cnt].typ := 10 + BOOL_TO_BYTE(s1);\n\tesr_out[cnt].adress := a1;\n\tesr_out[cnt].DS := DT_in;\n\tesr_out[cnt].TS := TX;\n\tX1 := S1;\n\tcnt := cnt + 1;\n\tesr_flag := TRUE;\nEND_IF;\nIF s2 <> X2 THEN\n\tesr_out[cnt].typ := 10 + BOOL_TO_BYTE(s2);\n\tesr_out[cnt].adress := a2;\n\tesr_out[cnt].DS := DT_in;\n\tesr_out[cnt].TS := TX;\n\tX2 := S2;\n\tcnt := cnt + 1;\n\tesr_flag := TRUE;\nEND_IF;\nIF s3 <> X3 THEN\n\tesr_out[cnt].typ := 10 + BOOL_TO_BYTE(s3);\n\tesr_out[cnt].adress := a3;\n\tesr_out[cnt].DS := DT_in;\n\tesr_out[cnt].TS := TX;\n\tX3 := S3;\n\tcnt := cnt + 1;\n\tesr_flag := TRUE;\nEND_IF;\nIF s4 <> X4 AND cnt < 4 THEN\n\tesr_out[cnt].typ := 10 + BOOL_TO_BYTE(s4);\n\tesr_out[cnt].adress := a4;\n\tesr_out[cnt].DS := DT_in;\n\tesr_out[cnt].TS := TX;\n\tX4 := S4;\n\tcnt := cnt + 1;\n\tesr_flag := TRUE;\nEND_IF;\nIF s5 <> X5 AND cnt < 4 THEN\n\tesr_out[cnt].typ := 10 + BOOL_TO_BYTE(s5);\n\tesr_out[cnt].adress := a5;\n\tesr_out[cnt].DS := DT_in;\n\tesr_out[cnt].TS := TX;\n\tX5 := S5;\n\tcnt := cnt + 1;\n\tesr_flag := TRUE;\nEND_IF;\nIF s6 <> X6 AND cnt < 4 THEN\n\tesr_out[cnt].typ := 10 + BOOL_TO_BYTE(s6);\n\tesr_out[cnt].adress := a6;\n\tesr_out[cnt].DS := DT_in;\n\tesr_out[cnt].TS := TX;\n\tX6 := S6;\n\tcnt := cnt + 1;\n\tesr_flag := TRUE;\nEND_IF;\nIF s7 <> X7 AND cnt < 4 THEN\n\tesr_out[cnt].typ := 10 + BOOL_TO_BYTE(s7);\n\tesr_out[cnt].adress := a7;\n\tesr_out[cnt].DS := DT_in;\n\tesr_out[cnt].TS := TX;\n\tX7 := S7;\n\tcnt := cnt + 1;\n\tesr_flag := TRUE;\nEND_IF;\n\n(* revision history\nhm\t26. jan 2007\trev 1.0\n\toriginal version\n\nhm\t17. sep 2007\trev 1.1\n\treplaced time() with T_PLC_MS() for compatibility reasons\n\nhm\t22. oct. 2008\trev 1.2\n\toptimized code\n\nhm\t1.dec. 2009\trev 1.3\n\tchanged esr_out to be I/O\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "ESR_MON_R4.st", - "source": "FUNCTION_BLOCK ESR_MON_R4\nVAR_INPUT\n\tR0, R1, R2, R3 : REAL;\n\tDT_in : DT;\nEND_VAR\nVAR_INPUT CONSTANT\n\ta0, a1, a2, a3 : STRING(10);\n\ts0, s1, s2, s3 : REAL;\nEND_VAR\nVAR_OUTPUT\n\tESR_Flag : BOOL;\nEND_VAR\nVAR_IN_OUT\n\tESR_Out: ARRAY [0..3] OF esr_data;\nEND_VAR\nVAR\n\tp0, p1, p2, p3 : POINTER TO DWORD;\n\tx0, x1, x2, x3 : REAL;\n\ttx: TIME;\n\tcnt : INT;\nEND_VAR\n\n(*\nversion 1.4\t1. dec. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nESR_mon_R4 monitores up to 4 Real inputs and reports changes with time stamd and adress label.\nthe module checks 4 inputs for a change of more than the specified sensitivity S and reports all changes with time and adress stamp to the output.\n\n*)\n\n(* read system timer *)\ntx := DWORD_TO_TIME(T_PLC_MS());\nP0 := ADR(R0);\nP1 := ADR(R1);\nP2 := ADR(R2);\nP3 := ADR(R3);\n\nESR_Flag := FALSE;\nesr_out[3].typ := 0;\nesr_out[2].typ := 0;\nesr_out[1].typ := 0;\nesr_out[0].typ := 0;\ncnt := 0;\n\n(* check if inputs have chaged and fill buffer *)\nIF DIFFER(R0, X0, S0) THEN\n\tesr_out[cnt].typ := 20;\n\tesr_out[cnt].adress := a0;\n\tesr_out[cnt].DS := DT_in;\n\tesr_out[cnt].TS := TX;\n\tesr_out[cnt].data[0] := Byte_of_Dword(P0^,0);\n\tesr_out[cnt].data[1] := Byte_of_Dword(P0^,1);\n\tesr_out[cnt].data[2] := Byte_of_Dword(P0^,2);\n\tesr_out[cnt].data[3] := Byte_of_Dword(P0^,3);\n\tX0 := R0;\n\tcnt := cnt + 1;\n\tesr_flag := TRUE;\nEND_IF;\nIF differ(R1, X1, S1) THEN\n\tesr_out[cnt].typ := 20;\n\tesr_out[cnt].adress := a1;\n\tesr_out[cnt].DS := DT_in;\n\tesr_out[cnt].TS := TX;\n\tesr_out[cnt].data[0] := Byte_of_Dword(P1^,0);\n\tesr_out[cnt].data[1] := Byte_of_Dword(P1^,1);\n\tesr_out[cnt].data[2] := Byte_of_Dword(P1^,2);\n\tesr_out[cnt].data[3] := Byte_of_Dword(P1^,3);\n\tX1 := R1;\n\tcnt := cnt + 1;\n\tesr_flag := TRUE;\nEND_IF;\nIF differ(R2, X2, S2) THEN\n\tesr_out[cnt].typ := 20;\n\tesr_out[cnt].adress := a2;\n\tesr_out[cnt].DS := DT_in;\n\tesr_out[cnt].TS := TX;\n\tesr_out[cnt].data[0] := Byte_of_Dword(P2^,0);\n\tesr_out[cnt].data[1] := Byte_of_Dword(P2^,1);\n\tesr_out[cnt].data[2] := Byte_of_Dword(P2^,2);\n\tesr_out[cnt].data[3] := Byte_of_Dword(P2^,3);\n\tX2 := R2;\n\tcnt := cnt + 1;\n\tesr_flag := TRUE;\nEND_IF;\nIF DIFFER(R3, X3, S3) THEN\n\tesr_out[cnt].typ := 20;\n\tesr_out[cnt].adress := a3;\n\tesr_out[cnt].DS := DT_in;\n\tesr_out[cnt].TS := TX;\n\tesr_out[cnt].data[0] := Byte_of_Dword(P3^,0);\n\tesr_out[cnt].data[1] := Byte_of_Dword(P3^,1);\n\tesr_out[cnt].data[2] := Byte_of_Dword(P3^,2);\n\tesr_out[cnt].data[3] := Byte_of_Dword(P3^,3);\n\tX3 := R3;\n\tcnt := cnt + 1;\n\tesr_flag := TRUE;\nEND_IF;\n\n\n(* revision history\nhm\t26. jan 2007\trev 1.0\n\toriginal version\n\nhm\t17. sep. 2007\t\trev 1.1\n\treplaced time() with T_PLC_MS() for compatibility reasons\n\nhm\t8. dec. 2007\t\trev 1.2\n\tcorrected an error while esr typ would not be set\n\nhm\t16. mar. 2008\t\trev 1.3\n\tdeleted wrong conversion real_to_dword\n\nhm\t1. dec 2009\t\trev 1.4\n\tchanged esr_out to be I/O\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "ESR_MON_X8.st", - "source": "FUNCTION_BLOCK ESR_MON_X8\nVAR_INPUT\n\ts0, s1, s2, s3, s4, s5, s6, s7 : BYTE;\n\tDT_in : DT;\n\tMode : BYTE := 3;\nEND_VAR\nVAR_INPUT CONSTANT\n\ta0, a1, a2, a3, a4, a5, a6, a7 : STRING(10);\nEND_VAR\nVAR_OUTPUT\n\tESR_Flag : BOOL;\nEND_VAR\nVAR_IN_OUT\n\tESR_Out: ARRAY [0..3] OF esr_data;\nEND_VAR\nVAR\n\tx0, x1, x2, x3, x4, x5, x6, x7 : BYTE;\n\ttx: TIME;\n\tcnt : INT;\nEND_VAR\n\n(*\nversion 1.2\t1. dec. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nESR_MON_X8 is a status and error collector.\nthe module checks 8 status inputs for a change and reports up to 4 input changes with time and adress stamp to the output.\nthe mode can be \n1 for error only\n2 for error and status\n3 for error, status and debug\nthe adress label of the 8 inputs can be configured individually.\n*)\n\n(* read system timer *)\ntx := DWORD_TO_TIME(T_PLC_MS());\n\nESR_Flag := FALSE;\nesr_out[3].typ := 0;\nesr_out[2].typ := 0;\nesr_out[1].typ := 0;\nesr_out[0].typ := 0;\ncnt := 0;\n\n\n(* check if inputs have chaged and fill buffer *)\nIF s0 <> X0 AND ((s0 < 100) OR (S0 > 99 AND S0 < 200 AND mode >= 2) OR (S0 > 199 AND mode = 3)) THEN\n\tesr_out[cnt] := status_to_ESR(s0, a0, DT_in, TX);\n\tX0 := S0;\n\tcnt := cnt + 1;\n\tesr_flag := TRUE;\nEND_IF;\nIF s1 <> X1 AND ((s1 < 100) OR (S1 > 99 AND S1 < 200 AND mode >= 2) OR (S1 > 199 AND mode = 3)) THEN\n\tesr_out[cnt] := status_to_ESR(s1, a1, DT_in, TX);\n\tX1 := S1;\n\tcnt := cnt + 1;\n\tesr_flag := TRUE;\nEND_IF;\nIF s2 <> X2 AND ((s2 < 100) OR (S2 > 99 AND S2 < 200 AND mode >= 2) OR (S2 > 199 AND mode = 3)) THEN\n\tesr_out[cnt] := status_to_ESR(s2, a2, DT_in, TX);\n\tX2 := S2;\n\tcnt := cnt + 1;\n\tesr_flag := TRUE;\nEND_IF;\nIF s3 <> X3 AND ((s3 < 100) OR (S3 > 99 AND S3 < 200 AND mode >= 2) OR (S3 > 199 AND mode = 3)) THEN\n\tesr_out[cnt] := status_to_ESR(s3, a3, DT_in, TX);\n\tX3 := S3;\n\tcnt := cnt + 1;\n\tesr_flag := TRUE;\nEND_IF;\nIF cnt < 4 AND s4 <> X4 AND ((s4 < 100) OR (S4 > 99 AND S4 < 200 AND mode >= 2) OR (S4 > 199 AND mode = 3)) THEN\n\tesr_out[cnt] := status_to_ESR(s4, a4, DT_in, TX);\n\tX4 := S4;\n\tcnt := cnt + 1;\n\tesr_flag := TRUE;\nEND_IF;\nIF cnt < 4 AND s5 <> X5 AND ((s5 < 100) OR (S5 > 99 AND S5 < 200 AND mode >= 2) OR (S5 > 199 AND mode = 3)) THEN\n\tesr_out[cnt] := status_to_ESR(s5, a5, DT_in, TX);\n\tX5 := S5;\n\tcnt := cnt + 1;\n\tesr_flag := TRUE;\nEND_IF;\nIF cnt < 4 AND s6 <> X6 AND ((s6 < 100) OR (S6 > 99 AND S6 < 200 AND mode >= 2) OR (S6 > 199 AND mode = 3)) THEN\n\tesr_out[cnt] := status_to_ESR(s6, a6, DT_in, TX);\n\tX6 := S6;\n\tcnt := cnt + 1;\n\tesr_flag := TRUE;\nEND_IF;\nIF cnt < 4 AND s7 <> X7 AND ((s7 < 100) OR (S7 > 99 AND S7 < 200 AND mode >= 2) OR (S7 > 199 AND mode = 3)) THEN\n\tesr_out[cnt] := status_to_ESR(s7, a7, DT_in, TX);\n\tX7 := S7;\n\tcnt := cnt + 1;\n\tesr_flag := TRUE;\nEND_IF;\n\n\n(* revision history\nhm\t26. jan 2007\t\trev 1.0\n\toriginal version\n\nhm\t17. sep 2007\trev 1.1\n\treplaced time() with T_PLC_MS() for compatibility reasons\n\nhm\t1. dec. 2009\trev 1.2\n\tchanged esr_out to be I/O\n\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "EVEN.st", - "source": "FUNCTION EVEN : BOOL\nVAR_INPUT\n\tin : DINT;\nEND_VAR\n\n\n(*\nversion 1.1\t1 dec 2007\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function chacks an input for even value\nthe output is true if the input is even.\nexecution time on wago 750 - 841 = 10 us\n*)\n\nEVEN := NOT in.0;\n\n(* revision history\nhm\t1. oct 2006\trev 1.0\n\tORIGINAL VERSION\n\nhm\t01.12.2007\trev 1.1\n\tchanged code for improved performance\n\nhm\t21. mar. 2008\trev 1.2\n\tchanged type of input IN from INT to DINT\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "EVENTS.st", - "source": "FUNCTION_BLOCK EVENTS\nVAR_INPUT\n\tDATE_IN : DATE;\n\tENA : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tY : BOOL;\n\tNAME : STRING(30);\nEND_VAR\nVAR\n\ti : INT;\n\tlast_active : DATE;\n\tsize :INT := 49;\n\tday_in: DINT;\n\tcyr: INT;\n\tlday: DINT;\n\tcheck : HOLIDAY_DATA;\n\ty_int : BOOL;\n\tname_int : STRING(30);\nEND_VAR\nVAR_IN_OUT\n\tELIST : ARRAY[0..49] OF HOLIDAY_DATA;\nEND_VAR\n\n(*\nversion 1.0\t18. jan. 2010\nprogrammer \thugo\ntested by\t\ttobias\n\nevent checks an array with a list of events and displays the event if today is one.\n\n*)\n\n(* for performance reasons only activate once a day *)\nIF last_active <> date_in THEN\n\tlast_active := DATE_IN;\n\tY_int := FALSE;\n\tname_int := '';\n\tday_in := DAY_OF_DATE(DATE_IN);\n\tcyr := YEAR_OF_DATE(DATE_IN);\n\n\t(* search list for events *)\n\tFOR i := 0 TO size DO\n\t\tcheck := elist[i];\n\t\tlday := DAY_OF_DATE(SET_DATE(cyr,check.month, check.day));\n\t\tIF day_in >= lday AND day_in <= lday + check.use - 1 THEN\n\t\t\ty_int := TRUE;\n\t\t\tname_int := check.name;\n\t\t\tEXIT;\n\t\tEND_IF;\n\tEND_FOR;\nEND_IF;\n\nIF ENA THEN\n\tY := y_int;\n\tNAME := name_int;\nELSE\n\tY := FALSE;\n\tNAME := '';\nEND_IF;\n\n(* revision history\nhm 18. jan. 2011\trev 1.0\n\tnew module\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "EXEC.st", - "source": "FUNCTION EXEC : STRING(STRING_LENGTH)\nVAR_INPUT\n\tstr : STRING(STRING_LENGTH);\nEND_VAR\nVAR\n\tpos: INT;\n\tR1: REAL;\n\tR2: REAL;\n\toperator: STRING(10);\nEND_VAR\n\n(*\nversion 1.4\t29. mar. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nexec executes a mathematical term and returns the result as a string\nthe term can only be a simple term without brackets and only one operator\nallowed operastors are: (+, -, *, /, ^, sqrt, sin, cos, tan).\n\n*)\n\n(* extract both numbers and operator *)\nEXEC := UPPERCASE(TRIM(str));\n\npos := FINDB_NONUM(EXEC);\nIF pos > 1 THEN R1 := STRING_TO_REAL(LEFT(EXEC,pos-1)); END_IF;\nR2 := STRING_TO_REAL(RIGHT(EXEC,LEN(EXEC)-pos));\nEXEC := LEFT(EXEC,pos);\npos := FINDB_NUM(EXEC);\noperator := RIGHT(EXEC,LEN(EXEC) - pos);\nIF operator = '' AND LEN(str) = 0 THEN\n\tEXEC := '';\n\tRETURN;\nELSIF operator = '' THEN\n\tEXEC := str;\n\tRETURN;\nEND_IF;\nIF operator = '^' THEN\n\tEXEC := REAL_TO_STRING(EXPT(R1, R2));\nELSIF operator = 'SQRT' THEN\n\tEXEC := REAL_TO_STRING(SQRT(R2));\nELSIF operator = 'SIN' THEN\n\tEXEC := REAL_TO_STRING(SIN(r2));\nELSIF operator = 'COS' THEN\n\tEXEC := REAL_TO_STRING(COS(r2));\nELSIF operator = 'TAN' THEN\n\tEXEC := REAL_TO_STRING(TAN(R2));\nELSIF operator = '*' THEN\n\tEXEC := REAL_TO_STRING(R1 * R2);\nELSIF operator = '/' THEN\n\tIF R2 <> 0 THEN EXEC := REAL_TO_STRING(R1 / R2); ELSE EXEC := 'ERROR'; END_IF;\nELSIF operator = '+' THEN\n\tEXEC := REAL_TO_STRING(r1 + r2);\nELSIF operator = '-' THEN\n\tEXEC := REAL_TO_STRING(r1 - r2);\nELSE\n\tEXEC := 'ERROR';\nEND_IF;\n\nIF EXEC = 'ERROR' THEN\n\tRETURN;\n(* some systems deliver integer instead of real *)\nELSIF FIND(EXEC,'.') = 0 THEN\n\tEXEC := CONCAT(EXEC, '.0');\n(* some systems deliver n. instead of n.0 ! *)\nELSIF RIGHT(EXEC,1) = '.' THEN\n\tEXEC := CONCAT(EXEC,'0');\nEND_IF;\n\n\n(* revision history\n\nhm \t6.feb 2007\t\trev 1.1\n\tcos has to be written in uppercase\n\tdivide by 0 will return an error\n\nhm\t5. mar. 2008\trev 1.2\n\tadd a 0 to the string if a '.' is at the end of the string\n\nhm\t20. mar. 2008\trev 1.3\n\tmake sure the function always returns a real value in the form of x.y\n\nhm\t29. mar. 2008\trev 1.4\n\tchanged STRING to STRING(STRING_LENGTH)\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "EXP10.st", - "source": "FUNCTION EXP10 : REAL\nVAR_INPUT\n\tX : REAL;\nEND_VAR\n\n\n(*\nversion 1.0\t 2 dec 2007\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the exponent to the basis 10\nexp10(3) = 1000\n\n*)\n\nEXP10 := EXP(X * 2.30258509299405);\n\n(* revision history\nhm\t2. dec 2007\t\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "EXPN.st", - "source": "FUNCTION EXPN : REAL\nVAR_INPUT\n\tX : REAL;\n\tN : INT;\nEND_VAR\nVAR\n\tsign: BOOL;\nEND_VAR\n\n(*\nversion 1.2\t10. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nthis function calculates X to the power of N (Y = X^N) whilke N is an integer\nespecially on CPU's without a floating point unit this algorythm is about 30 times faster then the IEC standard EXPT() Function\n\n*)\n\nsign := n.15;\nN := ABS(N);\nIF N.0 THEN EXPN := X; ELSE EXPN := 1.0; END_IF;\nN := SHR(N,1);\nWHILE N > 0 DO\n X := X * X;\n IF N.0 THEN EXPN := EXPN * X; END_IF;\n N := SHR(N,1);\nEND_WHILE;\nIF sign THEN EXPN := 1.0 / EXPN; END_IF;\n\n\n\n(* revision history\nhm\t4. dec 2007\trev 1.0\n\toriginal version\n\nhm\t22. oct. 2008\trev 1.1\n\toptimized code\n\nhm\t10. mar. 2009\trev 1.2\n\tremoved nested comments\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "FACT.st", - "source": "FUNCTION FACT : DINT\nVAR_INPUT\n\tX : INT;\nEND_VAR\n\n\n(*\nversion 1.5\t26. mar. 2011\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the factorial of x\n\nif the input is negative or higher then 12 the output will be -1.\n\n*)\n\nIF X >= 0 AND X <= 12 THEN\n\tFACT := math.FACTS[X];\nELSE\n\tFACT := -1;\nEND_IF;\n\n\n(* working code without array\nIF X > 12 OR X < 0 THEN\n\tFACT := -1;\nELSIF X < 7 THEN\n\tFACT := 1;\n\tFOR i := 2 TO X DO\n\t\tFACT := FACT * i;\n\tEND_FOR;\nELSE\n\tFACT := 5040;\n\tFOR i := 8 TO X DO\n\t\tFACT := FACT * i;\n\tEND_FOR;\nEND_IF;\n*)\n\n(* revision history\nhm 4.3.2007\t\trev 1.1\n\tchanged a critical error where while loop was indefinite.\n\nhm\t10.12.2007\trev 1.2\n\tstart value for i has changed to 2 for better performance\n\nhm\t10. mar 2008\trev 1.3\n\tchanged output of fact to dint to allow bigger values\n\nhm\t27. oct. 2008\trev 1.4\n\toptimized code\n\nhm\t26. mar. 2011\trev 1.5\n\tusing array math.facts\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "FADE.st", - "source": "FUNCTION_BLOCK FADE\nVAR_INPUT\n\tIN1 : REAL;\n\tIN2 : REAL;\n\tF : BOOL;\n\tTF : TIME;\n\trst : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tY : REAL;\nEND_VAR\nVAR\n\trmx : RMP_W;\nEND_VAR\n\n(*\nversion 1.3\t24. jan. 2009\nprogrammer \toscat\ntested BY\t\toscat\n\nFADE is used to crossfade between the inputs IN1 and IN2. The fade_over time is specified with TF.\nWhen F = TRUE then Y = IN2 after the time TF, and when F = FALSE then Y = IN1.\n\n*)\n\nrmx(rst := rst AND NOT F, set := rst AND F, pt := TF, up := F);\nY := (in2 - In1) / 65535.0 * WORD_TO_REAL(rmx.out) + in1;\n\n\n(* code for rev 1.1\nIF rst THEN\n\trmx(set := F, rst := NOT F);\nELSIF F AND (NOT rmx.high) THEN\n\trmx(PT := TF, UP := TRUE, e := TRUE, rst := FALSE, set := FALSE);\nELSIF (NOT F) AND (NOT rmx.low) THEN\n\trmx(PT := TF, UP := FALSE, e := TRUE, rst := FALSE, set := FALSE);\nELSE\n\trmx(e := FALSE, rst := FALSE, set := FALSE);\nEND_IF;\nY := (WORD_TO_REAL(rmx.out) * in1 + WORD_TO_REAL(FF - rmx.out) * IN2) / FF;\n*)\n\n\n(* revision history\nhm\t26. dec 2007\trev 1.0\n\toriginal version\n\nhm\t18. oct. 2008\trev 1.1\n\timproved performance\n\tchanged calls for rmp_w because rmp_w has chaged\n\nhm\t17. dec. 2008\trev 1.2\n\tfunction of input f was inverted\n\nhm\t24. jan. 2009\trev 1.3\n\tdelted unused var FF\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FF_D2E.st", - "source": "FUNCTION_BLOCK FF_D2E\nVAR_INPUT\n\tD0 : BOOL;\n\tD1 : BOOL;\n\tCLK : BOOL;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tQ0 : BOOL;\n\tQ1 : BOOL;\nEND_VAR\nVAR\n\tedge : BOOL;\nEND_VAR\n\n(*\nversion 1.3\t14. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\ndual D-type flip flop with reset and rising clock trigger\n\n*)\n\nIF rst THEN\n\tQ0 := FALSE;\n\tQ1 := FALSE;\nELSIF clk AND NOT edge THEN\n\tQ0 := D0;\n\tQ1 := D1;\nEND_IF;\nedge := CLK;\n\n(* revision history\nhm\t25. dec 2007\trev 1.0\n\toriginal version\n\nhm\t27. dec 2007\trev 1.1\n\tchanged code for better performance\n\nhm\t30. oct. 200\trev 1.2\n\tdeleted unnecessary init with 0\n\nhm\t14. mar. 2009\trev 1.3\n\tremoved double assignments\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FF_D4E.st", - "source": "FUNCTION_BLOCK FF_D4E\nVAR_INPUT\n\tD0 : BOOL;\n\tD1 : BOOL;\n\tD2 : BOOL;\n\tD3 : BOOL;\n\tCLK : BOOL;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tQ0 : BOOL;\n\tQ1 : BOOL;\n\tQ2 : BOOL;\n\tQ3 : BOOL;\nEND_VAR\nVAR\n\tedge : BOOL;\nEND_VAR\n\n\n(*\nversion 1.3\t14. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nquad D-type flip flop with reset and rising clock trigger\n\n*)\n\nIF rst THEN\n\tQ0 := FALSE;\n\tQ1 := FALSE;\n\tQ2 := FALSE;\n\tQ3 := FALSE;\nELSIF clk AND NOT edge THEN\n\tQ0 := D0;\n\tQ1 := D1;\n\tQ2 := D2;\n\tQ3 := D3;\nEND_IF;\nedge := CLK;\n\n(* revision history\nhm\t4. aug 2006\trev 1.0\n\toriginal version\n\nhm\t27. dec 2007\trev 1.1\n\tchanged code for better performance\n\nhm\t30. oct. 200\trev 1.2\n\tdeleted unnecessary init with 0\n\nhm\t14. mar. 2009\trev 1.3\n\tremoved double assignments\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FF_DRE.st", - "source": "FUNCTION_BLOCK FF_DRE\nVAR_INPUT\n\tSET : BOOL;\n\tD : BOOL;\n\tCLK : BOOL;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\nEND_VAR\nVAR\n\tedge : BOOL;\nEND_VAR\n\n\n(*\nversion 1.2\t30. oct. 2008\nprogrammer \thugo\ntested by\toscat\n\nD-type flip flop with set, reset and rising clock trigger\n\n*)\n\nIF rst OR set THEN\n\tQ := NOT rst;\nELSIF clk AND NOT edge THEN\n\tQ := D;\nEND_IF;\nedge := CLK;\n\n(* revision history\nhm\t4. aug 2006\t\trev 1.0\n\toriginal version\n\nhm\t27. dec 2007\trev 1.1\n\tchanged code for better performance\n\nhm\t30. oct. 2008\trev 1.2\n\toptimized performance\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FF_JKE.st", - "source": "FUNCTION_BLOCK FF_JKE\nVAR_INPUT\n\tSET : BOOL;\n\tJ : BOOL;\n\tCLK : BOOL;\n\tK : BOOL;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\nEND_VAR\nVAR\n\tedge : BOOL;\nEND_VAR\n\n\n(*\nversion 1.2\t30. oct. 2008\nprogrammer \thugo\ntested by\toscat\n\nJK-type flip flop with set, reset and rising clock trigger\nset and reset are asynchron while the FF is rising edge triggered\nJ=0 and K=0 and CLK >>> no action\nJ=1 and K=0 and CLK >>> output = 1\nJ=0 and K=1 and CLK >>> output = 0\nJ=1 and K=1 and CLK >>> toggle output\n\n\n*)\n\nIF rst OR set THEN\n\tQ := NOT rst;\nELSIF clk AND NOT edge THEN\n\tIF J XOR K THEN Q := J;\n\tELSE Q := K XOR Q;\n\tEND_IF;\nEND_IF;\nedge := CLK;\n\n(* revision history\nhm\t4. aug 2006\t\trev 1.0\n\toriginal version\n\nhm\t27. dec 2007\trev 1.1\n\tchanged code for better performance\n\nhm\t30. oct. 2008\trev 1.2\n\toptimized performance\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FF_RSE.st", - "source": "FUNCTION_BLOCK FF_RSE\nVAR_INPUT\n\tCS : BOOL;\n\tCR : BOOL;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\nEND_VAR\nVAR\n\tes, er : BOOL;\nEND_VAR\n\n(*\nversion 1.0\t16. jul. 2008\nprogrammer \thugo\ntested by\toscat\n\nthis is a rising edge triggered rs flip flop\na rising edge on CS sets Q = TRUE and a rising edge on CR sets Q = FALSE.\nCR has priority over CS.\n\n*)\n\nIF rst THEN\n\t(* asynchronous reset *)\n\tQ := FALSE;\nELSIF CR AND NOT er THEN\n\t(* rising edge on CR *)\n\tQ := FALSE;\nELSIF CS AND NOT es THEN\n\t(* rising edge on CS *)\n\tQ := TRUE;\nEND_IF;\n\nes := CS;\ner := CR;\n\n(* revision history\n\nhm\t16. jul. 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FIB.st", - "source": "FUNCTION FIB : DINT\nVAR_INPUT\n\tX : INT;\nEND_VAR\nVAR\n\tt1, t2: DINT;\nEND_VAR\n\n(*\nversion 1.3\t26. mar. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the fibonacci sequence\n\n*)\n\nIF X < 0 OR X > 46 THEN\n\tFIB := -1;\nELSIF x < 2 THEN\n\tFIB := X;\n\tRETURN;\nELSE\n\t(* the fibonacci number is the sum of the two suceeding fibonaci numbers *)\n\t(* we store the numbers alternatively in t1 and t2 depending on pt *)\n\tt2 := 1;\n\tWHILE X > 3 DO\n\t\tX := X-2;\n\t\tt1 := t1 + t2;\n\t\tt2 := t1 + t2;\n\tEND_WHILE;\n\tIF X > 2 THEN t1 := t1 + t2; END_IF;\n\tfib := t1 + t2;\nEND_IF;\n\n(* alternative code for very big numbers\n\nIF X < 31 THEN\n\tfib := 0.4472136 * (expn(1.618034,X) - expn(-0.618034,X));\nELSE\n\tfib := 0.4472133 * expn(1.618034,X);\nEND_IF;\n\n*)\n\n(* revision history\nhm\t\t27. dec 2007\trev 1.0\n\toriginal version\n\nhm\t\t2. jan 2008\trev 1.1\n\tdeleted unused variable pt\n\nhm\t\t10. mar 2008\trev 1.2\n\tchanged output to dint instead of real\n\nhm\t\t26. mar. 2008\trev 1.3\n\tfunction now returns -1 for input < 0 or > 46\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "FIFO_16.st", - "source": "FUNCTION_BLOCK FIFO_16\nVAR_INPUT\n\tDin : DWORD;\n\tE : BOOL := TRUE;\n\tRD : BOOL;\n\tWD : BOOL;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tDout : DWORD;\n\tEMPTY : BOOL := TRUE;\n\tFULL : BOOL;\nEND_VAR\nVAR\n\tfifo : ARRAY[0..n] OF DWORD;\n\tpr : INT;\n\tpw : INT;\nEND_VAR\nVAR CONSTANT\n\tn : INT := 16;\t(* changing this value will chage the number of stored elements in the fifo *)\nEND_VAR\n\n\n(*\nversion 2.0\t24. jul. 2009\nprogrammer \thugo\ntested by\t\toscat\n\n16 Dword FIFO memory\n*)\n\nIF RST THEN\n\tpw := pr;\n\tFULL := FALSE;\n\tEMPTY := TRUE;\n\tDout := 0;\nELSIF E THEN\n\tIF NOT EMPTY AND RD THEN\n\t\tDout := fifo[pr];\n\t\tpr := INC1(pr,n);\n\t\tEMPTY := pr = pw;\n\t\tFULL := FALSE;\n\tEND_IF;\n\tIF NOT FULL AND WD THEN\n\t\tfifo[pw] := Din;\n\t\tpw := INC1(pw,n);\n\t\tFULL := pw = pr;\n\t\tEMPTY := FALSE;\n\tEND_IF;\nEND_IF;\n\n\n(* revision history\n\nhm\t4. aug. 2006\trev 1.0\n\toriginal version\n\nhm\t19. feb 2008\trev 1.1\n\tperformance improvements\n\nhm\t17. oct. 2008\trev 1.2\n\timproved performance\n\nks\t27. oct. 2008\trev 1.3\n\toptimized coding\n\nhm\t14. mar. 2009\trev 1.4\n\tremoved double assignments\n\nhm 24. jul. 2009\trev 2.0\n\tchaged inputs E and WR to E, WD and WR\n\tallow read and write in one cycle\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FIFO_32.st", - "source": "FUNCTION_BLOCK FIFO_32\nVAR_INPUT\n\tDin : DWORD;\n\tE : BOOL := TRUE;\n\tRD : BOOL;\n\tWD : BOOL;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tDout : DWORD;\n\tEMPTY : BOOL := TRUE;\n\tFULL : BOOL;\nEND_VAR\nVAR\n\tfifo : ARRAY[0..n] OF DWORD;\n\tpr : INT;\n\tpw : INT;\nEND_VAR\nVAR CONSTANT\n\tn : INT := 32;\t(* changing this value will chage the number of stored elements in the fifo *)\nEND_VAR\n\n(*\nversion 2.0\t24. jul. 2009\nprogrammer \thugo\ntested by\t\toscat\n\n32 Dword FIFO memory\n*)\n\nIF RST THEN\n\tpw := pr;\n\tFULL := FALSE;\n\tEMPTY := TRUE;\n\tDout := 0;\nELSIF E THEN\n\tIF NOT EMPTY AND RD THEN\n\t\tDout := fifo[pr];\n\t\tpr := INC1(pr,n);\n\t\tEMPTY := pr = pw;\n\t\tFULL := FALSE;\n\tEND_IF;\n\tIF NOT FULL AND WD THEN\n\t\tfifo[pw] := Din;\n\t\tpw := INC1(pw,n);\n\t\tFULL := pw = pr;\n\t\tEMPTY := FALSE;\n\tEND_IF;\nEND_IF;\n\n(* revision history\nhm\t4. aug. 2006\trev 1.0\n\toriginal version\n\nhm\t19. feb 2008\trev 1.1\n\tperformance improvements\n\nhm\t17. oct. 2008\trev 1.2\n\timproved performance\n\nks\t27. oct. 2008 rev 1.3\n\timproved code\n\nhm\t14. mar. 2009\trev 1.4\n\tremoved double assignments\n\nhm 24. jul. 2009\trev 2.0\n\tchaged inputs E and WR to E, WD and WR\n\tallow read and write in one cycle\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FILL.st", - "source": "FUNCTION FILL : STRING(STRING_LENGTH)\nVAR_INPUT\n\tC : BYTE;\n\tL : INT;\nEND_VAR\nVAR\n\ti: INT;\n\tsx: STRING(1);\nEND_VAR\n\n(*\nversion 1.1\t17. dec. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nthe function fill creates a string at length L of characters C.\n\n*)\n\nSx := CHR_TO_STRING(c);\n(* limit L to maximum 80 characters the length of a standard string *)\nL := LIMIT(0,L,STRING_LENGTH);\n(* create a string of characters to be connected to str *)\nFOR i := 1 TO 8 DO\n\tFILL := CONCAT(FILL,FILL);\n\tIF L.7 THEN FILL := CONCAT(FILL,Sx); END_IF;\n\tL := SHL(L,1);\nEND_FOR;\n\n\n\n\n(* revision histroy\nhm\t29. mar. 2008\trev 1.0\n\toriginal release\n\nhm\t17. dec. 2008\trev 1.1\n\tchanged function chr to chr_to_string\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "FILTER_DW.st", - "source": "FUNCTION_BLOCK FILTER_DW\nVAR_INPUT\n\tX : DWORD;\n\tT : TIME;\nEND_VAR\nVAR_OUTPUT\n\tY : DWORD;\nEND_VAR\nVAR\n\tlast : DWORD;\n\ttx: DWORD;\n\tinit: BOOL;\n\tYi : REAL;\nEND_VAR\n\n(*\nversion 1.1\t3. nov. 2008\nprogrammer \thugo\ntested by\t\toscat\n\nFILTER_DW is an low pass filter with a programmable time T used for DWORD format.\n \n*)\n\n(* read system time *)\ntx := T_PLC_MS();\n\n(* startup initialisation *)\nIF NOT init OR T = t#0s THEN\n\tinit := TRUE;\n\tYi := DWORD_TO_REAL(X);\nELSE\n\tYi := Yi + (DWORD_TO_REAL(X) - DWORD_TO_REAL(Y)) * DWORD_TO_REAL(tx - last) / TIME_TO_REAL(T);\nEND_IF;\nlast := tx;\n\nY := REAL_TO_DWORD(Yi);\n\n\n\n(*\nhm 10. oct. 2008\trev 1.0\n\toriginal version\n\nhm\t3. nov. 2008\tREV 1.1\n\tcorrected an overflow problem\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FILTER_I.st", - "source": "FUNCTION_BLOCK FILTER_I\nVAR_INPUT\n\tX : INT;\n\tT : TIME;\nEND_VAR\nVAR_OUTPUT\n\tY : INT;\nEND_VAR\nVAR\n\tYi : DINT;\n\tlast : DWORD;\n\ttx: DWORD;\n\tinit: BOOL;\nEND_VAR\n\n(*\nversion 1.0\t8. nov. 2008\nprogrammer \thugo\ntested by\toscat\n\nFILTER_I is a low pass filter with a programmable time T used for INT format.\n \n*)\n\n(* read system time *)\ntx := T_PLC_MS();\n\n(* startup initialisation *)\nIF NOT init OR T = t#0s THEN\n\tinit := TRUE;\n\tYi := INT_TO_DINT(X) * 1000;\nELSE\n\t(* to increase accuracy of the filter we calculate internal Yi wich is Y * 1000 *)\n\tYi := Yi + INT_TO_DINT(X - Y) * DWORD_TO_DINT(tx - last) * 1000 / TIME_TO_DINT(T);\nEND_IF;\nlast := tx;\nY := DINT_TO_INT(yi / 1000);\n\n\n\n(*\nhm 8. nov. 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FILTER_MAV_DW.st", - "source": "FUNCTION_BLOCK FILTER_MAV_DW\nVAR_INPUT\n\tX : DWORD;\n\tN : UINT;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tY : DWORD;\nEND_VAR\nVAR\n\tinit: BOOL;\n\tbuffer : ARRAY[0..31] OF DWORD;\n\ti: INT;\nEND_VAR\nVAR_TEMP\n\ttmp: INT;\nEND_VAR\n\n(*\nversion 1.3\t23. feb. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nFILTER_MAV_DW is a moving average filter with programmable length N for DWORD Data.\n \n*)\n\n(* limit N to size of buffer *)\nN := MIN(N, 32);\n\n(* startup initialisation *)\nIF NOT init OR rst OR N = 0 THEN\n\tinit := TRUE;\n\ttmp := UINT_TO_INT(N)-1;\n\tFOR i := 0 TO tmp DO\n\t\tbuffer[i] := X;\n\tEND_FOR;\n\tY := X;\nELSE\n\ttmp := UINT_TO_INT(N);\n\ti := INC1(i, tmp);\n\tY := Y + (X - buffer[i]) / N;\n\tbuffer[i] := X;\nEND_IF;\n\n\n\n\n(*\nhm 13. oct. 2008\trev 1.0\n\toriginal version\n\nhm\t27. oct. 2008\trev 1.1\n\tadded typecast to avoid warnings\n\nhm\t24. nov. 2008\trev 1.2\n\tadded typecasts to avoid warnings\n\tavoid divide by 0 if N = 0\n\nhm\t23. feb. 2009\trev 1.3\n\tlimit N to max array size\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FILTER_MAV_W.st", - "source": "FUNCTION_BLOCK FILTER_MAV_W\nVAR_INPUT\n\tX : WORD;\n\tN : UINT;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tY : WORD;\nEND_VAR\nVAR\n\tinit: BOOL;\n\tbuffer : ARRAY[1..32] OF WORD;\n\ti: INT;\n\tsum : DWORD;\nEND_VAR\nVAR_TEMP\n\ttmp : INT;\nEND_VAR\n\n(*\nversion 1.4\t26. MAR. 2011\nprogrammer \thugo\ntested by\t\toscat\n\nFILTER_MAV_W is a moving average filter with programmable length N for WORD Data.\n \n*)\n\n(* limit N to size of buffer *)\nN := MIN(N, 32);\n\n(* startup initialisation *)\nIF NOT init OR rst OR N = 0 THEN\n\tinit := TRUE;\n\ttmp := UINT_TO_INT(N) - 1;\n\tFOR i := 1 TO tmp DO\n\t\tbuffer[i] := X;\n\tEND_FOR;\n\tsum := Y * N;\n\tY := X;\nELSE\n\ttmp := UINT_TO_INT(N);\n\ti := INC1(i, tmp);\n\tsum := sum + X - buffer[i];\n\tY := DWORD_TO_WORD(sum / N);\n\tbuffer[i] := X;\nEND_IF;\n\n\n\n(*\nhm 13. oct. 2008\trev 1.0\n\toriginal version\n\nhm\t18. oct. 2008\trev 1.1\n\tadded typecast to avoid warnings\n\nhm\t24. nov. 2008\trev 1.2\n\tadded typecasts to avoid warnings\n\tavoid devide by 0 if N = 0\n\nhm\t23. feb. 2009\trev 1.3\n\tlimit N to max array size\n\nhm\t26. mar. 2011\trev 1.4\n\tcorrected error in calculation\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FILTER_W.st", - "source": "FUNCTION_BLOCK FILTER_W\nVAR_INPUT\n\tX : WORD;\n\tT : TIME;\nEND_VAR\nVAR_OUTPUT\n\tY : WORD;\nEND_VAR\nVAR\n\tlast : DWORD;\n\ttx: DWORD;\n\tinit: BOOL;\n\ttmp: DWORD;\nEND_VAR\n\n(*\nversion 1.2\t25. jan. 2011\nprogrammer \thugo\ntested by\toscat\n\nFILTER_W is an low pass filter with a programmable time T used for WORD format.\n \n*)\n\n(* read system time *)\ntx := T_PLC_MS();\n\n(* startup initialisation *)\nIF NOT init OR T = T#0s THEN\n\tinit := TRUE;\n\tlast := tx;\n\tY := X;\nELSIF Y = X THEN\n\tlast := tx;\nELSE\n\ttmp := WORD_TO_DWORD(X - Y) * (tx - last) / TIME_TO_DWORD(T);\n\tIF tmp <> 0 THEN\n\t\tY := DINT_TO_WORD(WORD_TO_DINT(Y) + DWORD_TO_DINT(tmp));\n\t\tlast := tx;\n\tEND_IF;\nEND_IF;\n\n(*\nhm 10. oct. 2008\trev 1.0\n\toriginal version\n\nhm\t3. nov. 2008\trev 1.1\n\tfixed overflow problem in formula\n\nhm\t25. jan. 2011\trev 1.2\n\tfixed error in formula\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FILTER_WAV.st", - "source": "FUNCTION_BLOCK FILTER_WAV\nVAR_INPUT\n\tX : REAL;\n\tW : ARRAY[0..15] OF REAL;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tY : REAL;\nEND_VAR\nVAR\n\tinit: BOOL;\n\tbuffer : ARRAY[0..15] OF REAL;\n\ti: INT;\n\tn: INT;\nEND_VAR\n\n(*\nversion 1.2\t10. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nFILTER_WAV is a moving average filter with programmable length N for DWORD Data.\n\n*)\n\n(* startup initialisation *)\nIF NOT init OR rst THEN\n\tinit := TRUE;\n\tFOR i := 0 TO 15 DO\n\t\tbuffer[i] := X;\n\tEND_FOR;\n\ti := 15;\n\tY := X;\nELSE\n\ti := INC1(i, 16);\n\tbuffer[i] := X;\nEND_IF;\n\n(* calculate the weighted average *)\nY := 0.0;\nFOR n := 0 TO 15 DO\n\tY := buffer[i] * W[n] + Y;\n\ti := DEC1(i, 16);\nEND_FOR;\n\n\n(*\nhm \t14. oct. 2008\trev 1.0\n\toriginal version\n\nhm\t27. oct. 2008\trev 1.1\n\tchanged _DEC and _INC to DEC1 and INC1\n\nhm\t10. mar. 2009\trev 1.2\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FINDB.st", - "source": "FUNCTION FINDB : INT\nVAR_INPUT\n\tstr1 : STRING(STRING_LENGTH);\n\tstr2 : STRING(STRING_LENGTH);\nEND_VAR\nVAR\n\tpos: INT;\n\tlength: INT;\nEND_VAR\n\n(*\nversion 1.3\t29. mar. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nthe function find searches an str1 for the presence of str2 and returns the first position of str1 of the last presence in instring.\nthe function is similar to find except it searches from the right to left.\n a 0 is returned if the string is not found.\n\n*)\n\nlength := LEN(str2);\nFOR pos := LEN(str1) - length + 1 TO 1 BY -1 DO\n\tIF MID(str1,length,pos) = str2 THEN\n\t\tFindB := pos;\n\t\tRETURN;\n\tEND_IF;\nEND_FOR;\nFindB := 0;\n\n(* revision history\nhm\t6. oct 2006\t\trev 1.0\n\toriginal version\n\nhm\t15 dec 2007\t\trev 1.1\n\tchanged code for better performance\n\nhm\t29. feb 2008\trev 1.2\n\tadded findb := 0 for compatibility reasons\n\nhm\t29. mar. 2008\trev 1.3\n\tchanged STRING to STRING(STRING_LENGTH)\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "FINDB_NONUM.st", - "source": "FUNCTION FINDB_NONUM : INT\nVAR_INPUT\n\tstr : STRING(STRING_LENGTH);\nEND_VAR\nVAR\n\tpos: INT;\n\tpt : POINTER TO BYTE;\nEND_VAR\n\n(*\nversion 1.3\t21. oct. 2008\nprogrammer \thugo\ntested by\toscat\n\nfindB_noNum searches str backwards and returns the last position which is not a number.\na number is characterized by a letter \"0..9\" or \".\"\n\n*)\n\npt := ADR(str) + LEN(str) - 1;\nFOR pos := LEN(str) TO 1 BY -1 DO;\n\tIF (PT^ < 48 AND PT^ <> 46) OR PT^ > 57 THEN\n\t\tFINDB_NONUM := pos;\n\t\tRETURN;\n\tEND_IF;\n\tPT := PT - 1;\nEND_FOR;\nFINDB_NONUM := 0;\n\n\n(* revision history\nhm\t6. oct 2006\t\trev 1.0\n\toriginal version\n\nhm\t29. feb 2008\trev 1.1\n\timproved performance\n\nhm\t29. mar. 2008\trev 1.2\n\tchanged STRING to STRING(STRING_LENGTH)\n\nhm\t21. oct. 2008\trev 1.3\n\toptimized code\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "FINDB_NUM.st", - "source": "FUNCTION FINDB_NUM : INT\nVAR_INPUT\n\tstr : STRING(STRING_LENGTH);\nEND_VAR\nVAR\n\tpos: INT;\n\tpt : POINTER TO BYTE;\nEND_VAR\n\n(*\nversion 1.2\t29. mar. 2008\nprogrammer \thugo\ntested by\ttobias\n\nfindB_Num searches str backward and returns the last position of a number\na number is characterized by a letter \"0..9\" or \".\"\n\n*)\n\npt := ADR(str) + LEN(str) - 1;\nFOR pos := LEN(str) TO 1 BY -1 DO;\n\tIF (PT^ > 47 AND PT^ < 58) OR PT^ = 46 THEN\n\t\tFINDB_NUM := pos;\n\t\tRETURN;\n\tEND_IF;\n\tPT := PT - 1;\nEND_FOR;\nFINDB_NUM := 0;\n\n(* revision history\nhm\t6. oct 2006\t\trev 1.0\n\toriginal version\n\nhm\t29. feb 2008\trev 1.1\n\timproved performance\n\nhm\t29. mar. 2008\trev 1.2\n\tchanged STRING to STRING(STRING_LENGTH)\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "FINDP.st", - "source": "FUNCTION FINDP : INT\nVAR_INPUT\n\tstr : STRING(STRING_LENGTH);\n\tsrc : STRING(STRING_LENGTH);\n\tpos: INT;\nEND_VAR\nVAR\n\ti: INT;\n\tls: INT;\n\tlx: INT;\n\tstp: INT;\nEND_VAR\n\n(*\nversion 1.2\t29. mar. 2008\nprogrammer \thugo\ntested by\ttobias\n\nthe function findP searches a string str for the occurence of src beginning at the position pos.\n\n*)\n\nls := LEN(str);\nlx := LEN(src);\nIF ls < lx OR lx = 0 THEN RETURN; END_IF;\nstp := ls - lx + 1;\nFOR i := MAX(pos,1) TO stp DO\n\tIF MID(str,lx,i) = src THEN\n\t\tFINDP := i;\n\t\tRETURN;\n\tEND_IF;\nEND_FOR;\nFINDP := 0;\n\n(* revision histroy\nhm\t4. feb. 2008\trev 1.0\n\toriginal release\n\nhm\t29. feb 2008\trev 1.1\n\tADDED MAX(pos,1) in loop initialization\n\nhm\t29. mar. 2008\trev 1.2\n\tchanged STRING to STRING(STRING_LENGTH)\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "FIND_CHAR.st", - "source": "FUNCTION FIND_CHAR : INT\nVAR_INPUT\n\tstr : STRING(STRING_LENGTH);\n\tpos : INT;\nEND_VAR\nVAR\n\ti: INT;\n\tpt : POINTER TO ARRAY[1..255] OF BYTE;\n\tstop: INT;\n\tX: BYTE;\nEND_VAR\n\n(*\nversion 1.3\t21. oct. 2008\nprogrammer \thugo\ntested by\ttobias\n\nfind_char searches str and returns the starting position of the first character that is not a control character.\ncontrol characters are the ascii character 00 .. 31 and 127\n\n*)\n\npt := ADR(str);\nstop := LEN(str);\nFOR i := MAX(pos,1) TO stop DO;\n\tX := pt^[i];\n\tIF X > 31 AND ((setup.EXTENDED_ASCII AND X <> 127) OR (NOT setup.EXTENDED_ASCII AND X < 127)) THEN\n\t\tFIND_CHAR := i;\n\t\tRETURN;\n\tEND_IF;\nEND_FOR;\nFIND_CHAR := 0;\n\n\n(* revision history\nhm\t29. feb 2008\trev 1.0\n\toriginal version\n\nhm\t26. mar. 2008\trev 1.1\n\tchar will now accept extended ascii\n\nhm\t29. mar. 2008\trev 1.2\n\tchanged STRING to STRING(STRING_LENGTH)\n\nhm\t21. oct. 2008\trev 1.3\n\tchanges setup constants\n\toptimized code\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "FIND_CTRL.st", - "source": "FUNCTION FIND_CTRL : INT\nVAR_INPUT\n\tstr : STRING(STRING_LENGTH);\n\tpos : INT;\nEND_VAR\nVAR\n\ti: INT;\n\tpt : POINTER TO ARRAY[1..255] OF BYTE;\n\tstop: INT;\n\tx: BYTE;\nEND_VAR\n\n(*\nversion 1.2\t29. mar. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nfind_ctrl searches str and returns the starting position of a control character\ncontrol characters are the ascii character 00 .. 31 and 127.\n\n*)\n\npt := ADR(str);\nstop := LEN(str);\nFOR i := MAX(pos,1) TO stop DO;\n\tx := PT^[I];\n\tIF x < 32 OR X = 127 THEN\n\t\tFIND_CTRL := i;\n\t\tRETURN;\n\tEND_IF;\nEND_FOR;\nFIND_CTRL := 0;\n\n\n(* revision history\nhm\t29. feb 2008\trev 1.0\n\toriginal version\n\nhm\t26. mar. 2008\trev 1.1\n\tcharacter 127 is now recognized as control\n\nhm\t29. mar. 2008\trev 1.2\n\tchanged STRING to STRING(STRING_LENGTH)\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "FIND_NONUM.st", - "source": "FUNCTION FIND_NONUM : INT\nVAR_INPUT\n\tstr : STRING(STRING_LENGTH);\n\tpos : INT;\nEND_VAR\nVAR\n\ti: INT;\n\tpt : POINTER TO ARRAY[1..255] OF BYTE;\n\tend: INT;\n\tX: BYTE;\nEND_VAR\n\n(*\nversion 1.3\t21. oct. 2008\nprogrammer \thugo\ntested by\ttobias\n\nfind_noNum searches str and returns the first position which is not a number.\na number is characterized by a letter \"0..9\" or \".\"\n\n*)\n\npt := ADR(str);\nend := LEN(str);\nFOR i := MAX(pos,1) TO end DO;\n\tX := pt^[i];\n\tIF (X < 48 AND X <> 46) OR X > 57 THEN\n\t\tFIND_NONUM := i;\n\t\tRETURN;\n\tEND_IF;\nEND_FOR;\nFIND_NONUM := 0;\n\n\n(* revision history\nhm\t6. oct. 2006\trev 1.0\n\toriginal version\n\nhm\t29. feb 2008\trev 1.1\n\tadded input pos to start search at position\n\nhm\t29. mar. 2008\trev 1.2\n\tchanged STRING to STRING(STRING_LENGTH)\n\nhm\t21. oct. 2008\trev 1.3\n\toptimized code\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "FIND_NUM.st", - "source": "FUNCTION FIND_NUM : INT\nVAR_INPUT\n\tstr : STRING(STRING_LENGTH);\n\tpos : INT;\nEND_VAR\nVAR\n\ti : INT;\n\tpt : POINTER TO ARRAY[1..255] OF BYTE;\n\tstop : INT;\n\tX: BYTE;\nEND_VAR\n\n(*\nversion 1.2\t29. mar. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nfind_Num searches str and returns the starting position of a number\na number is characterized by a letter \"0..9\" or \".\"\n\n*)\n\npt := ADR(str);\nstop := LEN(str);\nFOR i := MAX(pos,1) TO stop DO;\n\tX := pt^[i];\n\tIF (X > 47 AND X < 58) OR X = 46 THEN\n\t\tFIND_NUM := i;\n\t\tRETURN;\n\tEND_IF;\nEND_FOR;\nFIND_NUM := 0;\n\n\n(* revision history\nhm\t6. oct. 2006\trev 1.0\n\toriginal version\n\nhm\t29. feb 2008\trev 1.1\n\tadded input pos to start search at position\n\nhm\t29. mar. 2008\trev 1.2\n\tchanged STRING to STRING(STRING_LENGTH)\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "FIX.st", - "source": "FUNCTION FIX : STRING(STRING_LENGTH)\nVAR_INPUT\n\tstr : STRING(STRING_LENGTH);\n\tL : INT;\n\tC : BYTE;\n\tM : INT;\nEND_VAR\nVAR\n\tN : INT;\n\tSX: STRING(STRING_LENGTH);\nEND_VAR\n\n(*\nversion 1.0\t29. mar. 2008\nprogrammer \thugo\ntested by\ttobias\n\nthe function fix truncates a string at length L \nor if the string is shorter then L it will be filled with ending Spaces till its length = N.\n\n*)\n\n(* make sure L does not exceed the limits of a string *)\nN := LIMIT(0,L,STRING_LENGTH) - LEN(str);\nIF N <= 0 THEN\n\t(* truncate the string at length N *)\n\tIF M = 1 THEN\n\t\tFIX := RIGHT(str,L);\n\tELSE\n\t\tFIX := LEFT(str,L);\n\tEND_IF;\nELSIF M = 1 THEN\n\t(* connect fill characters at the beginning *)\n\tsx := FILL(C,N);\n\tFIX := CONCAT(sx,str);\nELSIF M = 2 THEN\n\t(* center str beween fill characters *)\n\t(* for an uneven number of fill characters, there is one more at the end *)\n\tsx := FILL(C,SHR(N+1,1));\n\tFIX := CONCAT(str,sx);\n\tSX := LEFT(sx,SHR(N,1));\n\tFIX := CONCAT(sx,FIX);\nELSE\n\t(* connect fill characters at the end *)\n\tSX := FILL(C,N);\n\tFIX := CONCAT(str,SX);\nEND_IF;\n\n\n(* revision histroy\nhm\t29. mar. 2008\trev 1.0\n\toriginal release\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "FLOAT_TO_REAL.st", - "source": "FUNCTION FLOAT_TO_REAL : REAL\nVAR_INPUT\n\tFLT : STRING(20);\nEND_VAR\nVAR\n\tpt : POINTER TO ARRAY[1..20] OF BYTE;\n\ti: INT;\n\tX: BYTE;\n\tsign: INT := 1;\n\tstop: INT;\n\ttmp: DINT;\n\td : INT;\nEND_VAR\n\n(*\nversion 1.3\t23. oct. 2008\nprogrammer \thugo\ntested by\toscat\n\nFLOAT_TO_REAL converts a string to a REAL.\nthe function ignores all wrong characters.\nthe comma can be , or .\nthe exponent has to start with capital E or lowercase e .\n\n\n*)\n\npt := ADR(FLT);\nstop := LEN(FLT);\n\n(* we first check for sign and exit if first number or dot is reached *)\nFOR i := 1 TO stop DO\n\tX := pt^[i];\n\tIF X > 47 AND X < 58 OR X = 46 THEN\n\t\tEXIT;\n\tELSIF X = 45 THEN\n\t\t(* code 45 is sign *)\n\t\tsign := -1;\n\tEND_IF;\nEND_FOR;\n\n(* now we scan numbers till end or dot or E is reached *)\nFOR i := i TO stop DO\n\tX := pt^[i];\n\tIF X = 44 OR X = 46 OR X = 69 OR X = 101 THEN\n\t\tEXIT;\n\t(* calculate the value of the digit *)\n\tELSIF X > 47 AND x < 58 THEN\n\t\ttmp := tmp * 10 + X - 48;\n\tEND_IF;\nEND_FOR;\n\n(* process the portion after the comma if comma or dot is reached exit if exponent starts *)\nIF x = 44 OR X = 46 THEN\n\tFOR i := i + 1 TO stop DO\n\t\tX := pt^[i];\n\t\tIF X = 69 OR X = 101 THEN\n\t\t\tEXIT;\n\t\tELSIF x > 47 AND x < 58 THEN\n\t\t\ttmp := tmp * 10 + X - 48;\n\t\t\td := d - 1;\n\t\tEND_IF;\n\tEND_FOR;\nEND_IF;\n\n(* process exponent if present *)\nIF X = 69 OR X = 101 THEN\n\td := d + DEC_TO_INT(RIGHT(FLT, stop - i));\nEND_IF;\n\nFLOAT_TO_REAL := EXPN(10, d) * DINT_TO_REAL(TMP * SIGN);\n\n\n\n\n(* revision histroy\nhm\t22. jun. 2008\trev 1.0\n\toriginal release\n\nhm\t2. oct. 2008\trev 1.1\n\tfixed an error, characters 8 and 9 would not be converted\n\nhm\t22. oct. 2008\trev 1.2\n\tlast fix was not done correctly\n\nhm\t23. oct. 2008\trev 1.3\n\toptimzed code\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "FLOOR.st", - "source": "FUNCTION FLOOR : INT\nVAR_INPUT\n\tX : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t21. mar. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nThis is a rounding function which returns the biggest possible integer which is less or equal to X.\nfloor(3.14) = 3\nfloor(-3.14) = -4\n\n*)\n\nFLOOR := REAL_TO_INT(X);\nIF FLOOR > X THEN\n\tFLOOR := FLOOR - 1;\nEND_IF;\n\n(* revision history\nhm\t\t7. feb 2007\t\trev 1.0\n\toriginlal version\n\nhm\t\t21. mar. 2008\trev 1.1\n\treplaced trunc with real_to_int for compatibility reasons\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "FLOOR2.st", - "source": "FUNCTION FLOOR2 : DINT\nVAR_INPUT\n\tX : REAL;\nEND_VAR\n\n\n\n(*\nversion 1.1\t4. apr. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nThis is a rounding function which returns the biggest possible integer which is less or equal to X.\nfloor2(3.14) = 3\nfloor2(-3.14) = -4\n\n*)\n\nFLOOR2 := REAL_TO_DINT(X);\nIF DINT_TO_REAL(FLOOR2) > X THEN\n\tFLOOR2 := FLOOR2 - 1;\nEND_IF;\n\n(* revision history\nhm\t21. mar. 2008\trev 1.0\n\toriginlal version\n\nhm\t4. apr. 2008\trev 1.1\n\tadded type conversion to avoid warnings under codesys 3.0\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "FLOW_METER.st", - "source": "FUNCTION_BLOCK FLOW_METER\nVAR_INPUT\n\tVX : REAL;\n\tE : BOOL;\n\tRST : BOOL;\nEND_VAR\nVAR_INPUT CONSTANT\n\tPULSE_MODE : BOOL;\n\tUPDATE_TIME : TIME := t#1s;\nEND_VAR\nVAR_OUTPUT\n\tF : REAL;\nEND_VAR\nVAR_IN_OUT\n\tX : REAL;\n\tY : UDINT;\nEND_VAR\nVAR\n\ttx, tl : TIME;\n\tint1 : INTEGRATE;\n\tinit: BOOL;\n\te_last : BOOL;\n\ttmp: INT;\n\tx_last : REAL;\n\ty_last : UDINT;\nEND_VAR\n\n(*\nversion 1.0\t23. jan. 2011\nprogrammer \thugo\ntested by\toscat\n\nFlow meter measures flow according to gated time or pulses.\n\n*)\n\nIF NOT init THEN\t(* init on power up *)\n\tinit := TRUE;\n\ttl := tx;\n\tx_last := X;\n\ty_last := Y;\n\tint1.K := 2.7777777777777777E-4;\nEND_IF;\n\n(* run integrator *)\nint1(E := NOT (RST OR PULSE_MODE) AND E, X := VX, Y := X);\t(* gated operation *)\n\nIF RST THEN\t\t(* reset *)\n\tX := 0.0;\n\tY := 0;\n\ttl := tx;\n\tx_last := 0.0;\n\ty_last := 0;\nELSIF E AND PULSE_MODE THEN\t(* check for pulse mode *)\n\tIF NOT e_last THEN X := X + VX; END_IF;\nEND_IF;\ne_last := E;\n\n(* reduce X to be less than 1 and increase Y respectively *)\nIF X > 1.0 THEN\n\ttmp := FLOOR(X);\n\tY := Y + INT_TO_UDINT(tmp);\n\tX := X - INT_TO_REAL(tmp);\nEND_IF;\n\n(* calculate the current flow *)\ntx := DWORD_TO_TIME(T_PLC_MS());\nIF tx - tl >= UPDATE_TIME AND UPDATE_TIME > t#0s THEN\n\tF := (UDINT_TO_REAL(Y - y_last) + X - x_last) / TIME_TO_REAL(tx - tl) * 3.6E6;\n\ty_last := Y;\n\tx_last := X;\n\ttl := tx;\nEND_IF;\n\n\n\n(* revision history\nhm\t23. jan. 2011\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FRACT.st", - "source": "FUNCTION FRACT : REAL\nVAR_INPUT\n\tx : REAL;\nEND_VAR\n\n\n(*\nversion 1.3\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function returns the fraction of a real number\nfract(3.14) = 0.14\n\n*)\n\nIF ABS(x) < 2.0E9 THEN\n\tFRACT := x - DINT_TO_REAL(D_TRUNC(x));\nELSE\n\tFRACT := 0.0;\nEND_IF;\n\n(* revision history\nhm\t4. aug 2006\trev 1.0\n\toriginal version\n\nhm\t11. mar 2008\trev 1.1\n\tadded dint_to_real for compatibility reasons\n\tnow returns 0 for number > 2e9\n\tchanged input to x\n\nhm\t21. mar. 2008\trev 1.2\n\tuse D_trunc instead of TRUNC for compatibility reasons\n\nhm\t10. mar. 2009\trev 1.3\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "FRACTION.st", - "source": "TYPE FRACTION :\nSTRUCT\n\tNUMERATOR : INT;\n\tDENOMINATOR : INT;\nEND_STRUCT\nEND_TYPE\n" - }, - { - "fileName": "FRMP_B.st", - "source": "FUNCTION FRMP_B : BYTE\nVAR_INPUT\n\tSTART : BYTE;\n\tDIR : BOOL;\n\tTD : TIME;\n\tTR : TIME;\nEND_VAR\nVAR\nEND_VAR\n\n\n(*\nversion 1.0\t\t17. feb. 2011\nprogrammer \thugo\ntested by\t\toscat\n\nthis function calculates a ramp and limits the output to 0 .. 255 without overflow problems\n\n*)\n\nIF TD < TR THEN\n\tFRMP_B := MIN(DWORD_TO_BYTE(SHL(TIME_TO_DWORD(TD), 8) / TIME_TO_DWORD(TR)), SEL(DIR, START, BYTE#255 - START));\n\tIF DIR THEN\n\t\tFRMP_B := START + FRMP_B;\n\tELSE\n\t\tFRMP_B := START - FRMP_B;\n\tEND_IF;\nELSE\n\tFRMP_B := SEL(DIR, 0, 255);\nEND_IF;\n\n\n(* revision history\n\n17. feb. 2011\trev 1.0\n\tnew module\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "FSTRING_TO_BYTE.st", - "source": "FUNCTION FSTRING_TO_BYTE : BYTE\nVAR_INPUT\n\tIN : STRING(12);\nEND_VAR\n\n\n(*\nversion 1.1\t20. sep. 2008\nprogrammer \thugo\ntested by\t\toscat\n\nFSTRING_TO_BYTE converts a formatted string into a byte.\nthe string can be of the form 2#01010, 8#7234, 16#2AD3 and 1234\n\n*)\n\nIF LEFT(IN, 2) = '2#' THEN\n\t(* we need to convert binary *)\n\tFSTRING_TO_BYTE := BIN_TO_BYTE(RIGHT(in, LEN(in) - 2));\nELSIF LEFT(in, 2) = '8#' THEN\n\t(* weneed to convert octals *)\n\tFSTRING_TO_BYTE := OCT_TO_BYTE(RIGHT(in, LEN(in) - 2));\nELSIF LEFT(in, 3) = '16#' THEN\n\t(* we need to convert hexadecimal *)\n\tFSTRING_TO_BYTE := HEX_TO_BYTE(RIGHT(in, LEN(in) - 3));\nELSE\n\t(* we assume decimal representation *)\n\tFSTRING_TO_BYTE := DEC_TO_BYTE(CLEAN(in,'0123456789'));\nEND_IF;\n\n\n(* revision histroy\nhm\t18. jun. 2008\trev 1.0\n\toriginal release\n\nhm\t20. sep. 2008\trev 1.1\n\tchanged length of input string from 20 to 12\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "FSTRING_TO_DT.st", - "source": "FUNCTION FSTRING_TO_DT : DT\nVAR_INPUT\n\tSDT : STRING(60);\n\tFMT : STRING(60);\nEND_VAR\nVAR CONSTANT\n\tignore: STRING(1) := '*'; (* ignore character is * *)\n\tfchar : STRING(1) := '#'; (* format character is # *)\nEND_VAR\nVAR\n\tc: STRING(1);\n\ttmp: STRING(20);\n\tend: INT;\n\tdy : INT := 1970;\n\tdm : INT := 1;\n\tdd : INT := 1;\n\tth : INT;\n\ttm : INT;\n\tts : INT;\nEND_VAR\n\n\n(*\nversion 1.0\t24. sep. 2008\nprogrammer \thugo\ntested by\toscat\n\nFSTRING_TO_DT converts Formatted String into a DT value.\n\n*)\n\n(* scan input string *)\nWHILE fmt <> '' DO\n\tc := LEFT(fmt,1);\n\tIF c = ignore THEN\n\t\t(* skip ignore characters *)\n\t\tfmt := DELETE(fmt,1,1);\n\t\tsdt := DELETE(sdt,1,1);\n\tELSIF C = fchar THEN\n\t\t(* format chracter found skip format char and read identifier *)\n\t\t(* store format identifier in c and skip to next char in fmt *)\n\t\tc := MID(fmt,1,2);\n\t\tfmt := DELETE(fmt,2,1);\n\t\t(* extract the substring until the end of sdt or to next char of fmt *)\n\t\tIF fmt = '' THEN\n\t\t\ttmp := sdt;\n\t\tELSE\n\t\t\t(* serach for end of substring *)\n\t\t\tend := FIND(sdt, LEFT(fmt,1))-1;\n\t\t\ttmp := LEFT(sdt, end);\n\t\t\tsdt := DELETE(sdt, end,1);\n\t\tEND_IF;\n\t\t(* extract information from substring *)\n\t\tIF c = 'Y' THEN\n\t\t\tdy := STRING_TO_INT(tmp);\n\t\t\tIF dy < 100 THEN dy := dy + 2000; END_IF;\n\t\tELSIF c = 'M' THEN\n\t\t\tdm := STRING_TO_INT(tmp);\n\t\tELSIF c = 'N' THEN\n\t\t\tdm := FSTRING_TO_MONTH(tmp,0);\n\t\tELSIF c = 'D' THEN\n\t\t\tdd := STRING_TO_INT(tmp);\n\t\tELSIF c = 'h' THEN\n\t\t\tth := STRING_TO_INT(tmp);\n\t\tELSIF c = 'm' THEN\n\t\t\ttm := STRING_TO_INT(tmp);\n\t\tELSIF c = 's' THEN\n\t\t\tts := STRING_TO_INT(tmp);\n\t\tEND_IF;\n\tELSIF c = LEFT(sdt,1) THEN\n\t\t(* skip matching characters *)\n\t\tfmt := DELETE(fmt,1,1);\n\t\tsdt := DELETE(sdt,1,1);\n\tELSE\n\t\tRETURN;\n\tEND_IF;\nEND_WHILE;\n\nFSTRING_TO_DT := SET_DT(dy,dm,dd,th,tm,ts);\n\n\n(* revision histroy\nhm\t24. sep. 2008\trev 1.0\n\toriginal release\n\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "FSTRING_TO_DWORD.st", - "source": "FUNCTION FSTRING_TO_DWORD : DWORD\nVAR_INPUT\n\tIN : STRING(40);\nEND_VAR\n\n\n(*\nversion 1.1\t20. sep. 2008\nprogrammer \thugo\ntested by\t\toscat\n\nFSTRING_TO_BYTE converts a formatted string into a byte.\nthe string can be of the form 2#01010, 8#7234, 16#2AD3 and 1234\n\n*)\n\nIF LEFT(IN, 2) = '2#' THEN\n\t(* we need to convert binary *)\n\tFSTRING_TO_DWORD := BIN_TO_DWORD(RIGHT(in, LEN(in) - 2));\nELSIF LEFT(in, 2) = '8#' THEN\n\t(* weneed to convert octals *)\n\tFSTRING_TO_DWORD := OCT_TO_DWORD(RIGHT(in, LEN(in) - 2));\nELSIF LEFT(in, 3) = '16#' THEN\n\t(* we need to convert hexadecimal *)\n\tFSTRING_TO_DWORD := HEX_TO_DWORD(RIGHT(in, LEN(in) - 3));\nELSE\n\t(* we assume decimal representation *)\n\tFSTRING_TO_DWORD := DEC_TO_DWORD(CLEAN(in,'0123456789'));\nEND_IF;\n\n\n(* revision histroy\nhm\t18. jun. 2008\trev 1.0\n\toriginal release\n\nhm\t20. sep. 2008\trev 1.1\n\tchanged length of input dtring from 20 to 40\n\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "FSTRING_TO_MONTH.st", - "source": "FUNCTION FSTRING_TO_MONTH : INT\nVAR_INPUT\n\tMTH : STRING(20);\n\tLANG : INT;\nEND_VAR\nVAR\n\tlx: INT;\nEND_VAR\n\n\n(*\nversion 1.2\t25. oct 2008\nprogrammer \thugo\ntested by\toscat\n\nFSTRING_TO_MONTH converts a string into a month, the string can be a name for the month or a number.\nthe function is language sensitve when LANG > 1 and checks for all languages when LANG = 0\n\n*)\n\nIF LANG = 0 THEN lx := LANGUAGE.DEFAULT; ELSE lx := MIN(LANG, LANGUAGE.LMAX); END_IF;\nMTH := TRIM(mth);\nMTH := CAPITALIZE(LOWERCASE(MTH));\n\nFOR FSTRING_TO_MONTH := 1 TO 12 DO\n\tIF MTH = language.MONTHS[lx, FSTRING_TO_MONTH] THEN RETURN; END_IF;\n\tIF MTH = language.MONTHS3[lx, FSTRING_TO_MONTH] THEN RETURN; END_IF;\nEND_FOR;\n\n(* since no name matched try to decode as integer *)\nFSTRING_TO_MONTH := STRING_TO_INT(MTH);\n\n\n\n\n(* revision histroy\nhm\t25. sep. 2008\trev 1.0\n\toriginal release\n\nhm\t19. oct. 2008\trev 1.1\n\tchanged language setup constants\n\nhm\t25. oct. 2008\trev 1.2\n\toptimized code\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "FSTRING_TO_WEEK.st", - "source": "FUNCTION FSTRING_TO_WEEK : BYTE\nVAR_INPUT\n\tWEEK : STRING(60);\n\tLANG : INT;\nEND_VAR\nVAR\n\tpos: INT;\nEND_VAR\n\n\n(*\nversion 1.1\t25. oct. 2008\nprogrammer \thugo\ntested by\toscat\n\nFSTRING_TO_WEEK converts a list of weekdays into a byte where each bit represents a day of the week.\nbit 6 = mo, 0 = su;\n\n*)\n\npos := FIND(WEEK, ',');\nWHILE pos > 0 DO\n\tFSTRING_TO_WEEK := FSTRING_TO_WEEK OR SHR(BYTE#128, FSTRING_TO_WEEKDAY(MID(WEEK, pos - 1, 1), LANG));\n\tWEEK := RIGHT(WEEK, LEN(Week) - pos);\n\tpos := FIND(WEEK, ',');\nEND_WHILE;\nFSTRING_TO_WEEK := (FSTRING_TO_WEEK OR SHR(BYTE#128, FSTRING_TO_WEEKDAY(WEEK, LANG))) AND BYTE#127;\n\n\n(* revision histroy\nhm\t18. jun. 2008\trev 1.0\n\toriginal release\n\nhm\t25. oct. 2008\trev 1.1\n\tusing language defauls and input lang\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "FSTRING_TO_WEEKDAY.st", - "source": "FUNCTION FSTRING_TO_WEEKDAY : INT\nVAR_INPUT\n\tWDAY : STRING(20);\n\tLANG : INT;\nEND_VAR\nVAR\n\ttmp: STRING(2);\n\ti: INT;\n\tly: INT;\nEND_VAR\n\n\n(*\nversion 1.2\t25. oct. 2008\nprogrammer \thugo\ntested by\toscat\n\nFSTRING_TO_WEEKDAY converts a weekday string into an integer 1..7.\n\n*)\n\nIF LANG = 0 THEN ly := LANGUAGE.DEFAULT; ELSE ly := MIN(LANG, LANGUAGE.LMAX); END_IF;\n(* tmp needs to be calculated first otherwise find can return wrong values *)\ntmp := TRIM(wday);\ntmp := CAPITALIZE(LOWERCASE(tmp));\nFOR i := 1 TO 7 DO\n\tIF language.WEEKDAYS2[ly, i] = tmp THEN\n\t\tFSTRING_TO_WEEKDAY := i;\n\t\tRETURN;\n\tEND_IF;\nEND_FOR;\nFSTRING_TO_WEEKDAY := STRING_TO_INT(WDAY);\n\n\n\n\n(* revision histroy\nhm\t18. jun. 2008\trev 1.0\n\toriginal release\n\nhm\t18. jul. 2008\trev 1.1\n\tchanged nested call of left(trim()) for compatibility reasons\n\nhm\t25. oct. 2008\trev 1.2\n\tusing language constants\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "FT_AVG.st", - "source": "FUNCTION_BLOCK FT_AVG\nVAR_INPUT\n\tIN : REAL;\n\tE : BOOL := TRUE;\n\tN : INT := 32;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tAVG : REAL;\nEND_VAR\nVAR\n\tbuff : DELAY;\n\ti: INT;\n\tinit : BOOL;\nEND_VAR\n\n(*\nversion 1.5\t10. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nthis function calculates the moving average over n samples from a sequential input\nthe input values are shifted into an N deep buffer and the avg of this buffer is diplayed at anytime on the output.\na rst will load the buffer with the current in value..\n\n*)\n\n(* limit n to a max of 32 because delay can do max 32 cycles *)\nbuff.N := LIMIT(0, N, 32);\n\nIF NOT init OR rst THEN\n\tFOR i := 1 TO N DO\n\t\tbuff(in := in);\n\tEND_FOR;\n\tavg := in;\n\tinit := TRUE;\nELSIF E THEN\n\tbuff(in := in);\n\tavg := avg + (in - buff.out ) / INT_TO_REAL(N);\nEND_IF;\n\n(* revision history\n\nhm\t7. jan. 2007\trev 1.1\n\tchaged rst logic to load the buffer with the actual input value instead of 0.\n\tadded en input to allow better control of signal flow\n\tadded init to load the buffer with in at startup to avoid rampup at beginning.\n\tdeleted unused variable cnt.\n\nhm\t14. jun. 2008\trev 1.2\n\tset default for input en = TRUE and N = 32\n\nhm\t10. oct. 2008\trev 1.3\n\timproved performance\n\nhm\t18. oct. 2008\trev 1.4\n\tchanged input en to e for compatibility reasons\n\nhm\t10. mar. 2009\trev 1.5\n\tadded type conversion for compatibility reasons\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FT_DERIV.st", - "source": "FUNCTION_BLOCK FT_DERIV\nVAR_INPUT\n\tin : REAL;\n\tK : REAL := 1.0;\n\trun : BOOL := TRUE;\nEND_VAR\nVAR_OUTPUT\n\tout : REAL;\nEND_VAR\nVAR\n\told: REAL;\n\ttx: DWORD;\n\tlast: DWORD;\n\tinit: BOOL;\n\ttc: REAL;\nEND_VAR\n\n\n(*\nversion 1.5\t11. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nFT_deriv calculates the derivate over the signal \"in\" with Faktor \"K\".\na run input enables or stops the calculation, if left unconnected its true and therfore the calculation is executed.\nif K is not specified the default is 1.\n\n*)\n\n(* read system time *)\ntx := T_PLC_US();\ntc := DWORD_TO_REAL(tx - last);\nlast := tx;\n\n(* init on first startup *)\nIF NOT init THEN\n\tinit := TRUE;\n\told := in;\nELSIF run AND tc > 0.0 THEN\n\tout := (in - old) / tc * 1000000.0 * K;\n\told := in;\nELSE\n\tout := 0.0;\nEND_IF;\n\n\n\n(*\nhm 3.1.2007\t\t\trev 1.1\n\tadded init code for startup\n\tset the default for K to 1\n\nhm\t15. sep 2007\trev 1.2\n\treplaced Time() with T_PLC_US for compatibility and performance reasons\n\tincreased accuracy and work in microseconds internally\n\nhm 29 oct 2007\trev 1.3\n\tprohibit calculation when tx - last = 0 to avoid division by 0 and increase accuracy on fast systems\n\nhm\t6. nov. 2008\trev 1.4\n\timproved performance\n\nhm\t11. mar. 2009\trev 1.5\n\tinproved code\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FT_IMP.st", - "source": "FUNCTION_BLOCK FT_IMP\nVAR_INPUT\n\tin : REAL;\n\tT : TIME;\n\tK : REAL := 1.0;\nEND_VAR\nVAR_OUTPUT\n\tout : REAL;\nEND_VAR\nVAR\n\tt1 : FT_PT1;\nEND_VAR\n\n(*\nversion 1.1\t3 Jan 2007\nprogrammer \thugo\ntested by\toscat\n\nFT_IMP is \tan impulse filter (high pass filter) with the time T and factor K.\n \n*)\n\nT1(in:= in, T:=T);\nout := (in - t1.out) * K;\n\n(*\nhm 3.1.2007\trev 1.1\n\tadded factor K\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FT_INT.st", - "source": "FUNCTION_BLOCK FT_INT\nVAR_INPUT\n\tIN : REAL;\n\tK : REAL := 1;\n\tRUN : BOOL := TRUE;\n\tRST : BOOL;\n\tOUT_MIN : REAL := -1E37;\n\tOUT_MAX : REAL := 1E37;\nEND_VAR\nVAR_OUTPUT\n\tOUT : REAL;\n\tLIM : BOOL;\nEND_VAR\nVAR\n\tINTeg : INTEGRATE;\nEND_VAR\n\n\n(*\nversion 2.2\t10. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nFT_int is an integrator with input IN and factor K.\nintegration is only done while run = true, if run is false integration is stopped and the out remains at the last value.\nif run is left unconnected, run is considered true by the function block.\nthe output ET will display the total integration time from last reset.\nthe out_min and out_max values can be set to ,imit the output value range. \nthe default for K is 1.\n\n \n*)\n\nIF rst THEN\n\tout := 0.0;\nELSE\n\tinteg(X := IN, E := RUN, K := K, Y := out);\nEND_IF;\n\n(* limit the outputs *)\nIF out >= OUT_MAX THEN\n\tout := out_max;\n\tLIM := TRUE;\nELSIF out <= out_min THEN\n\tout := out_min;\n\tlim := TRUE;\nELSE\n\tlim := FALSE;\nEND_IF;\n\n\n(*\nhm 13.12.2006\trev 1.1\n\tchanged to \"trapezregel\" which increases accuracy\n\tbefore out := out + in * time new: out := out + (in + in_last) / 2 * time\n\nhm 15.1.2007\t\trev 1.2\n\tadded default for k to be 1.\n\nhm\t15.9.2007\t\trev 1.3\n\treplaced time() with T_PLC_US for compatibility and performance reason\n\tincreased internal accuracy to microseconds\n\nhm 29. oct 2007\t\trev 1.4\n\tchanged code so int will not be called is time difference is 0 to increase accuracy on systems\n\twith cycle times below 1ms\n\nhm\t2. dec 2007\t \trev 1.5\n\tchanged code for better performance\n\nhm\t5. jan 2008\t\trev 1.6\n\tfurther improvements in performance\n\nhm\t8. feb 2008\t\trev 1.7\n\tdeleted limits +/- 1000 now limit is the range of real\n\tadded variables out1 and out2 to extend the resolution\n\tcorrected an error with elapsed time\n\tdeleted unusfull output ET\n\nhm\t13. mar 2008\trev 1.8\n\tchanged preset value out_min to -1e37.\n\tstop integrator at the limits.\n\nhm\t16. mar 2008\trev 1.9\n\tadded type conversion to avoid warning under codesys 3.0\n\nhm\t2. jun. 2008\trev 2.0\n\trewritten with clear code\n\tlimits can now be set without run\n\nhm\t3. nov. 2008\trev 2.1\n\toptimized code using INTEGRATE and LIMX\n\nhm\t10. mar. 2009\trev 2.2\n\tremoved nested comments\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FT_INT2.st", - "source": "FUNCTION_BLOCK FT_INT2\nVAR_INPUT\n\tIN : REAL;\n\tK : REAL := 1.0;\n\tRUN : BOOL := TRUE;\n\tRST : BOOL;\n\tOUT_MIN : REAL := -1.0E38;\n\tOUT_MAX : REAL := 1.0E38;\nEND_VAR\nVAR_OUTPUT\n\tOUT : REAL;\n\tLIM : BOOL;\nEND_VAR\nVAR\n\tinteg: INTEGRATE;\n\tix : REAL;\n\tval : REAL2;\nEND_VAR\n\n\n(*\nversion 1.2\t11. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nFT_int2 is an integrator with input IN and factor K.\nintegration is only done while run = true, if run is false integration is stopped and the out remains at the last value.\nif run is left unconnected, run is considered true by the function block.\nthe out_min and out_max values can be set to ,imit the output value range. \nthe default for K is 1.\nFT_INT2 has double presision accuracy (14 digits).\n\n\n*)\n\nIF RST THEN\n\tval := R2_SET(0.0);\n\tout := 0.0;\nELSE\n\tinteg(X := IN, E := RUN, K := K, Y := ix);\n\tval := R2_ADD(val, ix);\n\tix := 0.0;\n\tOUT := val.RX;\nEND_IF;\n\n(* check output for limits *)\nIF out > OUT_MIN AND out < OUT_MAX THEN\n\tLIM := FALSE;\nELSE\n\tOUT := LIMIT(OUT_MIN, OUT, OUT_MAX);\n\tval := R2_SET(OUT);\n\tLIM := TRUE;\nEND_IF;\n\n\n\n(*\trevision history\nhm\t2. jun. 2008\trev 1.0\n\toriginal version\n\nhm\t5. nov. 2008\trev 1.1\n\trewritten code using integrate\n\nhm\t11. mar. 2009\trev 1.2\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FT_MIN_MAX.st", - "source": "FUNCTION_BLOCK FT_MIN_MAX\nVAR_INPUT\n\tin : REAL;\n\trst : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tmx : REAL;\n\tmn : REAL;\nEND_VAR\nVAR\n\tinit: BOOL;\nEND_VAR\n\n(*\nversion 1.0\t1 sep 2006\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function block stores the min and max value of an input signal.\nwhen rst is true the mn and mx outputs are set to the in value.\nwhen a rst is never active the function autoresets to the in value at startup.\nsince the input might not be present at first cycle the mn and mx are set during second cycle.\n\n*)\n\nIF rst OR NOT init THEN\n\tmn := in;\n\tmx := in;\n\tinit := TRUE;\nELSIF in < mn THEN mn := in;\nELSIF in > mx THEN mx := in;\nEND_IF;\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FT_PD.st", - "source": "FUNCTION_BLOCK FT_PD\nVAR_INPUT\n\tIN : REAL;\n\tKP : REAL := 1.0;\n\tTV : REAL := 1.0;\nEND_VAR\nVAR_OUTPUT\n\tY : REAL;\nEND_VAR\nVAR\n\tdiff : FT_DERIV;\nEND_VAR\n\n(*\nversion 1.0\t3. jun 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nFT_PD is a PD controller.\nThe PD controller works according to the fomula Y = KP *(IN + DERIV(e) ).\n\n*)\n\n(* run differentiator *)\ndiff(IN := IN, K := TV);\n\n(* combine both values *)\nY := KP * (diff.out + IN);\n\n\n\n(* revision history\nhm \t3. jun. 2008 \trev 1.0\n\toriginal version\n\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FT_PDT1.st", - "source": "FUNCTION_BLOCK FT_PDT1\nVAR_INPUT\n\tIN : REAL;\n\tKP : REAL := 1.0;\n\tTV : REAL := 1.0;\n\tT1 : REAL := 1.0;\nEND_VAR\nVAR_OUTPUT\n\tY : REAL;\nEND_VAR\nVAR\n\tdiff : FT_DERIV;\n\tTP : FT_PT1;\nEND_VAR\n\n(*\nversion 1.0\t3. jun 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nFT_PD is a PD controller.\nThe PD controller works according to the fomula Y = KP *(IN + DERIV(e) ).\n\n*)\n\n(* run differentiator *)\ndiff(IN := IN, K := TV);\n\n(* Run PT1 filter *)\ntp(in := diff.out, T := REAL_TO_TIME(T1));\n\n(* combine both values *)\nY := KP * (tp.out + IN);\n\n\n\n(* revision history\nhm \t3. jun. 2008 \trev 1.0\n\toriginal version\n\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FT_PI.st", - "source": "FUNCTION_BLOCK FT_PI\nVAR_INPUT\n\tIN : REAL;\n\tKP : REAL := 1.0;\n\tKI : REAL := 1.0;\n\tILIM_L : REAL := -1E38;\n\tILIM_H : REAL := 1E38;\n\tIEN : BOOL := TRUE;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tY : REAL;\n\tLIM : BOOL;\nEND_VAR\nVAR\n\tinteg : FT_INT;\nEND_VAR\n\n(*\nversion 2.0\t3. jun 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nFT_PI is a PI controller.\nThe PID controller works according to the fomula Y = IN *(KP+ KI * INTEG(e) ).\na rst will reset the integrator to 0\nilim_h and iLim_l set the possible output range of the internal integrator.\nthe output flags lim will signal that the output limits are active.\n\ndefault values for KP = 1, KI = 1, ILIM_L = -1E37, iLIM_H = +1E38.\n*)\n\n(* run integrator *)\ninteg(IN := IN, K := KI, RUN := IEN, RST := RST, OUT_MIN := ILIM_L, OUT_MAX := ILIM_H);\n\n(* check if integrator has reached its limits and set overflow *)\nLIM := integ.LIM;\nY := KP * IN + integ.Out;\n\n\n\n(* revision history\nhm \t3. jun. 2008 \trev 2.0\n\toriginal version\n\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FT_PID.st", - "source": "FUNCTION_BLOCK FT_PID\nVAR_INPUT\n\tIN : REAL;\n\tKP : REAL := 1.0;\n\tTN : REAL := 1.0;\n\tTV : REAL := 1.0;\n\tILIM_L : REAL := -1.0E38;\n\tILIM_H : REAL := 1.0E38;\n\tIEN : BOOL := TRUE;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tY : REAL;\n\tLIM : BOOL;\nEND_VAR\nVAR\n\tinteg : FT_INT;\n\tdiff : FT_DERIV;\nEND_VAR\n\n(*\nversion 2.1\t11. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nFT_PI is a PI controller.\nThe PID controller works according to the fomula Y = IN *(KP+ KI * INTEG(e) ).\na rst will reset the integrator to 0\nilim_h and iLim_l set the possible output range of the internal integrator.\nthe output flags lim will signal that the output limits are active.\n\ndefault values for KP = 1, KI = 1, ILIM_L = -1E37, iLIM_H = +1E38.\n*)\n\n(* run integrator only if TN > 0 *)\nIF TN > 0.0 THEN\n\tinteg(IN := IN, K := 1.0 / TN, RUN := IEN, RST := RST, OUT_MIN := ILIM_L, OUT_MAX := ILIM_H);\nELSE\n\tinteg(RST := FALSE);\nEND_IF;\n\n(* run differentiator *)\ndiff(IN := IN, K := TV);\n\n(* combine both values *)\nY := KP * (integ.Out + diff.out + IN);\n\n(* check if integrator has reached its limits and set overflow *)\nLIM := integ.LIM;\n\n\n\n(* revision history\nhm 3. jun. 2008 \trev 2.0\n\toriginal version\n\nhm\t11. mar. 2009\trev 2.1\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FT_PIDW.st", - "source": "FUNCTION_BLOCK FT_PIDW\nVAR_INPUT\n\tIN : REAL;\n\tKP : REAL := 1.0;\n\tTN : REAL := 1.0;\n\tTV : REAL := 1.0;\n\tLIM_L : REAL := -1.0E38;\n\tLIM_H : REAL := 1.0E38;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tY : REAL;\n\tLIM : BOOL;\nEND_VAR\nVAR\n\tinteg : INTEGRATE;\n\tdiff : FT_DERIV;\n\tYI: REAL;\nEND_VAR\n\n(*\nversion 1.2\t11. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nFT_PIDW is a PID controller with dynamic wind_up reset.\nThe PID controller works according to the fomula Y = KP *(IN + KI * INTEG(e) + DERIV(e) ).\na rst will reset the integrator to 0\nlim_h and Lim_l set the possible output range of the internal integrator.\nthe output flags lim will signal that the output limits are active.\n\ndefault values for KP = 1, KI = 1, ILIM_L = -1E37, iLIM_H = +1E38.\n*)\n\n(* run the integrator *)\nIF tn = 0.0 OR rst THEN\n\tinteg(E := FALSE, Y := YI);\n\tYI := 0.0;\nELSE\n\tinteg(X := IN, K := 1.0 / TN, E := NOT LIM, Y := YI);\nEND_IF;\n\n(* add up integrator and linear part *)\nY := KP * (IN + YI);\n\n(* run differentiator *)\ndiff(IN := IN, K := TV);\n\n(* set lim before differentiator is added to stop integrator if necessary *)\nIF Y > LIM_L AND Y < LIM_H THEN\n\tLIM := FALSE;\nELSE\n\tLIM := TRUE;\nEND_IF;\n\n(* add differential part and limit output Y *)\n\nY := LIMIT(LIM_L, Y + KP * diff.out, LIM_H);\n\n\n\n\n(* revision history\nhm 3. jun. 2008 \trev 1.0\n\toriginal version\n\nhm\t5. nov. 2008\trev 1.1\n\tchanged code to use integrate\n\nhm\t11. mar. 2009\trev 1.2\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FT_PIDWL.st", - "source": "FUNCTION_BLOCK FT_PIDWL\nVAR_INPUT\n\tIN : REAL;\n\tKP : REAL := 1.0;\n\tTN : REAL := 1.0;\n\tTV : REAL := 1.0;\n\tLIM_L : REAL := -1.0E38;\n\tLIM_H : REAL := 1.0E38;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tY : REAL;\n\tLIM : BOOL;\nEND_VAR\nVAR\n\tpiwl : FT_PIWL;\n\tdiff : FT_DERIV;\nEND_VAR\n\n(*\nversion 1.3\t13. nov. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nFT_PIDWL is a PID controller with dynamic wind_up reset.\nThe PID controller works according to the fomula Y = KP *(IN + KI * INTEG(e) + DERIV(e) ).\na rst will reset the integrator to 0\nlim_h and Lim_l set the possible output range of the internal integrator.\nthe output flags lim will signal that the output limits are active.\n\ndefault values for KP = 1, KI = 1, ILIM_L = -1E37, iLIM_H = +1E38.\n*)\n\n(* if rst then *)\nIF rst THEN\n\tpiwl(rst := TRUE);\n\tpiwl.RST := FALSE;\nELSE\n\t(* run PIWL controller first *)\n\t(* we need to check if TN = 0 and do alternative calls *)\n\tIF TN = 0.0 THEN\n\t\tpiwl(in := IN * KP, KP := 1.0, KI := 0.0, LIM_L := LIM_L, LIM_H := LIM_H);\n\tELSE\n\t\tpiwl(in := IN * KP, KP := 1.0, KI := 1.0 / TN, LIM_L := LIM_L, LIM_H := LIM_H);\n\tEND_IF;\n\n\t(* run differentiator and add_to_output *)\n\tdiff(IN := IN, K := KP * TV);\n\tY := piwl.Y + diff.out;\n\n\t(* limit the output *)\n\tIF Y < LIM_L THEN\n\t\tLIM := TRUE;\n\t\tY := LIM_L;\n\tELSIF Y > LIM_H THEN\n\t\tLIM := TRUE;\n\t\tY := LIM_H;\n\tELSE\n\t\tLIM := FALSE;\n\tEND_IF;\nEND_IF;\n\n\n\n(* revision history\nhm 13. jun. 2008 \trev 1.0\n\toriginal version\n\nhm\t25. jan 2008\trev 1.1\n\tmultiply differential part with KP\n\nhm\t11. mar. 2009\trev 1.2\n\treal constants updated to new systax using dot\n\nhm\t13. nov. 2009\trev 1.3\n\tfixed code for negative KP\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FT_PIW.st", - "source": "FUNCTION_BLOCK FT_PIW\nVAR_INPUT\n\tIN : REAL;\n\tKP : REAL := 1.0;\n\tKI : REAL := 1.0;\n\tLIM_L : REAL := -1E38;\n\tLIM_H : REAL := 1E38;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tY : REAL;\n\tLIM : BOOL;\nEND_VAR\nVAR\n\tinteg : FT_INT;\nEND_VAR\n\n(*\nversion 1.0\t3. jun 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nFT_PIW is a PI controller.\nThe PID controller works according to the fomula Y = IN *(KP+ KI * INTEG(e) ).\na rst will reset the integrator to 0\nilim_h and iLim_l set the possible output range of the internal integrator.\nthe output flag lim will signal that the output limits are active.\nthe controller is equipped with anti wind_up circuitry that stops the integrator when lim_h or lim_l is reached\n\n\ndefault values for KP = 1, KI = 1, ILIM_L = -1E37, iLIM_H = +1E38.\n*)\n\n(* run integrator *)\ninteg(IN := IN, K := KI, RUN := NOT LIM, RST := RST);\n\n(* set output value *)\nY := KP * IN + integ.Out;\n\n(* check for limits and set integrator for anti wind up *)\nIF Y < LIM_L THEN\n\tY := LIM_L;\n\tLIM := TRUE;\nELSIF Y > LIM_H THEN\n\tY := LIM_H;\n\tLIM := TRUE;\nELSE\n\tLIM := FALSE;\nEND_IF;\n\n\n\n(* revision history\nhm \t3. jun. 2008 \trev 1.0\n\toriginal version\n\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FT_PIWL.st", - "source": "FUNCTION_BLOCK FT_PIWL\nVAR_INPUT\n\tIN : REAL;\n\tKP : REAL := 1.0;\n\tKI : REAL := 1.0;\n\tLIM_L : REAL := -1.0E38;\n\tLIM_H : REAL := 1.0E38;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tY : REAL;\n\tLIM : BOOL;\nEND_VAR\nVAR\n\tinit: BOOL;\n\ttx: DWORD;\n\ttc : REAL;\n\tt_last: DWORD;\n\tin_last : REAL;\n\ti: REAL;\n\tp: REAL;\nEND_VAR\n\n(*\nversion 1.3\t11. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nFT_PIWL is a PI controller.\nThe PID controller works according to the fomula Y = IN *(KP+ KI * INTEG(e) ).\na rst will reset the integrator to 0\nlim_h and Lim_l set the possible output range of the controller.\nthe output flag lim will signal that the output limits are active.\nthe integrator ist equipped with anti wind-up circuitry which limits trhe total output ranke to lim_l and lim_h\n\ndefault values for KP = 1, KI = 1, ILIM_L = -1E37, iLIM_H = +1E38.\n*)\n\n(* initialize at power_up *)\nIF NOT init OR RST THEN\n\tinit := TRUE;\n\tin_last := in;\n\tt_last := T_PLC_US();\n\ti := 0.0;\n\ttc := 0.0;\nELSE\n\t(* read last cycle time in Microseconds *)\n\ttx := T_PLC_US();\n\ttc := DWORD_TO_REAL(tx - t_last);\n\tt_last := tx;\n\n\t(* calculate proportional part *)\n\tp := KP * IN;\n\n\t(* run integrator *)\n\ti := (IN + in_last) * 5.0E-7 * KI * tc + i;\n\tin_last := IN;\n\n\t(* calculate output Y *)\n\tY := p + i;\n\n\t(* check output for limits *)\n\tIF Y >= LIM_H THEN\n\t\tY := LIM_H;\n\t\tIF ki <> 0.0 THEN\n\t\t\ti := LIM_H - p;\n\t\tELSE\n\t\t\ti := 0.0;\n\t\tEND_IF;\n\t\tLIM := TRUE;\n\tELSIF Y <= LIM_L THEN\n\t\tY := LIM_L;\n\t\tIF ki <> 0.0 THEN\n\t\t\ti := LIM_L - p;\n\t\tELSE\n\t\t\ti := 0.0;\n\t\tEND_IF;\n\t\tLIM := TRUE;\n\tELSE\n\t\tLIM := FALSE;\n\tEND_IF;\nEND_IF;\n\n\n\n\n(* revision history\nhm 13. jun. 2008 \trev 1.0\n\toriginal version\n\nhm\t27. oct. 2008\trev 1.1\n\tintegrator will not be adjusted when ki = 0\n\nhm\t25. jan 2009\trev 1.2\n\tmodule will also work with negative K\n\nhm\t11. mar. 2009\trev 1.3\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FT_PT1.st", - "source": "FUNCTION_BLOCK FT_PT1\nVAR_INPUT\n\tin : REAL;\n\tT : TIME;\n\tK : REAL := 1.0;\nEND_VAR\nVAR_OUTPUT\n\tout : REAL;\nEND_VAR\nVAR\n\tlast : DWORD;\n\ttx: DWORD;\n\tinit: BOOL;\nEND_VAR\n\n(*\nversion 1.11\t18. jan. 2011\nprogrammer \thugo\ntested by\t\toscat\n\nFT_PT1 is an low pass filter with a programmable time T and faktor K.\n \n*)\n\n(* read system time *)\ntx := T_PLC_US();\n\n(* startup initialisation *)\nIF NOT init OR T = t#0s THEN\n\tinit := TRUE;\n\tout := K * in;\nELSE\n\tout := out + (in * K - out) * DWORD_TO_REAL(Tx - last) / TIME_TO_REAL(T) * 1.0E-3;\n\tIF ABS(out) < 1.0E-20 THEN out := 0.0; END_IF;\nEND_IF;\nlast := tx;\n\n\n(*\nhm 1.1.2007\trev 1.1\n\tcorrected error while startup value was not correct\n\tfor very small time values real output would run out of range.\n\nhm 3.1.2007\trev 1.2\n\tcorrected an error for falling edge failures.\n\tadded output faktor K.\n\nhm 27. 2. 2007\trev 1.3\n\toutput will be input during init for definitive startup condition.\n\nhm\t15.9.2007\trev 1.4\n\tchanged time() to T_PLC_US() for compatibilitxy resons\n\tincreased internal accuracy to Microseconds instead of Milliseconds\n\nhm\t23. oct 2007\trev 1.5\n\tadded out := in to the init statements\n\nhm\t30. nov 2007\trev 1.6\n\tchanged out to be K * in during initialization\n\nhm\t5. jan 2008\trev 1.7\n\timproved code for better performance\n\nhm\t16. mar. 2008\trev 1.8\n\tadded type conversion to avoid warning under codesys 3.0\n\nhm\t14. jun. 2008\trev 1.9\n\timproved code\n\nhm\t11. mar. 2009\trev 1.10\n\treal constants updated to new systax using dot\n\nhm\t18. jan. 2011\trev 1.11\n\tavoid underrun of out\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FT_PT2.st", - "source": "FUNCTION_BLOCK FT_PT2\nVAR_INPUT\n\tin : REAL;\n\tT : TIME;\n\tD : REAL;\n\tK : REAL := 1.0;\nEND_VAR\nVAR_OUTPUT\n\tout : REAL;\nEND_VAR\nVAR\n\tinit: BOOL;\n\tint1 : INTEGRATE;\n\tint2 : INTEGRATE;\n\ttn: REAL;\n\tI1, I2 : REAL;\n\ttn2: REAL;\nEND_VAR\n\n(*\nversion 1.5\t11. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nFT_PT2 is a 2nd grade filter with programmable times T, D and faktor K.\n \n*)\n\n(* startup initialisation *)\nIF NOT init OR T = T#0s THEN\n\tinit := TRUE;\n\tout := K * in;\n\tI2 := out;\nELSE\n\tTN := TIME_TO_REAL(T) * 1.0E-3;\n\ttn2 := TN * TN;\n\tint1(X := in * K / tn2 - I1 * 0.5 * D / TN - I2 / TN2, Y := I1);\n\tint2(X := I1,Y := I2);\n\tout := I2;\nEND_IF;\n\n\n(* revision history\n\n15.1.2007 hm\t\trev 1.1\n\tchanged formula to new more acurate formula\n\nhm 15.9.2007\t\trev 1.2\n\tdeleted unused code for init system time reading tx\t\n\nhm\t30.11.2007\trev 1.3\n\tchanged out to be K * in during initialization\n\tavoind divide by 0 if tn = 0\n\nhm\t3. nov. 2008\trev 1.4\n\toptimized code and fixed a problem with init\n\nhm\t11. mar. 2009\trev 1.5\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FT_Profile.st", - "source": "FUNCTION_BLOCK FT_Profile\nVAR_INPUT\n\tK : REAL := 1.0;\n\tO : REAL;\n\tM : REAL := 1.0;\n\tE : BOOL;\nEND_VAR\nVAR_INPUT CONSTANT\n\tvalue_0 : REAL;\n\ttime_1 : TIME;\n\tvalue_1 : REAL;\n\ttime_2 : TIME;\n\tvalue_2 : REAL;\n\ttime_3 : TIME;\n\tvalue_3 : REAL;\n\ttime_10 : TIME;\n\tvalue_10 : REAL;\n\ttime_11 : TIME;\n\tvalue_11 : REAL;\n\ttime_12 : TIME;\n\tvalue_12 : REAL;\n\ttime_13 : TIME;\n\tvalue_13 : REAL;\nEND_VAR\nVAR_OUTPUT\n\tY : REAL;\n\tRUN : BOOL;\n\tET : TIME;\nEND_VAR\nVAR\n\ttx : TIME;\n\tedge : BOOL;\n\tstate: BYTE;\n\tta: TIME;\n\ttb: TIME;\n\tt0 : TIME;\n\ttemp: REAL;\n\tva: REAL;\n\tvb: REAL;\nEND_VAR\n\n(*\nversion 1.1\t15 sep 2007\nprogrammer \ttobias\ntested by\t\thugo\n\nFT_Profile generates an output signal which is defined by values over a time scale.\nthe different values are connected by ramps between the individual values.\na rising edge on E starts the output signal generation and E = True can delay time_3 / value_3 as long as it stays true.\nan additional multiplier K can be used to multiply the output and an offset O can be added to the output dynamically.\n*)\n\n(* read system time *)\ntx := DWORD_TO_TIME(T_PLC_MS());\n\n(* determine start condition *)\nIF E AND NOT edge THEN\n\tRUN := TRUE;\n\tET := t#0s;\n\tt0 := tx;\n\tta := tx;\n\ttb := multime(time_1, M);\n\tva := value_0;\n\tvb := value_1;\n\ttemp := value_0;\n\tstate := 1;\nEND_IF;\nedge := E;\n\n(* generate startup profile *)\nIF run THEN\n\tCASE state OF\n\t\t1:\tIF tx - ta >= tb THEN\n\t\t\t\tta := ta + tb;\n\t\t\t\ttb := multime(time_2 - time_1, M);\n\t\t\t\tva := value_1;\n\t\t\t\tvb := value_2;\n\t\t\t\ttemp := value_1;\n\t\t\t\tstate := 2;\n\t\t\tELSE\n\t\t\t\ttemp := ((vb - va) * TIME_TO_REAL(tx - ta) / TIME_TO_REAL(tb) + va);\n\t\t\tEND_IF;\n\t\t2:\tIF tx - ta >= tb THEN\n\t\t\t\tta := ta + tb;\n\t\t\t\ttb := multime(time_3 - time_2, M);\n\t\t\t\tva := value_2;\n\t\t\t\tvb := value_3;\n\t\t\t\ttemp := value_2;\n\t\t\t\tstate := 3;\n\t\t\tELSE\n\t\t\t\ttemp := ((vb - va) * TIME_TO_REAL(tx - ta) / TIME_TO_REAL(tb) + va);\n\t\t\tEND_IF;\n\t\t3:\tIF tx - ta >= tb THEN\n\t\t\t\tta := ta + tb;\n\t\t\t\ttb := multime(time_10 - time_3, M);\n\t\t\t\tva := value_3;\n\t\t\t\tvb := value_10;\n\t\t\t\ttemp := value_3;\n\t\t\t\tstate := 4;\n\t\t\tELSE\n\t\t\t\ttemp := ((vb - va) * TIME_TO_REAL(tx - ta) / TIME_TO_REAL(tb) + va);\n\t\t\tEND_IF;\n\t\t4 :\tIF tx - ta >= tb THEN\n\t\t\t\tta := ta + tb;\n\t\t\t\ttb := multime(time_11 - time_10, M);\n\t\t\t\tva := value_10;\n\t\t\t\tvb := value_11;\n\t\t\t\ttemp := value_10;\n\t\t\t\tIF E THEN state := 5; ELSE state := 6; END_IF;\n\t\t\tELSE\n\t\t\t\ttemp := ((vb - va) * TIME_TO_REAL(tx - ta) / TIME_TO_REAL(tb) + va);\n\t\t\tEND_IF;\n\t\t5:\t(* extend the signal while E is true *)\n\t\t\tIF E THEN\n\t\t\t\tta := tx;\n\t\t\tELSE\n\t\t\t\tstate := 6;\n\t\t\tEND_IF;\n\t\t6:\tIF tx - ta >= tb THEN\n\t\t\t\tta := ta + tb;\n\t\t\t\ttb := multime(time_12 - time_11, M);\n\t\t\t\tva := value_11;\n\t\t\t\tvb := value_12;\n\t\t\t\ttemp := value_11;\n\t\t\t\tstate := 7;\n\t\t\tELSE\n\t\t\t\ttemp := ((vb - va) * TIME_TO_REAL(tx - ta) / TIME_TO_REAL(tb) + va);\n\t\t\tEND_IF;\n\t\t7:\tIF tx - ta >= tb THEN\n\t\t\t\tta := ta + tb;\n\t\t\t\ttb := multime(time_13 - time_12, M);\n\t\t\t\tva := value_12;\n\t\t\t\tvb := value_13;\n\t\t\t\ttemp := value_12;\n\t\t\t\tstate := 8;\n\t\t\tELSE\n\t\t\t\ttemp := ((vb - va) * TIME_TO_REAL(tx - ta) / TIME_TO_REAL(tb) + va);\n\t\t\tEND_IF;\n\t\t8:\tIF tx - ta >= tb THEN\n\t\t\t\ttemp := value_13;\n\t\t\t\trun := FALSE;\n\t\t\tELSE\n\t\t\t\ttemp := ((vb - va) * TIME_TO_REAL(tx - ta) / TIME_TO_REAL(tb) + va);\n\t\t\tEND_IF;\n\tEND_CASE;\n\tY := temp * K + O;\n\tET := tx - t0;\nEND_IF;\n\n(* revision history\nhm\t27 feb 2007\t\trev 1.0\n\toriginal version\n\nhm\t15. sep2007\t\trev 1.1\n\treplaced Time() with T_PLC_MS for compatibility and performance reasons\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FT_RMP.st", - "source": "FUNCTION_BLOCK FT_RMP\nVAR_INPUT\n\tRmp : BOOL := TRUE;\n\tin : REAL;\n\tKR : REAL;\n\tKF : REAL;\nEND_VAR\nVAR_OUTPUT\n\tout : REAL;\n\tbusy : BOOL;\n\tUD : BOOL;\nEND_VAR\nVAR\n\ttx: TIME;\n\tlast: TIME;\n\tinit: BOOL;\nEND_VAR\n\n(*\n\tversion 1.4\t25 jan 2008\n\tprogrammer \toscat\n\ttested BY\t\toscat\n\nthis ramp function follows an input signal with a linear ramp up or down, the up or down speed can be set with KF and KR.\na K factor of 1 means 1 unit per second on the output. K factors can only be positive and not negative.\na busy output signals the ramp is running or busy false means the in value is present on the output.\na rmp input false means the output follows the input dierctly while a rmp = true means the output follows the input with a ramp.\na updn output signal the directon of the ramp (up or down).\n\n*)\n\n(* read system time *)\ntx := DWORD_TO_TIME(T_PLC_MS()) - last;\n\nIF NOT init THEN\n\tinit := TRUE;\n\tlast := tx;\n\ttx := t#0s;\n\tout := in;\nEND_IF;\nIF NOT rmp THEN\n\tout := in;\n\tbusy := FALSE;\nELSIF out > in THEN\n\t(* ramp down *)\n\tout := out - TIME_TO_REAL(tx) * 0.001 * KF;\n\tout := MAX(in, out);\nELSIF out < in THEN\n\t(* ramp up *)\n\tout := out + TIME_TO_REAL(tx) * 0.001 * KR;\n\tout := MIN(in, out);\nEND_IF;\n\n(* set busy and dir flags *)\nIF out < in THEN\n\tbusy := TRUE;\n\tud := TRUE;\nELSIF out > in THEN\n\tbusy := TRUE;\n\tud := FALSE;\nELSE\n\tbusy := FALSE;\nEND_IF;\nlast := last + tx;\n\n\n(* revision history:\n\nhm 8.10.2006\t\t\trev 1.1\n\tadded ud output\n\nhm 12. feb 2007\t\trev 1.2\n\tadded init variable and corrected a possible startup problem\n\nhm\t17. sep 2007\trev 1.3\n\treplaced time() with t_plc_ms() for compatibility reasons\n\nhm\t25. jan 2008\trev 1.4\n\tperformance improvements\n\tallow KR and KF to be 0\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FT_TN16.st", - "source": "FUNCTION_BLOCK FT_TN16\nVAR_INPUT\n\tin : REAL;\n\tT : TIME;\nEND_VAR\nVAR_OUTPUT\n\tout : REAL;\n\ttrig : BOOL;\nEND_VAR\nVAR\n\tlength : INT := 16;\n\tX : ARRAY[0..15] OF REAL;\n\tcnt : INT;\n\tlast : TIME;\n\ttx: TIME;\n\tinit: BOOL;\nEND_VAR\n\n(*\nversion 1.1\t16 sep 2007\nprogrammer \thugo\ntested by\t\ttobias\n\nFT_TN16 is delay function, it will delay a signal by a specified time : T and will store 16 values of in before they are put thru to out.\nfor higher or lower resolution please use FT_TN8 or FT_TN64 instead.\n \n*)\n\n(* read system time *)\ntx := DWORD_TO_TIME(T_PLC_MS());\n\ntrig := FALSE;\nIF NOT init THEN\n\tx[cnt] := in;\n\tinit := TRUE;\n\tlast := tx;\nELSIF tx - last >= T / length THEN\n\tIF cnt = length - 1 THEN cnt := 0; ELSE cnt := cnt + 1; END_IF;\n\tOut := X[cnt];\n\tx[cnt] := in;\n\tlast := tx;\n\tTrig := TRUE;\nEND_IF;\n\n(* revision history\nhm\t\t1. jan 2007\trev 1.0\n\toriginal version\n\nhm\t\t16. sep 2007\trev 1.1\n\tchanges time() to T_plc_ms() for compatibility reasons\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FT_TN64.st", - "source": "FUNCTION_BLOCK FT_TN64\nVAR_INPUT\n\tin : REAL;\n\tT : TIME;\nEND_VAR\nVAR_OUTPUT\n\tout : REAL;\n\ttrig: BOOL;\nEND_VAR\nVAR\n\tlength : INT := 64;\n\tX : ARRAY[0..63] OF REAL;\n\tcnt : INT;\n\tlast : TIME;\n\ttx: TIME;\n\tinit: BOOL;\nEND_VAR\n\n(*\nversion 1.1\t15 sep 2007\nprogrammer \thugo\ntested by\t\ttobias\n\nFT_TN7 is delay function, it will delay a signal by a specified time : T and will store 64 values of in before they are put thru to out.\nif lower resolution is needed, pls use FT_TN8 or FT_TN16 instead.\n \n*)\n\n(* read system time *)\ntx := DWORD_TO_TIME(T_PLC_MS());\n\ntrig := FALSE;\nIF NOT init THEN\n\tx[cnt] := in;\n\tinit := TRUE;\n\tlast := tx;\nELSIF tx - last >= T / length THEN\n\tIF cnt = length - 1 THEN cnt := 0; ELSE cnt := cnt + 1; END_IF;\n\tOut := X[cnt];\n\tx[cnt] := in;\n\tlast := tx;\n\ttrig := TRUE;\nEND_IF;\n\n(* revision history\nhm\t\t1. jan 2007\t\trev 1.0\n\toriginal version\n\nhm\t\t16. sep 2007\trev 1.1\n\tchanges time() to T_plc_ms() for compatibility reasons\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "FT_TN8.st", - "source": "FUNCTION_BLOCK FT_TN8\nVAR_INPUT\n\tin : REAL;\n\tT : TIME;\nEND_VAR\nVAR_OUTPUT\n\tout : REAL;\n\ttrig: BOOL;\nEND_VAR\nVAR\n\tlength : INT := 8;\n\tX : ARRAY[0..7] OF REAL;\n\tcnt : INT;\n\tlast : TIME;\n\ttx: TIME;\n\tinit: BOOL;\nEND_VAR\n\n(*\nversion 1.1\t15 Sep 2007\nprogrammer \thugo\ntested by\t\ttobias\n\nFT_TN8 is delay function, it will delay a signal by a specified time : T and will store 8 values of in before they are put thru to out.\nif higher resolution is needed, pls use FT_TN16 or FT_TN64 instead.\n \n*)\n\ntx := DWORD_TO_TIME(T_PLC_MS());\ntrig := FALSE;\nIF NOT init THEN\n\tx[cnt] := in;\n\tinit := TRUE;\n\tlast := tx;\nELSIF tx - last >= T / length THEN\n\tIF cnt = length - 1 THEN cnt := 0; ELSE cnt := cnt + 1; END_IF;\n\tOut := X[cnt];\n\tx[cnt] := in;\n\tlast := tx;\n\ttrig := TRUE;\nEND_IF;\n\n(* revision history\nhm\t\t1. jan 2007\t\trev 1.0\n\toriginal version\n\nhm\t\t16. sep 2007\trev 1.1\n\tchanges time() to T_plc_ms() for compatibility reasons\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "F_LIN.st", - "source": "FUNCTION F_LIN : REAL\nVAR_INPUT\n\tX : REAL;\n\tA : REAL;\n\tB : REAL;\nEND_VAR\n\n\n(*\nversion 1.0\t1 sep 2006\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the linear equation f_lin = a*x + b\n\n*)\n\nF_lin := A * X + B;\n\nEND_FUNCTION\n" - }, - { - "fileName": "F_LIN2.st", - "source": "FUNCTION F_LIN2 : REAL\nVAR_INPUT\n\tX : REAL;\n\tX1: REAL;\n\tY1 : REAL;\n\tX2 : REAL;\n\tY2 : REAL;\nEND_VAR\n\n\n(*\nversion 1.0\t1 jan 2007\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the linear equation f_lin = a*x + b given by two points x1/y1 and x2/y2.\n\n*)\n\nF_LIN2 := (Y2 - Y1) / (X2 - X1) * (X - X1) + Y1;\n\n\n(* revision history\nhm\t1. jan. 2007\trev 1.0\n\toriginal release\n\nhm\t17. dec. 2008\trev 1.1\n\toptimized formula\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "F_POLY.st", - "source": "FUNCTION F_POLY : REAL\nVAR_INPUT\n\tX : REAL;\n\tC : ARRAY[0..7] OF REAL;\nEND_VAR\nVAR\nEND_VAR\n\n(*\nversion 1.1\t18. mar. 2011\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the polynom C[0] + C[1]*X^1 + C[2]*X^2 * C[3]*X^3 + C[4]*X^4 + C[5]*X^5 + C[6]*X^6 + C[7]*X^7\n\n*)\n\nF_POLY := ((((((( c[7] * x + c[6] ) * x + c[5] ) * x + c[4] ) * x + c[3] ) * x + c[2] ) * x + c[1] ) * x + c[0] ) ;\n\n\n(* revision history\nhm\t\t20. may. 2008\t\trev 1.0\n\toriginal version\n\nhm\t18. mar. 2011\trev 1.1\n\timproved performance\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "F_POWER.st", - "source": "FUNCTION F_POWER : REAL\nVAR_INPUT\n\ta : REAL;\n\tx : REAL;\n\tn : REAL;\nEND_VAR\n\n\n(*\nversion 1.0\t1 sep 2006\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the power equation f_power = a*x^n\n\n*)\n\nF_POWER := a * EXPT(X, N);\n\nEND_FUNCTION\n" - }, - { - "fileName": "F_QUAD.st", - "source": "FUNCTION F_QUAD : REAL\nVAR_INPUT\n\tX : REAL;\n\tA : REAL;\n\tB : REAL;\n\tC : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t18. Mar. 2011\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the quadratic equation f_lin = a*x + b\n\n*)\n\nF_QUAD := (A * X + B) * X + C;\n\n(* revision history\n\nhm\t1. sep. 2006\trev 1.0\n\toriginal version\n\nhm\t18. mar. 2001\trev 1.1\n\timproved performance\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "F_TO_C.st", - "source": "FUNCTION F_TO_C : REAL\nVAR_INPUT\n\tfahrenheit : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t11. mar. 2009\nprogrammer \thugo\ntested BY\t\ttobias\n\nthis FUNCTION converts fahrenheit TO celsius\n\n*)\n\nF_TO_C := (fahrenheit - 32.0) * 0.5555555555555;\n\n(* revision history\nhm\t4. aug 2006\trev 1.0\n\toriginal version\n\nhm\t11. mar. 2009\trev 1.1\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "F_TO_OM.st", - "source": "FUNCTION F_TO_OM : REAL\nVAR_INPUT\n\tF : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t18. oct. 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function converts frequency to Omega F\nOmega = 2*PI*F\n*)\n\nF_TO_OM := math.PI2 * F;\n\n\n(* revision history\nhm\t22. jan. 2007\trev 1.0\n\toriginal version\n\nhm\t18. oct. 2008\trev 1.1\n\tunsing math constants\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "F_TO_PT.st", - "source": "FUNCTION F_TO_PT : TIME\nVAR_INPUT\n\tF : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t11. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function converts frequency to periode time \n*)\n\nF_TO_PT := DWORD_TO_TIME(REAL_TO_DWORD(1.0 / F * 1000.0));\n\n\n(* revision history\n\nhm\t4. aug. 2006\trev 1.0\n\toriginal version\n\nhm\t11. mar. 2009\trev 1.1\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "GAMMA.st", - "source": "FUNCTION GAMMA : REAL\nVAR_INPUT\n\tX : REAL;\nEND_VAR\n\n\n(*\nversion 1.3\t10. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nthis function calculates the stirling function which is an approximation for the gamma function\n\n*)\n\nIF x > 0.0 THEN\n\tGAMMA := SQRT(math.PI2 / X) * EXPT(math.E_INV * (x + 1.0 / (12.0 * x - 0.1 / X)), X);\nEND_IF;\n\n\n(* the stirling formula is not very accurate for small values of X\nIF X >=0 THEN GAMMA := SQRT(math.PI2 * X) * EXPT(X / math.E, X); END_IF;\n*)\n\n\n\n\n\n(* revision history\nhm\t10.12.2007\trev 1.0\n\toriginal version\n\nhm\t18. oct. 2008\trev 1.1\n\tusing math constants\n\nhm\t26. oct. 2008\trev 1.2\n\tusing new formula with better accuracy\n\nhm\t10. mar. 2009\trev 1.3\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "GAUSS.st", - "source": "FUNCTION GAUSS : REAL\nVAR_INPUT\n\tX : REAL;\n\tU : REAL;\n\tSI: REAL;\nEND_VAR\nVAR\n\ttemp: REAL;\n\tsi_inv: REAL;\nEND_VAR\n\n\n(*\nversion 1.2\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the gaussian density function\n\n*)\n\ntemp := X - U;\nsi_inv := 1.0 / si;\nGAUSS := EXP(Temp * Temp * si_inv * si_inv * - 0.5) * 0.39894228 * si_inv;\n\n\n\n(* revision hisdtory\nhm\t6. apr. 2008\trev 1.0\n\toriginal version\n\nhm\t27. oct. 2008\trev 1.1\n\toptimized performance\t\n\nhm\t10. mar. 2009\trev 1.2\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "GAUSSCD.st", - "source": "FUNCTION GAUSSCD : REAL\nVAR_INPUT\n\tX : REAL;\n\tU : REAL;\n\tSI: REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the gaussian cumulative distribution function\n\n*)\n\nGAUSSCD := (ERF((X - U) / (SI * 1.414213562)) + 1.0) * 0.5;\n\n\n\n(* revision hisdtory\nhm\t6. apr. 2008\trev 1.0\n\toriginal version\n\nhm\t10. mar. 2009\trev 1.1\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "GCD.st", - "source": "FUNCTION GCD : INT\nVAR_INPUT\n\tA : DINT;\n\tB : DINT;\nEND_VAR\nVAR\n\tt: DINT;\nEND_VAR\n\n\n(*\nversion 1.0\t19. jan. 2011\nprogrammer \thugo\ntested by\ttobias\n\nthis function calculates the gretaest common divisor of two numbers A and B\n\n*)\n\nIF A = 0 THEN\n\tGCD := DINT_TO_INT(ABS(B));\nELSIF B = 0 THEN\n\tGCD := DINT_TO_INT(ABS(A));\nELSE\n\tA := ABS(A);\n\tB := ABS(B);\n\tGCD := 1;\n\tWHILE NOT(A.0 OR B.0) DO\n\t\tA := SHR(A,1);\n\t\tB := SHR(B,1);\n\t\tGCD := SHL(GCD,1);\n\tEND_WHILE;\n\tWHILE A > 0 DO\n\t\tIF NOT(A.0) THEN A := SHR(A,1);\n\t\tELSIF NOT(B.0) THEN B := SHR(B,1);\n\t\tELSE\n\t\t\tt:= SHR(ABS(A-B),1);\n\t\t\tIF A < B THEN B := t; ELSE A := T; END_IF;\n\t\tEND_IF;\n\tEND_WHILE;\n\tGCD := GCD * DINT_TO_INT(B);\nEND_IF;\n\n\n(* revision history\nhm\t19. jan. 2011\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "GDF.st", - "source": "FUNCTION GDF : REAL\nVAR_INPUT\n\tX : REAL;\nEND_VAR\n\n\n(*\nversion 1.2\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the Gudermannian function.\n\n*)\n\nIF X = 0.0 THEN\n\tGDF := 0.0;\nELSIF X > 15.0 THEN\n\tGDF := math.PI05;\nELSIF X < -15.0 THEN\n\tGDF := -math.PI05;\nELSE\n\tGDF := ATAN(EXP(X)) * 2.0 - math.PI05;\nEND_IF;\n\n(* revision history\nhm\t27. apr. 2008\trev 1.0\n\toriginal version\n\nhm\t18. oct. 2008\trev 1.1\n\tusing math constants\n\nhm\t10. mar. 2009\trev 1.2\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "GEN_BIT.st", - "source": "FUNCTION_BLOCK GEN_BIT\nVAR_INPUT\n\tin0 : DWORD;\n\tin1 : DWORD;\n\tin2 : DWORD;\n\tin3 : DWORD;\n\tclk : BOOL;\n\tsteps : INT;\n\trep : INT;\n\trst : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tQ0 :BOOL;\n\tQ1 :BOOL;\n\tQ2 :BOOL;\n\tQ3 :BOOL;\n\tcnt : INT;\n\trun : BOOL;\nEND_VAR\nVAR\n\tr0: DWORD;\n\tr1: DWORD;\n\tr2: DWORD;\n\tr3: DWORD;\n\trx : INT := 1;\nEND_VAR\n\n(*\nversion 1.2\t14. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\ngen_bit is 4 bit sequencial pattern generator with 4 DWORD inputs and 4 serial outputs.\nwith the first clock pulse after a reset or after power on, bit 0 of the input DWORDS IN is present on the Outputs Q and the next clock cycle shifts to Bit 1 and so on.\nthe input steps defines how many bits of the input dwords will be shifted to the outputs. the sequence can be repetive when rep = 0 or any amount of repetitions can be defined with input rep.\n\n*)\n\n(* check if number of runs is finished or rep = 0 which means continuous *)\n\nIF clk AND NOT rst THEN\n\trun := (rep = 0) OR (rx <= rep);\n\tIF run THEN\n\t\t(* check for step counter reached and reset to 0 if cnt = steps *)\n\t\tIF cnt = steps THEN\n\t\t\tcnt := 0;\n\t\tEND_IF;\n\n\t\t(* when cnt = 0 then reload the inputs into the registers *)\n\t\tIF cnt = 0 THEN\n\t\t\tr0 := in0;\n\t\t\tr1 := in1;\n\t\t\tr2 := in2;\n\t\t\tr3 := in3;\n\t\tEND_IF;\n\n\t\t(* when cnt < steps, shift the lowest bits to the outputs *)\n\t\tIF (cnt < steps) THEN\n\t\t\tQ0 := r0.0;\n\t\t\tQ1 := r1.0;\n\t\t\tQ2 := r2.0;\n\t\t\tQ3 := r3.0;\n\t\t\tr0 := SHR(r0,1);\n\t\t\tr1 := SHR(r1,1);\n\t\t\tr2 := SHR(r2,1);\n\t\t\tr3 := SHR(r3,1);\n\t\tEND_IF;\n\n\t\t(* increment the step counter *)\n\t\tcnt := cnt +1;\n\t\tIF (cnt = steps) AND (rep <> 0) THEN rx := rx +1; END_IF;\n\t\tIF (rx > rep) AND (rep <> 0) THEN run := FALSE; END_IF;\n\tEND_IF;\nELSE\n\tIF rst THEN\n\t\trun := FALSE;\n\t\tQ0 := FALSE;\n\t\tQ1 := FALSE;\n\t\tQ2 := FALSE;\n\t\tQ3 := FALSE;\n\t\tr0 := 0;\n\t\tr1 := 0;\n\t\tr2 := 0;\n\t\tr3 := 0;\n\t\tcnt := 0;\n\t\trx := 1;\n\tEND_IF;\nEND_IF;\n\n\n\n(* revision histroy\nhm\t4 aug 2006\trev 1.0\n\toriginal version\n\nhm 15. oct. 2008\trev 1.1\n\timproved performance\n\nhm\t14. mar. 2009\trev 1.2\n\tremoved double assignments\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "GEN_PULSE.st", - "source": "FUNCTION_BLOCK GEN_PULSE\nVAR_INPUT\n\tENQ : BOOL := TRUE;\n\tPTH : TIME;\n\tPTL : TIME;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\nEND_VAR\nVAR\n\ttx: TIME;\n\ttn: TIME;\n\tinit: BOOL;\nEND_VAR\n\n(*\nversion 1.5\t8. apr. 2011\nprogrammer \thugo\ntested by\t\toscat\n\nGEN_PULSE uses the internal sps timer to generate a continuous output waveform with programmable high and low time.\nthe accuracy of gen_pulse is depending on the system timer.\nwhen time is 0 the high and low times are exactly one cycle.\nENQ = TRUE will start and ENQ = FALSE will stop the generator.\n\n*)\n\nIF enq THEN\n\ttx := DWORD_TO_TIME(T_PLC_MS());\n\tIF NOT init THEN init := TRUE; tn := tx; END_IF;\n\tIF tx - tn >= SEL(Q, PTL, PTH) THEN\n\t\ttn := tn + SEL(Q, PTL, PTH);\n\t\tQ := NOT Q;\n\tEND_IF;\nELSE\n\tQ := FALSE;\n\tinit := FALSE;\nEND_IF;\n\n\n\n(* revision history\nhm\t29. jun. 2008\trev 1.0\n\toriginal version\n\nhm\t23. nov. 2008\trev 1.1\n\tset default for enq to be true\n\nhm\t18. jul. 2009\trev 1.2\n\timproved performance\n\nhm\t13. nov. 2009\trev 1.3\n\tcorrected error\n\nhm\t16. feb. 2011\trev 1.4\n\tcorrected an error when timer overflows\n\nhm\t8. apr. 2011\trev 1.5\n\tptl and pth was exchanged\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "GEN_PW2.st", - "source": "FUNCTION_BLOCK GEN_PW2\nVAR_INPUT\n\tENQ : BOOL;\n\tTH1 : TIME;\n\tTL1 : TIME;\n\tTH2 : TIME;\n\tTL2 : TIME;\n\tTS : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\n\tTH : TIME;\n\tTL : TIME;\nEND_VAR\nVAR\n\tt_high : TIME;\n\tt_low : TIME;\n\ttx : TIME;\n\tstart : TIME;\n\tinit : BOOL;\n\tet : TIME;\nEND_VAR\n\n(*\nversion 1.1\t14. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nGEN_PW2 generates a time TH? followed by a time TL?.\nthe input ts selects between 2 sets of timings for the operation.\n\n\n*)\n\n(* read system timer *)\ntx := DWORD_TO_TIME(T_PLC_MS());\n\n(* startup initialization *)\nIF NOT init THEN\n\tstart := tx;\n\tinit := TRUE;\n\tTH := T#0s;\n\tTL := T#0s;\nEND_IF;\n\n(* timing selection *)\nIF TS THEN\n\tt_high := TH2;\n\tt_low := TL2;\nELSE\n\tt_high := TH1;\n\tt_low := TL1;\nEND_IF;\n\n(* normal operation *)\nIF ENQ THEN\n\tet := tx - start;\n\tIF NOT Q THEN\n\t\tIF et >= t_low THEN\n\t\t\tQ := TRUE;\n\t\t\tstart := tx;\n\t\t\tTL := T#0s;\n\t\tELSE\n\t\t\tTL := et;\n\t\tEND_IF;\n\tELSE\n\t\tIF et >= t_high THEN\n\t\t\tQ := FALSE;\n\t\t\tstart := tx;\n\t\t\tTH := T#0s;\n\t\tELSE\n\t\t\tTH := et;\n\t\tEND_IF;\n\tEND_IF;\nELSE\n\tQ := FALSE;\n\tTH := T#0s;\n\tTL := T#0s;\n\tstart := tx;\nEND_IF;\n\n\n\n(* revision history\nhm\t26. sep. 2008\trev 1.0\n\toriginal version\n\nhm\t14. mar. 2009\trev 1.1\n\tremoved double assignments\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "GEN_RDM.st", - "source": "FUNCTION_BLOCK GEN_RDM\nVAR_INPUT\n\tPT : TIME;\n\tAM : REAL := 1;\n\tOS : REAL;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\n\tOut : REAL;\nEND_VAR\nVAR\n\ttx : TIME;\n\tlast : TIME;\n\tinit : BOOL;\nEND_VAR\n\n(*\n\tversion 1.1\t16 sep 2007\n\tprogrammer \toscat\n\ttested BY\t\toscat\n\nthis signal generator generates a random output. The signal is defined by period time (PT), \namplitude (AM), offset (OS).\nThe Output waveform will have its max peak at AM/2 + OS and its minimum peak at -AM/2 + OS. \nThe period time PT defines how often the output signal will jump to a new randow value.\nThe Output Q will be true for one cycle anytime the output OUT has changed\n\n*)\n\n(* read system time and prepare input data *)\ntx := DWORD_TO_TIME(T_PLC_MS()) - last;\n\n(* init section *)\nIF NOT init THEN\n\tinit := TRUE;\n\tlast := tx;\n\ttx := t#0s;\nEND_IF;\n\n(* add last if one cycle is finished *)\nIF tx >= pt THEN\n\tlast := last + pt;\n\ttx := tx - pt;\n\n\t(* generate output signal *)\n\tout := am * (RDM(0) - 0.5) + os;\n\tq := TRUE;\nELSE\n\tq := FALSE;\nEND_IF;\n\n(* revision history\n\nhm\t7.2.2007\t\trev 1.0\n\toriginal version\n\nhm\t16.9.2007\t\trev 1.1\n\tchanges time() to T_plc_ms() for compatibility reasons\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "GEN_RDT.st", - "source": "FUNCTION_BLOCK GEN_RDT\n\nVAR_INPUT\n\tEnable\t\t : BOOL := TRUE ;\n\tMin_Time_ms\t: TIME := t#1s ; (* min Taktzeit *)\n\tMax_Time_ms\t: TIME := t#1.2s ; (* Max Taktzeit *)\n\tTP_Q\t\t : TIME := t#100ms ; (* Zeit Ausgang auf TRUE *)\nEND_VAR\nVAR_OUTPUT\n\txQ\t\t : BOOL ;\nEND_VAR\nVAR\n\t(* Taktgenerator Simulation *)\n\ttonRDMTimer\t: TON ; (* Zeitbaustein Taktgenerator *)\n\ttof_xQ\t\t: TOF ; (* Ausschaltverzögerung Taktgenerator *)\n\ttRDMTime\t: TIME ; (* Sollzeit *)\n\trRDMTime\t: REAL ; (* Zufalswert Timer *)\nEND_VAR\n\n(*\nversion 1.1\t16 mar. 2008\nprogrammer \tJ. Schohaus\ntested by\t\tHugo\n\nRDMT generates a defined pulse with pulse width TP_Q at random times. the random time will be defined with an minimum and maximum time.\n\n*)\n\n\n(*\nFUNCTION_BLOCK RDMTimer\n###############################################################################\n\t\t Ersteller / author :\t\t \t\t \t\t \t\t \t\t J.Schohaus\n\t\t Datum / date:\t\t \t\t \t\t \t\t \t\t \t\t 13.07.2007\n###############################################################################\n\t\t Änderungen / Datum / Ersteller :\t\t \t\t \t\t \t\t \t\t \t\t \t\t \t\t \t\t \t\t \t\t \t\t \t\t \t\t \t\t \n\t\t moditication / date / author :\t\t \t\t \n###############################################################################\n\t\t Verwendete Bibliotheken\t\t ( * werden im Baustein nicht benötigt )\n\t\t \t\t \t\t \t\t Oscat.lib\n###############################################################################\nBeschreibung:\n*)\n\ntonRDMTimer ( IN:= Enable , PT:= tRDMTime );\ntof_xQ ( IN:= tonRDMTimer.Q , PT:= TP_Q );\nXQ := tof_xq.Q;\nIF tonRDMTimer.Q THEN\n\t\t xQ := TRUE ;\n\t\t rRDMTime := RDM ( last:= rRDMTime ) ;\n\t\t tRDMTime := REAL_TO_TIME ( rRDMTime * DINT_TO_REAL(TIME_TO_DINT( Max_Time_ms - Min_Time_ms ) + TIME_TO_DINT(Min_Time_ms ))) ;\n\t\t tonRDMTimer ( IN:= FALSE );\nEND_IF;\n\n(* revision history\nJ. Schohaus\t19. nov 2007\trev 1.0\n\torigial version\n\nhm\t16. mar. 2008\t\t\trev 1.1\n\tadded type conversion to avoid warnings under codesys 3.0\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "GEN_RMP.st", - "source": "FUNCTION_BLOCK GEN_RMP\nVAR_INPUT\n\tPT : TIME := t#1s;\n\tAM : REAL := 1.0;\n\tOS : REAL;\n\tDL : REAL;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\n\tOUT : REAL;\nEND_VAR\nVAR\n\ttx : TIME;\n\tlast : TIME;\n\tinit : BOOL;\n\ttemp : REAL;\n\tltemp: REAL;\nEND_VAR\n\n(*\n\tversion 1.4\t10. mar. 2009\n\tprogrammer \toscat\n\ttested BY\t\toscat\n\nthis signal generator generates a ramp wave output. The ramp wave signal is defined by period time (PT), \namplitude (AM), offset (OS) and a specific delay for the output signal (DL).\nThe Output waveform will have its minimum peak at OS and its maximum peak at AM + OS. \nThe delay input can delay a signal up to PT, this can be useful to synchronize different generators \nand generate interleaving signals.\nin addition to the analog output Out there is a second boolean output Q with is true for one cycle when the ramp starts.\n*)\n\n(* read system time and prepare input data *)\ntx := DWORD_TO_TIME(T_PLC_MS()) - last;\nDL := MODR(dl,1.0);\nIF dl < 0.0 THEN dl := 1.0 - dl; END_IF;\n\n(* init section *)\nIF NOT init THEN\n\tinit := TRUE;\n\tlast := tx;\n\ttx := t#0s;\nEND_IF;\n\n(* add last if one cycle is finished *)\nIF tx >= pt THEN\n\tlast := last + pt;\n\ttx := tx - pt;\nEND_IF;\n\n(* generate sine wave *)\nltemp := temp;\nIF pt > t#0s THEN temp := FRACT(TIME_TO_REAL(tx + MULTIME(pt, dl)) / TIME_TO_REAL(pt)); END_IF;\nout := am * temp + os;\n\n(* boolean output Q *)\nQ := temp < ltemp;\n\n(* revision history\nhm\t3. mar 2007\t\trev 1.0\n\toriginal version\n\nhm\t17 sep 2007\t\trev 1.1\n\treplaced time() with t_plc_ms for compatibilitx reasons\n\nhm\t27. nov 2007\trev 1.2\n\tavoid divide by 0 when pt = 0\n\nks\t26. oct. 2008\trev 1.3\n\tcode optimization\n\nhm\t10. mar. 2009\trev 1.4\n\tchanged real constants to use dot syntax\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "GEN_SIN.st", - "source": "FUNCTION_BLOCK GEN_SIN\nVAR_INPUT\n\tPT : TIME;\n\tAM : REAL := 1.0;\n\tOS : REAL;\n\tDL : REAL;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\n\tOut : REAL;\nEND_VAR\nVAR\n\ttx : TIME;\n\tlast : TIME;\n\tinit : BOOL;\n\ttemp : REAL;\nEND_VAR\n\n(*\nversion 1.6\t11. mar. 2009\nprogrammer \toscat\ntested BY\toscat\n\nthis signal generator generates a sine wave output. The sine wave signal is defined by period time (PT), \namplitude (AM), offset (OS) and a specific delay for the output signal (DL).\nThe Output waveform will have its max peak at AM/2 + OS and its minimum peak at -AM/2 + OS. \nThe delay input can delay a signal up to PT, this can be useful to synchronize different generators \nand generate interleaving signals. A Cos wave can be generated accordingly.\nin addition to a analog output Out there is a second boolean output Q with the corresponding binary signal.\n*)\n\n(* read system time and prepare input data *)\ntx := DWORD_TO_TIME(T_PLC_MS()) - last;\nDL := MODR(dl,1.0);\nIF dl < 0.0 THEN dl := 1.0 - dl; END_IF;\n\n(* init section *)\nIF NOT init THEN\n\tinit := TRUE;\n\tlast := tx;\n\ttx := t#0s;\nEND_IF;\n\n(* add last if one cycle is finished *)\nIF tx >= pt THEN\n\tlast := last + pt;\n\ttx := tx - pt;\nEND_IF;\n\n(* generate sine wave *)\nIF pt > t#0s THEN temp := SIN(math.PI2 * DWORD_TO_REAL(TIME_TO_DWORD(tx + MULTIME(pt, dl))) / DWORD_TO_REAL(TIME_TO_DWORD(pt))); END_IF;\nout := am * 0.5 * temp + os;\n\n(* boolean output Q *)\nq := NOT SIGN_R(temp);\n\n(* revision history\nhm\t22. jan 2007\trev 1.0\n\toriginal version\n\nhm\t17 sep 2007\trev 1.1\n\treplaced time() with t_plc_ms for compatibilitx reasons\n\nhm\t27. nov 2007\trev 1.2\n\tavoid divide by 0 when pt = 0\n\nhm\t6. jan 2008\t\trev 1.3\n\timproved performance\n\nhm\t16. mar. 2008\trev 1.4\n\tadded type conversion to avoid warnings under codesys 3.0\n\nhm\t18. oct. 2008\trev 1.5\n\tusing math constants\n\nhm\t11. mar. 2009\trev 1.6\n\tchanged real constants to use dot syntax\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "GEN_SQ.st", - "source": "FUNCTION_BLOCK GEN_SQ\nVAR_INPUT\n\tPT : TIME;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\nEND_VAR\nVAR\n\ttn: DWORD;\n\ttx: DWORD;\n\tinit : BOOL;\nEND_VAR\n\n(*\nversion 1.3\t16. feb. 2011\nprogrammer \thugo\ntested by\t\ttobias\n\ngen_sq generates square wave signal with programmable period time.\n\n*)\n\n(* read system time *)\ntx := T_PLC_MS();\n\nIF NOT init THEN\n\tinit := TRUE;\n\ttn := tx;\n\tQ := TRUE;\nELSIF tx - tn >= SHR(TIME_TO_DWORD(PT),1) THEN\n\tQ := NOT Q;\n\ttn := tn + SHR(TIME_TO_DWORD(pt),1);\nEND_IF;\n\n\n(* revision history\nhm\t4. aug 2006\trev 1.0\n\toriginal version\n\nhm\t17. sep 2007\trev 1.1\n\treplaced time() with T_PLC_MS() for compatibility reasons\n\nhm\t18. jul. 2009\trev 1.2\n\timproved accuracy\n\nhm\t16. feb 2011\trev 1.3\n\tcorrected an error with timer overflow \n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "GEN_SQR.st", - "source": "FUNCTION_BLOCK GEN_SQR\nVAR_INPUT\n\tPT : TIME;\n\tAM : REAL := 1.0;\n\tOS : REAL;\n\tDC : REAL := 0.5;\n\tDL : REAL;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\n\tOut : REAL;\nEND_VAR\nVAR\n\ttx : TIME;\n\tlast : TIME;\n\tinit: BOOL;\nEND_VAR\n\n(*\nversion 1.4\t11. mar. 2009\nprogrammer \toscat\ntested BY\t\toscat\n\nthis signal generator generates a square wave output. The square wave signal is defined by period time (PT), \namplitude (AM), offset (OS), duty cycle (DC) and a specific delay for the output signal (DL).\nThe Output waveform will switch between AM/2 + OS and -AM/2 + OS. The DC input specifies ther duty cycle, \nDC = 0 means output is low at all times and 1 means output is high at all times.\nThe delay input can delay a signal up to PT, this can be useful to synchronize different generators and generate interleaving signals.\nin addition to a analog output Out there is a second boolean output Q.\n*)\n\n(* check dc = 1 or 0 *)\nIF dc = 0.0 THEN\n\tout := -am * 0.5 + os;\n\tQ := FALSE;\n\tRETURN;\nELSIF dc = 1.0 THEN\n\tout := am * 0.5 + os;\n\tQ := TRUE;\n\tRETURN;\nEND_IF;\n\n(* read system time and prepare input data *)\ntx := DWORD_TO_TIME(T_PLC_MS()) - last;\nDL := MODR(dl,1.0);\nIF dl < 0.0 THEN dl := 1.0 - dl; END_IF;\ndc := MODR(dc,1.0);\nIF dc < 0.0 THEN dc := 1.0 - dc; END_IF;\n\n(* init section *)\nIF NOT init THEN\n\tinit := TRUE;\n\tlast := tx;\n\ttx := t#0s;\nEND_IF;\n\n(* add last if one cycle is finished *)\nIF tx >= pt THEN\n\tlast := last + pt;\n\ttx := tx - pt;\nEND_IF;\n\n(* check if falling or rising edge first *)\nIF MULTIME(pt, dl + dc) >= pt THEN\n\t(* generate falling edge *)\n\tIF tx >= MULTIME(pt, dl + dc - 1) THEN\n\t\tout := -am * 0.5 + os;\n\t\tQ := FALSE;\n\tEND_IF;\n\t(* generate rising edge *)\n\tIF tx >= MULTIME(pt, dl) THEN\n\t\tout := am * 0.5 + os;\n\t\tQ := TRUE;\n\tEND_IF;\nELSE\n\t(* generate rising edge first *)\n\tIF tx >= MULTIME(pt, dl) THEN\n\t\tout := am * 0.5 + os;\n\t\tQ := TRUE;\n\tEND_IF;\n\t(* generate falling edge *)\n\tIF tx >= MULTIME(pt, dl + dc) THEN\n\t\tout := -am * 0.5 +os;\n\t\tQ := FALSE;\n\tEND_IF;\nEND_IF;\n\n(* revision history\n\nhm\t12. feb 2007\trev 1.1\n\tadded default value for dc = 0.5\n\nhm\t17 sep 2007\trev 1.2\n\treplaced time() with t_plc_ms for compatibilitx reasons\n\nhm\t6. jan 2008\trev 1.3\n\timproved performance\n\nhm\t11. mar. 2009\trev 1.4\n\tchanged real constants to use dot syntax\n\tset default amplitude to 1.0\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "GEO_TO_DEG.st", - "source": "FUNCTION GEO_TO_DEG : REAL\nVAR_INPUT\n\tD : INT;\n\tM : INT;\n\tSEC : REAL;\nEND_VAR\n\n\n(*\nversion 1.0\t22. jan. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nthis function converts degrees, minutes seconds to decimal degrees.\n\n*)\n\nGEO_TO_DEG := INT_TO_REAL(D) + INT_TO_REAL(M) * 0.016666666666667 + sec * 0.00027777777777778;\n\n\n(* revision histroy\nhm\t22. jan. 2009\trev 1.0\n\toriginal release\n\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "GOLD.st", - "source": "FUNCTION GOLD : REAL\nVAR_INPUT\n\tX : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the golden function.\n\n*)\n\nGOLD := (X + SQRT(X*X + 4.0)) * 0.5;\n\n\n(* revision history\nhm\t27. apr. 2008\trev 1.0\n\toriginal version\n\nhm\t10. mar. 2009\trev 1.1\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "GRAY_TO_BYTE.st", - "source": "FUNCTION GRAY_TO_BYTE : BYTE\nVAR_INPUT\n\tIN : BYTE;\nEND_VAR\n\n\n(*\nversion 1.0\t9. nov. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nthis function converts a gray code into binary\n\n*)\n\nGRAY_TO_BYTE := SHR(IN,4) XOR IN;\nGRAY_TO_BYTE := SHR(GRAY_TO_BYTE,2) XOR GRAY_TO_BYTE;\nGRAY_TO_BYTE := SHR(GRAY_TO_BYTE,1) XOR GRAY_TO_BYTE;\n\n(* revision history\nhm\t9. nov. 2009\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "GVL_1.gvl.st", - "source": "VAR_GLOBAL\n\tMATH : CONSTANTS_MATH;\n\tPHYS : CONSTANTS_PHYS;\n\tLANGUAGE : CONSTANTS_LANGUAGE;\n\tSETUP : CONSTANTS_SETUP;\n\tLOCATION : CONSTANTS_LOCATION;\nEND_VAR\n" - }, - { - "fileName": "GVL_2.gvl.st", - "source": "VAR_GLOBAL RETAIN\n\nEND_VAR\n" - }, - { - "fileName": "HEX_TO_BYTE.st", - "source": "FUNCTION HEX_TO_BYTE : BYTE\nVAR_INPUT\n\tHEX : STRING(5);\nEND_VAR\nVAR\n\tpt : POINTER TO BYTE;\n\ti: INT;\n\tX: BYTE;\n\tstop: INT;\nEND_VAR\n\n(*\nversion 1.1\t20. sep. 2008\nprogrammer \thugo\ntested by\t\toscat\n\nHEX_TO_BYTE converts a Hexadecimal string into a byte.\n\n*)\n\npt := ADR(hex);\nstop := LEN(hex);\nFOR I := 1 TO stop DO\n\t(* read the first character and subtract 48 to get value in decimal 0 = 48 *)\n\tx := pt^;\n\t(* calculate the value of the digit *)\n\tIF X > 47 AND x < 58 THEN\n\t\tHEX_TO_BYTE := SHL(HEX_TO_BYTE,4) + X - 48;\n\tELSIF X > 64 AND X < 71 THEN\n\t\tHEX_TO_BYTE := SHL(HEX_TO_BYTE,4) + X - 55;\n\tELSIF X > 96 AND X < 103 THEN\n\t\tHEX_TO_BYTE := SHL(HEX_TO_BYTE,4) + X - 87;\n\tEND_IF;\n\tpt := pt + 1;\nEND_FOR;\n\n\n\n\n(* revision histroy\nhm\t18. jun. 2008\trev 1.0\n\toriginal release\n\nhm\t20. sep.2008\trev 1.1\n\tchanged length of input string from 20 to 5\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "HEX_TO_DWORD.st", - "source": "FUNCTION HEX_TO_DWORD : DWORD\nVAR_INPUT\n\tHex : STRING(20);\nEND_VAR\nVAR\n\tpt : POINTER TO BYTE;\n\ti: INT;\n\tX: BYTE;\n\tstop: INT;\nEND_VAR\n\n(*\nversion 1.4\t18. jun. 2008\nprogrammer \thugo\ntested by\ttobias\n\nHEX_TO_DWORD converts a Hexadecimal string into a DWORD.\n\n*)\n\npt := ADR(hex);\nstop := LEN(hex);\nFOR I := 1 TO stop DO\n\t(* read the first character and subtract 48 to get value in decimal 0 = 48 *)\n\tx := pt^;\n\t(* calculate the value of the digit *)\n\tIF X > 47 AND x < 58 THEN\n\t\tHEX_TO_DWORD := SHL(HEX_TO_DWORD,4) + X - 48;\n\tELSIF X > 64 AND X < 71 THEN\n\t\tHEX_TO_DWORD := SHL(HEX_TO_DWORD,4) + X - 55;\n\tELSIF X > 96 AND X < 103 THEN\n\t\tHEX_TO_DWORD := SHL(HEX_TO_DWORD,4) + X - 87;\n\tEND_IF;\n\tpt := pt + 1;\nEND_FOR;\n\n\n\n(* revision histroy\nhm\t2.10.2007\t\trev 1.0\n\toriginal release\n\nhm\t19.11.2007\t\trev 1.1\n\tchanged type of function from int to dword\n\nhm \t4. mar 2008\t\trev 1.2\n\tadded support for a..f and return 0 for invalid string\n\nhm\t29. mar. 2008\trev 1.3\n\tchanged STRING to STRING(8)\n\nhm\t18. jun. 2008\trev 1.4\n\tchanged input hex to STRING(20)\n\tfunction now ignores wrong characters\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "HOLIDAY.st", - "source": "FUNCTION_BLOCK HOLIDAY\nVAR_INPUT\n\tDATE_IN : DATE;\n\tLANGU : INT;\n\tFRIDAY : BOOL;\n\tSATURDAY : BOOL;\n\tSUNDAY : BOOL;\nEND_VAR\nVAR_IN_OUT\n\tHOLIDAYS : ARRAY[0..29] OF HOLIDAY_DATA;\nEND_VAR\nVAR CONSTANT\n\tSIZE : INT := 29;\nEND_VAR\nVAR_OUTPUT\n\tY : BOOL;\n\tNAME : STRING(30);\nEND_VAR\nVAR\n\tlast_active : DATE;\n\tostern: DATE;\n\ti: INT;\n\tjahr: INT;\n\tx_date: DATE;\n\tlx: INT;\n\twdx: INT;\nEND_VAR\n\n(*\nversion 2.0\t18. jans 2011\nprogrammer \thugo\ntested by\t\ttobias\n\nholiday calculates if a given day is a holiday and displays the name of the holiday as string as well as a boolean flag to indicate a holiday.\nthe holidays are specified in the country setup under global constants.\na holiday can be of fixed date for example new years day on january 1st.\na holiday can have a fixed offset from easter sunday as for most church holidays.\na holiday can be a specific weekday before a fixed date, for example buss und bettag is the last wednesday before nov 23rd.\nwith a simple f_use flag any specific holiday can be turned on or off if needed.\n\nplease check the manual for examples of holiday definitions\n*)\n\n(* for performance reasons only activate once a day *)\nIF last_active = date_in THEN RETURN; END_IF;\nlast_active := DATE_IN;\n\n(* determine language *)\nIF LANGU = 0 THEN\n\tlx := language.DEFAULT;\nELSE\n\tlx := MIN(language.LMAX, LANGU);\nEND_IF;\n\n(* berechnung von ostern für das aktuelle jahr *)\njahr := YEAR_OF_DATE(date_in);\nostern := EASTER(jahr);\nwdx := DAY_OF_WEEK(DATE_IN);\nY := FALSE;\n\n(* check for holidays *)\nFOR i := 0 TO size DO\n\tx_date := SET_DATE(jahr, HOLIDAYS[i].MONTH , HOLIDAYS[i].DAY);\n\tIF HOLIDAYS[i].USE = 1 AND HOLIDAYS[i].MONTH > 0 THEN\n\t\t(* check for fixed date holiday *)\n\t\tIF x_date = date_in THEN\n\t\t\tY := TRUE;\n\t\t\tNAME := HOLIDAYS[i].NAME;\n\t\t\tRETURN;\n\t\tEND_IF;\n\tELSIF HOLIDAYS[i].USE = 1 AND HOLIDAYS[i].MONTH = 0 THEN\n\t\t(* check for holiday in reference to easter *)\n\t\tIF DATE_ADD(ostern, HOLIDAYS[i].DAY ,0,0,0) = date_in THEN\n\t\t\tY := TRUE;\n\t\t\tNAME := HOLIDAYS[i].NAME;\n\t\t\tRETURN;\n\t\tEND_IF;\n\tELSIF HOLIDAYS[i].USE < 0 THEN\n\t\t(* check for holiday on a weekday before date *)\n\t\tIF DAY_OF_WEEK(date_in) = ABS(HOLIDAYS[i].USE) AND date_in < x_date AND date_in >= DATE_ADD(x_date,-7,0,0,0) THEN\n\t\t\tY := TRUE;\n\t\t\tNAME := HOLIDAYS[i].NAME;\n\t\t\tRETURN;\n\t\tEND_IF;\n\tEND_IF;\nEND_FOR;\n\n(* check array if today is weekend *)\nIF NOT Y AND (wdx = 5 AND FRIDAY OR wdx = 6 AND SATURDAY OR wdx = 7 AND SUNDAY) THEN\n\tY := TRUE;\n\tNAME := LANGUAGE.WEEKDAYS[LOCATION.LANGUAGE[lx],wdx];\nELSE\n\tNAME := '';\nEND_IF;\n\n\n(*\nNeujahrstag \t1. Januar \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t•\nHeilige Drei Könige \t6. Januar \t• \t• \t\t\t\t\t\t\t\t\t\t\t\t• \t\t\nKarfreitag \tOstersonntag - 2d \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t•\nOstersonntag \tsiehe Osterdatum \t\t\t\t(•) \t\t\t\t\t\t\t\t\t\t\t\t\nOstermontag \tOstersonntag + 1d \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t•\nTag der Arbeit \t1. Mai \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t•\nChristi Himmelfahrt \tOstersonntag + 39d \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t•\nPfingstsonntag \tOstersonntag + 49d \t\t\t\t(•) \t\t\t\t\t\t\t\t\t\t\t\t\nPfingstmontag \tOstersonntag + 50d \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t•\nFronleichnam \tOstersonntag + 60d \t• \t• \t\t\t\t\t• \t\t\t• \t• \t• \t1) \t\t\t2)\nAugsburger Friedensfest \t8. August \t\t(3) \t\t\t\t\t\t\t\t\t\t\t\t\t\t\nMariä Himmelfahrt \t15. August \t\t(5) \t\t\t\t\t\t\t\t\t\t• \t\t\t\t\nTag der Deutschen Einheit \t3. Oktober 6) \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t•\nReformationstag \t31. Oktober \t\t\t\t• \t\t\t\t• \t\t\t\t\t• \t• \t\t•\nAllerheiligen \t1. November \t• \t• \t\t\t\t\t\t\t\t• \t• \t• \t\t\t\t\nBuß- und Bettag 4) \tMittwoch vor dem 23.11. \t\t\t7 \t\t\t\t\t\t\t\t\t\t• \t\t\t\n1. Weihnachtstag \t25. Dezember \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t•\n2. Weihnachtstag \t26. Dezember \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t• \t•\n*)\n\n\n\n(* revision history\nhm \t27. feb. 2007\trev 1.1\n\tdeleted unused variable init\n\nhm\t31. oct. 2007\trev 1.2\n\tchanged holiday definition from constant to input constant to allow easier changes by user without recompilation of the lib\n\nhm \t24. nov. 2007\trev 1.3\n\tchanges F_use of Buß_und_Bettag to 0 because this is no official holiday\n\nhm\t7. apr. 2008\trev 1.4\n\timproved performance\n\nhm\t7. oct. 2008\trev 1.5\n\tchanged code to use setup data from global constants\n\tchanged length of output NAME from 20 to 30\n\tholiday will now also be indicated on a weekend\n\tchanged function year to year_of_date\n\tchanged function weekday to day_of_week\n\nhm\t21. oct. 2008\trev 1.6\n\tusing location constants\n\nhm\t18. jan 2011\trev 2.0\n\tusing user specified array for holidays\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "HOLIDAY_DATA.st", - "source": "TYPE HOLIDAY_DATA :\nSTRUCT\n\tNAME : STRING(30);\n\tDAY : SINT;\n\tMONTH : SINT;\n\tUSE : SINT;\nEND_STRUCT\nEND_TYPE\n" - }, - { - "fileName": "HOUR.st", - "source": "FUNCTION HOUR : INT\nVAR_INPUT\n\titod : TOD;\nEND_VAR\n\n\n(*\nversion 1.1\t2 okt 2006\nprogrammer \thugo\ntested by\ttobias\n\nextracts the hour of a Time_of_day \n*)\n\nHOUR := DWORD_TO_INT(TOD_TO_DWORD(itod) / 3600000);\n\n\n(* change history\nhm 4. aug 2006\trev 1.0\n\toriginal version\n\nhm 2.10.2006 \trev 1.1\n\tchanged name of input to itod\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "HOUR_OF_DT.st", - "source": "FUNCTION HOUR_OF_DT : INT\nVAR_INPUT\n\tXDT : DT;\nEND_VAR\n\n\n(*\n\tversion 1.0\t6. jun. 2008\n\tprogrammer \toscat\n\ttested BY\toscat\n\nHOUR_OF_DT returns the current hour (hour of the day) of a DT variable\n\n*)\n\nHOUR_OF_DT := DWORD_TO_INT((DT_TO_DWORD(XDT) MOD 86400) / 3600);\n\n\n(* revision history\nhm\t\t6.9.2008\trev 1.0\n\toriginal version\n\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "HOUR_TO_TIME.st", - "source": "FUNCTION HOUR_TO_TIME : TIME\nVAR_INPUT\n\tIN : REAL;\nEND_VAR\n\n\n(*\nversion 1.2\t24. feb. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nconverts an amount of hours in real to time\n\n*)\n\nHOUR_TO_TIME := DWORD_TO_TIME(REAL_TO_DWORD(IN * 3600000));\n\n\n(* revision history\nhm\t\t4. aug 2006\trev 1.0\n\toriginal version\n\nhm\t14. mar. 2008\trev 1.1\n\trounded the input after the last digit\n\nhm\t24. feb. 2009\trev 1.2\n\tchanged input to IN\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "HOUR_TO_TOD.st", - "source": "FUNCTION HOUR_TO_TOD : TOD\nVAR_INPUT\n\tIN : REAL;\nEND_VAR\n\n\n(*\nversion 1.2\t24. feb 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nconverts an amount of hours in real to time of day TOD.\n\n*)\n\nHOUR_TO_TOD := DWORD_TO_TOD(REAL_TO_DWORD(IN * 3600000));\n\n\n(* revision history\nhm\t4. aug. 2006\trev 1.0\n\toriginal version\n\nhm\t14. mar. 2008\trev 1.1\n\trounded the input after the last digit\n\nhm\t24. feb. 2009\trev 1.2\n\tchanged input to IN\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "HYPOT.st", - "source": "FUNCTION HYPOT : REAL\nVAR_INPUT\n\tX : REAL;\n\tY : REAL;\nEND_VAR\n\n\n(*\nversion 1.0\t21 feb 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function calculates the pythagorean function\n\n*)\n\nHYPOT := SQRT(x*x + y*y);\n\n\n(* revision history\nhm\t21. feb 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "HYST.st", - "source": "FUNCTION_BLOCK HYST\nVAR_INPUT\n\tIn : REAL;\n\tON : REAL;\n\tOFF : REAL;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\n\twin : BOOL;\nEND_VAR\n\n\n(*\nversion 1.0\t2. jun. 2008\nprogrammer \thugo\ntested BY\toscat\n\nThis Hystereses function has two modes:\n1. if on > off then Q will be switched high when in > on and switched low when in < off.\n2. if on < off then Q will be switched high when in < on and switched low when in > off.\nthe output win will be high when in is between low and high.\n\n*)\n\nIF ON >= OFF THEN\n\tIF IN < OFF THEN\n\t\tQ := FALSE;\n\t\tWIN := FALSE;\n\tELSIF IN > ON THEN\n\t\tQ := TRUE;\n\t\tWIN := FALSE;\n\tELSE\n\t\tWIN := TRUE;\n\tEND_IF;\nELSE\n\tIF IN > OFF THEN\n\t\tQ := FALSE;\n\t\tWIN := FALSE;\n\tELSIF IN < ON THEN\n\t\tQ := TRUE;\n\t\tWIN := FALSE;\n\tELSE\n\t\tWIN := TRUE;\n\tEND_IF;\nEND_IF;\n\n\n(* revision history\nhm\t\t2. jun 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "HYST_1.st", - "source": "FUNCTION_BLOCK HYST_1\nVAR_INPUT\n\tIn : REAL;\n\thigh : REAL;\n\tlow : REAL;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\n\twin : BOOL;\nEND_VAR\n\n\n(*\nversion 1.1\t2. jun. 2008\nprogrammer \thugo\ntested BY\toscat\n\nthis hysteresis function switches the output high if the input signal reaches obove high and will switch to low when the input falls back below low value.\na separate output mid is set if the input stays between low and high value.\n\n*)\n\nIF in < low THEN\n\tQ := FALSE;\n\twin := FALSE;\nELSIF in > high THEN\n\tQ := TRUE;\n\twin := FALSE;\nELSE\n\twin := TRUE;\nEND_IF;\n\n\n\n\n(* revision history\nhm\t\t4. aug. 2006\trev 1.0\n\toriginal version\n\nhm\t\t2. jun. 2008\trev 1.1\n\timproved performance\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "HYST_2.st", - "source": "FUNCTION_BLOCK HYST_2\nVAR_INPUT\n\tIN : REAL;\n\tVAL : REAL;\n\tHYS : REAL;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\n\tWIN: BOOL;\nEND_VAR\nVAR\n\ttmp: REAL;\nEND_VAR\n\n\n(*\nversion 1.2\t2. jun. 2008\nprogrammer \toscat\ntested BY\toscat\n\nthis hysteresis function switches the output high if the input signal reaches obove val + hys/2 and will switch to low when the input falls back below val - hys/2 value.\na separate output mid is set if the input stays between low and high value.\n\n*)\n\ntmp := val - hys * 0.5;\nIF in < tmp THEN\n\tQ := FALSE;\n\twin := FALSE;\nELSIF in > tmp + hys THEN\n\tQ := TRUE;\n\twin := FALSE;\nELSE\n\twin := TRUE;\nEND_IF;\n\n\n\n(* revision history\nhm\t\t4. aug 2006\trev 1.0\n\toriginal version\n\nhm\t\t5. jan 2008\trev 1.1\n\timproved code for better performance\n\nhm\t\t2. jun. 2008\trev 1.2\n\timproved performance\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "HYST_3.st", - "source": "FUNCTION_BLOCK HYST_3\nVAR_INPUT\n\tin : REAL;\n\thyst : REAL;\n\tval1 : REAL;\n\tval2 : REAL;\nEND_VAR\nVAR_OUTPUT\n\tQ1 : BOOL;\n\tQ2 : BOOL;\nEND_VAR\nVAR\n\tX: REAL;\nEND_VAR\n\n(*\nversion 1.2\t5 jan 2008\nprogrammer \toscat\ntested BY\toscat\n\nthis is a double hysteresis function. Out1 follows a hysteresis function defined by val1and hyst, while out 2 follows val2 and hyst.\nif the input signal is between the two hysteresis switches (val1 and val2) then non of the outputs is active.\n\n*)\n\nX := hyst * 0.5;\nIF in < val1 - X THEN\n\tq1 := TRUE;\nELSIF in > val1 + X THEN\n\tq1 := FALSE;\nEND_IF;\nIF in < val2 - X THEN\n\tq2 := FALSE;\nELSIF in > val2 + X THEN\n\tq2 := TRUE;\nEND_IF;\n\n\n\n(* revision history\nhm\t22. jan 2007\trev 1.0\n\toriginal version\n\nhm\t27. dec 2007\trev 1.1\n\tchanged code for better performance\n\nhm\t5. jan 2008\trev 1.2\n\tfurther performance iprovements\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "INC.st", - "source": "FUNCTION INC : INT\nVAR_INPUT\n\tX : INT;\n\tD : INT;\n\tM : INT;\nEND_VAR\n\n\n(*\nversion 1.1\t15. jan 2008\nprogrammer \thugo\ntested by\toscat\n\nThis is a increment function which increments the input X by the value D and compares the result with M.\nif the output exceeds M it will continue to count from 0 again.\n\n*)\n\nINC := (X + D + M + 1) MOD (M + 1);\n\n(* revision history\nhm\t7. feb 2007\t\tREV 1.0\n\toriginal version\n\nhm\t15. jan 2008\trev 1.1\n\tallow for neagtive increment\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "INC1.st", - "source": "FUNCTION INC1 : INT\nVAR_INPUT\n\tX : INT;\n\tN : INT;\nEND_VAR\n\n\n\n(*\nversion 1.2\t23. feb. 2009\nprogrammer \thugo\ntested by\toscat\n\nThis is a increment function which increments the variable X by 1 and if N is reached, it begins with 0 instead of N again.\ninc1(X,3) will generate 0,1,2,0,1,.....\n\n*)\n\nIF X >= N - 1 THEN\n\tINC1 := 0;\nELSE\n\tINC1 := X + 1;\nEND_IF;\n\n\n\n(* revision history\nhm\t13. oct. 2008\trev 1.0\n\toriginal version\n\nhm\t22. oct. 2008\trev 1.1\n\tadded statement to return value for compatibility reasons\n\nhm\t23. feb. 2009\trev 1.2\n \twhen inc1 is called with X >= N inc will continue with 0\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "INC2.st", - "source": "FUNCTION INC2 : INT\nVAR_INPUT\n\tX : INT;\n\tD : INT;\n\tL : INT;\n\tU : INT;\nEND_VAR\nVAR\n\ttmp: INT;\nEND_VAR\n\n\n(*\nversion 1.0\t29. jun. 2008\nprogrammer \thugo\ntested by\toscat\n\nThis function increments the input X by the value D and compares the result with U.\nif the output exceeds U it will continue to count from L again.\n\n*)\n\ntmp := U - L + 1;\nINC2 := (X + D - L + tmp) MOD tmp + L;\n\n\n\n(* revision history\nhm\t29. jun. 2008\t\tREV 1.0\n\toriginal version\n\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "INC_DEC.st", - "source": "FUNCTION_BLOCK INC_DEC\nVAR_INPUT\n\tCHa : BOOL;\n\tCHb : BOOL;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tdir : BOOL;\n\tcnt : INT;\nEND_VAR\nVAR\n\tedgea : BOOL;\n\tclk: BOOL;\n\tclka: BOOL;\n\tclkb: BOOL;\n\tedgeb: BOOL;\n\taxb: BOOL;\nEND_VAR\n\n(*\n\tversion 1.0\t4 aug 2006\n\tprogrammer \toscat\n\ttested BY\t\toscat\n\nincremental decoder with quadruple accuracy.\n2 pulses for each channel are created for each directional pulse.\n*)\n\naxb := cha XOR chb;\n\n(* create pulses for channel a *)\nclka := cha XOR edgea;\nedgea := cha;\n\nclkb := chb XOR edgeb;\nedgeb := chb;\n\n(* create pulses for both channels *)\nclk := clka OR clkb;\n\n(* set the direction output *)\nIF axb AND clka THEN dir := TRUE; END_IF;\nIF axb AND clkb THEN dir := FALSE; END_IF;\n\n(* increment or decrement the counter *)\nIF clk AND dir THEN cnt := cnt + 1; END_IF;\nIF clk AND NOT dir THEN cnt := cnt -1; END_IF;\n\n(* reset the counter if rst active *)\nIF rst THEN cnt := 0; END_IF;\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "INTEGRATE.st", - "source": "FUNCTION_BLOCK INTEGRATE\nVAR_INPUT\n\tE : BOOL := TRUE;\n\tX : REAL;\n\tK : REAL := 1.0;\nEND_VAR\nVAR_IN_OUT\n\tY : REAL;\nEND_VAR\nVAR\n\tX_last : REAL;\n\tinit: BOOL;\n\tlast: DWORD;\n\ttx: DWORD;\nEND_VAR\n\n\n(*\nversion 1.0\t3. nov. 2008\nprogrammer \thugo\ntested by\toscat\n\nintegrate is a plain integrator with I/O for out.\n\n \n*)\n\n(*read system time *)\ntx := T_PLC_MS();\n\nIF NOT init THEN\n\tinit := TRUE;\n\tX_last := X;\nELSIF E THEN\n\tY := (X + X_LAST) * 0.5E-3 * DWORD_TO_REAL(tx-last) * K + Y;\n\tX_last := X;\nEND_IF;\nlast := tx;\n\n\n\n(*\nhm 3. nov. 2008\trev 1.0\noriginal version\n\t\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "INTERLOCK.st", - "source": "FUNCTION_BLOCK INTERLOCK\nVAR_INPUT\n\tI1, I2 : BOOL;\n\tTL : TIME;\nEND_VAR\nVAR_OUTPUT\n\tQ1, Q2 : BOOL;\nEND_VAR\nVAR\n\tT1, T2 : TOF;\nEND_VAR\n\n(*\nversion 1.0\t28 sep 2007\nprogrammer \thugo\ntested by\t\ttobias\n\nINTERLOCK has two inputs I1 and I2 which drive the corresponding outputs Q1 and Q2.\nthe inputs signals lock each other out and therfore I1 can only drive Q1 when I2 is Low and vice versa.\nThe input TL specifies a dead time between two outputs can become active.\nan output can only become active when the other output was not active for the time TL.\n\n*)\n\n(* the input signal have a run delay to lockout the other input *)\nT1(IN := I1, PT := TL);\nT2(IN := I2, PT := TL);\n\nQ1 := I1 AND NOT t2.Q;\nQ2 := I2 AND NOT t1.Q;\n\n\n(* revision history\n\nhm\t28 sep 2007\t\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "INTERLOCK_4.st", - "source": "FUNCTION_BLOCK INTERLOCK_4\nVAR_INPUT CONSTANT\nEND_VAR\nVAR_INPUT\n\tI0 : BOOL;\n\tI1 : BOOL;\n\tI2 : BOOL;\n\tI3 : BOOL;\n\tE : BOOL;\n\tMODE : INT;\n\nEND_VAR\nVAR_OUTPUT\n\tOUT : BYTE;\n\tTP : BOOL;\nEND_VAR\nVAR\n\tin: BYTE;\n\tlast: BYTE;\n\told: BYTE;\n\tlmode: INT;\nEND_VAR\n\n(*\nversion 1.1\t14. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nINTERLOCK_4 detects one of 4 switches and delivers the number of the switch pressed on the output out\na output tp is true for one cycle if the output has changed.\na setup variable MODE selects between 3 different modes:\nMODE = 0, any input active will disable all other inputs\nMODE = 1, the input with the highest number will be acepted\nmode = 2, the input last pressed will disable all others \n\n*)\n\n(* check if enable is active *)\nIF E THEN\n(* reset all vars when there is a mode change on thy fly *)\n\tIF mode <> lmode THEN\n\t\tout := 0;\n\t\tlast := 0;\n\t\told := 0;\n\t\tlmode := mode;\n\tEND_IF;\n\t(* load inputs into in *)\n\tin.0 := I0;\n\tin.1 := I1;\n\tin.2 := I2;\n\tin.3 := I3;\n\t(* only execute when there is any change *)\n\tIF in <> last THEN\n\t\t(* only execute when inputs have chages state *)\n\t\tCASE mode OF\n\t\t\t0:\t(* output directly display inputs as bits in byte out *)\n\t\t\t\tout := in;\n\n\t\t\t1:\t(* the input with the highest number will be acepted *)\n\t\t\t\tIF in.3 THEN out := 8;\n\t\t\t\tELSIF in.2 THEN out := 4;\n\t\t\t\tELSIF in.1 THEN out := 2;\n\t\t\t\tELSE out := in;\n\t\t\t\tEND_IF;\n\n\t\t\t2:\t(* input last pressed will be displayed only *)\n\t\t\t\tlast := ((in XOR last) AND in);\n\t\t\t\tIF last.3 THEN out := 8;\n\t\t\t\tELSIF last.2 THEN out := 4;\n\t\t\t\tELSIF last.1 THEN out := 2;\n\t\t\t\tELSE out := last;\n\t\t\t\tEND_IF;\n\n\t\t\t3:\t(* any input active will disable all other inputs *)\n\t\t\t\tIF (out AND in) = 0 THEN\n\t\t\t\t\tIF in.3 THEN out := 8;\n\t\t\t\t\tELSIF in.2 THEN out := 4;\n\t\t\t\t\tELSIF in.1 THEN out := 2;\n\t\t\t\t\tELSE out := in;\n\t\t\t\t\tEND_IF;\n\t\t\t\tEND_IF;\n\n\t\tEND_CASE;\n\t\tlast := in;\n\tEND_IF;\n\ttp := out <> old;\n\told := out;\nELSE\n\tout := 0;\n\tlast := 0;\n\told := 0;\n\tlmode := 0;\n\ttp := FALSE;\nEND_IF;\n\n\n(* revision history\nhm\t24. oct 2008\trev 1.0\n\toriginal version\n\nhm\t14. mar. 2009\trev 1.1\n\treplaced double assignments\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "INT_TO_BCDC.st", - "source": "FUNCTION INT_TO_BCDC : BYTE\nVAR_INPUT\n\tIN : INT;\nEND_VAR\n\n\n(*\nversion 1.1\t30. jun. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function converts an integer into a two digit bcd number.\n*)\n\nINT_TO_BCDC := SHL(INT_TO_BYTE(IN / INT#10),4) OR INT_TO_BYTE(in MOD INT#10);\n\n(* revision history\nhm\t13.12.2007\n\toriginal version\n\nhm\t30.6.2008\trev 1.1\n\tchanged name INT_TO_BCD to INT_TO_BCDC to avoid collision with util.lib\n\tcorrected error in code\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "INV.st", - "source": "FUNCTION INV : REAL\nVAR_INPUT\n\tX : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nThis function calculates the result of 1 / X\n\n*)\n\nIF X <> 0.0 THEN INV := 1.0 / X; END_IF;\n\n\n\n\n(* revision history\nhm\t26. oct. 2008\trev 1.0\n\toriginal version\n\nhm\t10. mar. 2009\trev 1.1\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "ISC_ALPHA.st", - "source": "FUNCTION ISC_ALPHA : BOOL\nVAR_INPUT\n\tIN : BYTE;\nEND_VAR\n\n\n(*\nversion 1.1\t19. oct. 2008\nprogrammer \toscat\ntested by\toscat\n\nISC_ALPHA checks if a character is a..z or A..Z.\n\n*)\n\nIF setup.EXTENDED_ASCII THEN\n\tISC_ALPHA := (in > 64 AND in < 91) OR (in > 191 AND in <> 215 AND in <> 247) OR (in > 96 AND in < 123);\nELSE\n\tISC_ALPHA := (IN > 64 AND IN < 91) OR (in > 96 AND in < 123);\nEND_IF;\n\n(* revision history\nhm\t6. mar. 2008\trev 1.0\n\toriginal version\n\nhm\t19. oct. 2008\trev 1.1\n\tchanges setup constants\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "ISC_CTRL.st", - "source": "FUNCTION ISC_CTRL : BOOL\nVAR_INPUT\n\tIN : BYTE;\nEND_VAR\n\n\n(*\nversion 1.0\t6. mar 2008\nprogrammer \toscat\ntested by\t\thugo\n\nISC_ALPHA checks if a character is a control character.\n\n*)\n\nISC_CTRL := IN < 32 OR IN = 127;\n\n(* revision history\nhm\t\t6. mar. 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "ISC_HEX.st", - "source": "FUNCTION ISC_HEX : BOOL\nVAR_INPUT\n\tIN : BYTE;\nEND_VAR\n\n\n(*\nversion 1.0\t6. mar 2008\nprogrammer \toscat\ntested by\t\thugo\n\nISC_HEX checks if a character is 0..9, A..F, a..f.\n\n*)\n\nISC_HEX := (IN > 47 AND IN < 58) OR (IN > 64 AND IN < 71) OR (IN > 96 AND IN < 103);\n\n(* revision history\nhm\t\t6. mar. 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "ISC_LOWER.st", - "source": "FUNCTION ISC_LOWER : BOOL\nVAR_INPUT\n\tIN : BYTE;\nEND_VAR\n\n\n(*\nversion 1.1\t19. oct. 2008\nprogrammer \thugo\ntested by\toscat\n\nisc_lower checks if a character is lowercase.\n\n*)\n\nIF setup.EXTENDED_ASCII THEN\n\tISC_LOWER := ((in > 96) AND (in < 123)) OR ((in > 222) AND (in <> 247));\nELSE\n\tISC_LOWER := ((in > 96) AND (in < 123));\nEND_IF;\n\n(* revision history\nhm\t6. mar. 2008\trev 1.0\n\toriginal version\n\nhm\t19. oct. 2008\trev 1.1\n\tchanges setup constants\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "ISC_NUM.st", - "source": "FUNCTION ISC_NUM : BOOL\nVAR_INPUT\n\tIN : BYTE;\nEND_VAR\n\n\n(*\nversion 1.0\t6. mar 2008\nprogrammer \toscat\ntested by\t\thugo\n\nISC_NUM checks if a character is 0..9.\n\n*)\n\nISC_NUM := IN > 47 AND IN < 58;\n\n(* revision history\nhm\t\t6. mar. 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "ISC_UPPER.st", - "source": "FUNCTION ISC_UPPER : BOOL\nVAR_INPUT\n\tIN : BYTE;\nEND_VAR\n\n\n(*\nversion 1.1\t19. oct. 2008\nprogrammer \thugo\ntested by\toscat\n\nISC_upper checks if a character is uppercase\n\n*)\n\nIF setup.EXTENDED_ASCII THEN\n\tISC_UPPER := ((in > 64) AND (in < 91)) OR (((in > 191) AND (in < 223)) AND (in <> 215));\nELSE\n\tISC_UPPER := ((in > 64) AND (in < 91));\nEND_IF;\n\n\n(* revision history\nhm\t6. mar. 2008\trev 1.0\n\toriginal version\n\nhm\t19. oct. 2008\trev 1.1\n\tchanges setup constants\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "IS_ALNUM.st", - "source": "FUNCTION IS_ALNUM : BOOL\nVAR_INPUT\n\tstr : STRING(STRING_LENGTH);\nEND_VAR\nVAR\n\tL: INT;\n\tpt : POINTER TO BYTE;\n\tpos: INT;\nEND_VAR\n\n(*\nversion 1.1\t29. mar. 2008\nprogrammer \t\tkurt\ntested by\t\thugo\n\nISC_ALNUM testet ob in einem string nur Zahlen 0..9 vorkommen.\n\n*)\n\nPT := ADR(str);\nL := LEN(str);\nFOR pos := 1 TO L DO\n\tIF NOT (ISC_ALPHA(pt^) OR ISC_NUM(pt^)) THEN\n\t\tIS_ALNUM := FALSE;\n\t\tRETURN;\n\tEND_IF;\n \tPT := PT + 1;\nEND_FOR;\nIS_ALNUM := L > 0;\n\n\n(* revision history\nhm\t29. feb 2008\trev 1.0\n\toriginal version\n\nhm\t29. mar. 2008\trev 1.1\n\tchanged STRING to STRING(STRING_LENGTH)\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "IS_ALPHA.st", - "source": "FUNCTION IS_ALPHA : BOOL\nVAR_INPUT\n\tstr : STRING(STRING_LENGTH);\nEND_VAR\nVAR\n\tL: INT;\n\tpt : POINTER TO BYTE;\n\tpos: INT;\nEND_VAR\n\n(*\nversion 1.1\t29. mar. 2008\nprogrammer \t\tkurt\ntested by\t\thugo\n\nIS_ALPHA testet ob in einem string nur Zeichen a-z oder A - Z vorkommen.\n\n*)\n\nPT := ADR(str);\nL := LEN(str);\nFOR pos := 1 TO L DO\n\tIF NOT ISC_ALPHA(pt^) THEN\n\t\tIS_ALPHA := FALSE;\n\t\tRETURN;\n\tEND_IF;\n \tPT := PT + 1;\nEND_FOR;\nIS_ALPHA := L > 0;\n\n\n(* revision history\nhm\t29. feb 2008\trev 1.0\n\toriginal version\n\nhm\t29. mar. 2008\trev 1.1\n\tchanged STRING to STRING(STRING_LENGTH)\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "IS_CC.st", - "source": "FUNCTION IS_CC : BOOL\nVAR_INPUT\n\tstr : STRING(STRING_LENGTH);\n\tcmp : STRING(STRING_LENGTH);\nEND_VAR\nVAR\n\tL: INT;\n\tpos: INT;\nEND_VAR\n\n(*\nversion 1.1\t29. mar. 2008\nprogrammer \tTobias\ntested by\thugo\n\nISC_CC testet ob ein string nur aus Zeichen des Strings CMP besteht.\n\n*)\n\nL := LEN(str);\nFOR pos := 1 TO L DO\n\tIF FIND(CMP,MID(str,1,pos)) = 0 THEN RETURN; END_IF;\nEND_FOR;\nIS_CC := L > 0;\n\n\n\n(* revision history\nhm\t19. mar 2008\trev 1.0\n\toriginal version\n\nhm\t29. mar. 2008\trev 1.1\n\tchanged STRING to STRING(STRING_LENGTH)\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "IS_CTRL.st", - "source": "FUNCTION IS_CTRL : BOOL\nVAR_INPUT\n\tSTR : STRING(STRING_LENGTH);\nEND_VAR\nVAR\n\tL: INT;\n\tpt : POINTER TO BYTE;\n\tpos: INT;\nEND_VAR\n\n(*\nversion 1.1\t29. mar 2008\nprogrammer \t\tkurt\ntested by\t\thugo\n\nIS_CTRL testet ob in einem string nur Steuerzeichen (Char < 32) vorkommen.\n\n*)\n\nPT := ADR(str);\nL := LEN(str);\nFOR pos := 1 TO L DO\n\tIF NOT (ISC_CTRL(pt^)) THEN\n\t\tIS_CTRL := FALSE;\n\t\tRETURN;\n\tEND_IF;\n \tPT := PT + 1;\nEND_FOR;\nIS_CTRL := L > 0;\n\n\n(* revision history\nhm\t29. feb. 2008\trev 1.0\n\toriginal version\n\nhm\t29. mar. 2008\trev 1.1\n\tchanged STRING to STRING(STRING_LENGTH)\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "IS_HEX.st", - "source": "FUNCTION IS_HEX : BOOL\nVAR_INPUT\n\tstr : STRING(STRING_LENGTH);\nEND_VAR\nVAR\n\tL: INT;\n\tpt : POINTER TO BYTE;\n\tpos: INT;\nEND_VAR\n\n(*\nversion 1.1\t29. mar. 2008\nprogrammer \t\tkurt\ntested by\t\thugo\n\nIS_HEX testet ob in einem string nur Zahlen 0..9 oder A..F oder a..f vorkommen.\n\n*)\n\nPT := ADR(str);\nL := LEN(str);\nFOR pos := 1 TO L DO\n\tIF NOT (ISC_HEX(pt^)) THEN\n\t\tIS_HEX := FALSE;\n\t\tRETURN;\n\tEND_IF;\n \tPT := PT + 1;\nEND_FOR;\nIS_HEX := L > 0;\n\n\n(* revision history\nhm\t29. feb 2008\trev 1.0\n\toriginal version\n\nhm\t29. mar. 2008\trev 1.1\n\tchanged STRING to STRING(STRING_LENGTH)\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "IS_LOWER.st", - "source": "FUNCTION IS_LOWER : BOOL\nVAR_INPUT\n\tstr : STRING(STRING_LENGTH);\nEND_VAR\nVAR\n\tl: INT;\n\tpt : POINTER TO BYTE;\n\tpos: INT;\nEND_VAR\n\n(*\nversion 1.1\t29. mar. 2008\nprogrammer \t\tkurt\ntested by\t\thugo\n\nIS_LOWER testet ob in einem string nur kleinbuchstaben vorkommen.\n\n*)\n\nPT := ADR(str);\nL := LEN(str);\nFOR pos := 1 TO L DO\n\tIF NOT (ISC_LOWER(pt^)) THEN\n\t\tIS_LOWER := FALSE;\n\t\tRETURN;\n\tEND_IF;\n \tPT := PT + 1;\nEND_FOR;\nIS_LOWER := L > 0;\n\n\n(* revision history\nhm\t29. feb 2008\trev 1.0\n\toriginal version\n\nhm\t29. mar. 2008\trev 1.1\n\tchanged STRING to STRING(STRING_LENGTH)\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "IS_NCC.st", - "source": "FUNCTION IS_NCC : BOOL\nVAR_INPUT\n\tstr : STRING(STRING_LENGTH);\n\tcmp : STRING(STRING_LENGTH);\nEND_VAR\nVAR\n\tL: INT;\n\tpos: INT;\nEND_VAR\n\n(*\nversion 1.1\t29. mar. 2008\nprogrammer \tTobias\ntested by\t\thugo\n\nIS_NCC testet ob in einem string keine Zeichen des Strings CMP enthalten sind.\n\n*)\n\nL := LEN(str);\nFOR pos := 1 TO L DO\n\tIF FIND(CMP,MID(str,1,pos)) > 0 THEN RETURN; END_IF;\nEND_FOR;\nIS_NCC := TRUE;\n\n\n\n(* revision history\nhm\t19. mar 2008\trev 1.0\n\toriginal version\n\nhm\t29. mar. 2008\trev 1.1\n\tchanged STRING to STRING(STRING_LENGTH)\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "IS_NUM.st", - "source": "FUNCTION IS_NUM : BOOL\nVAR_INPUT\n\tstr : STRING(STRING_LENGTH);\nEND_VAR\nVAR\n\tL : INT;\n\tpt : POINTER TO BYTE;\n\tpos: INT;\nEND_VAR\n\n(*\nversion 1.1\t29. mar. 2008\nprogrammer \t\tkurt\ntested by\t\thugo\n\nIS_NUM testet ob in einem string nur Zahlen 0..9 vorkommen.\n\n*)\n\nPT := ADR(str);\nL := LEN(str);\nFOR pos := 1 TO L DO\n\tIF NOT (ISC_NUM(pt^)) THEN\n\t\tIS_NUM := FALSE;\n\t\tRETURN;\n\tEND_IF;\n \tPT := PT + 1;\nEND_FOR;\nIS_NUM := L > 0;\n\n\n(* revision history\nhm\t29. feb 2008\trev 1.0\n\toriginal version\n\nhm\t29. mar. 2008\trev 1.1\n\tchanged STRING to STRING(STRING_LENGTH)\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "IS_SORTED.st", - "source": "FUNCTION IS_SORTED : BOOL\nVAR_INPUT\n\tpt : POINTER TO ARRAY[0..32000] OF REAL;\n\tsize : UINT;\nEND_VAR\nVAR\n\n\tstop: INT;\n\ti: INT;\nEND_VAR\n\n(*\nversion 1.1\t4. apr. 2008\nprogrammer \thugo\ntested by\ttobias\n\nthis function will return true if the given array is sorted in an ascending order.\nthe function needs to be called:\tarray_sorted(adr(\"array\"),sizeof(\"array\"));\nbecause this function works with pointers its very time efficient and it needs no extra memory.\n\n*)\n\nstop := UINT_TO_INT(SHR(size,2)-2);\nFOR i := 0 TO stop DO\n\tIF pt^[i] > pt^[i+1] THEN\n\t\tIS_SORTED := FALSE;\n\t\tRETURN;\n\tEND_IF;\nEND_FOR;\n\nIS_SORTED := TRUE;\n\n(* revision history\n\nhm \t29. mar. 2008 \trev 1.0\n\toriginal version\n\nhm\t4. apr. 2008\trev 1.1\n\tadded type conversion to avoid warnings under codesys 3.0\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "IS_UPPER.st", - "source": "FUNCTION IS_UPPER : BOOL\nVAR_INPUT\n\tstr : STRING(STRING_LENGTH);\nEND_VAR\nVAR\n\tL: INT;\n\tpt : POINTER TO BYTE;\n\tpos: INT;\nEND_VAR\n\n(*\nversion 1.1\t29. mar. 2008\nprogrammer \t\tkurt\ntested by\t\thugo\n\nIS_UPPER testet ob in einem string keine Kleinbuchstaben vorkommen.\n\n*)\n\nPT := ADR(str);\nL := LEN(str);\nFOR pos := 1 TO L DO\n\tIF NOT (ISC_UPPER(pt^)) THEN\n\t\tIS_UPPER := FALSE;\n\t\tRETURN;\n\tEND_IF;\n \tPT := PT + 1;\nEND_FOR;\nIS_UPPER := L > 0;\n\n\n(* revision history\nhm\t29. feb 2008\trev 1.0\n\toriginal version\n\nhm\t29. mar. 2008\trev 1.1\n\tchanged STRING to STRING(STRING_LENGTH)\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "JD2000.st", - "source": "FUNCTION JD2000 : REAL\nVAR_INPUT\n\tDTI : DT;\nEND_VAR\n\n\n(*\nversion 1.0\t15. jul. 2008\nprogrammer \thugo\ntested by\toscat\n\nJULIAN calculates the astronomic julian date from 1.1.2000-12:00.\n\n*)\n\nJD2000 := DWORD_TO_REAL(DT_TO_DWORD(DTI) - 946728000) / 86400.0;\n\n(* revision histroy\nhm\t15. jul. 2008\trev 1.0\n\toriginal release\n\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "KMH_TO_MS.st", - "source": "FUNCTION KMH_TO_MS : REAL\nVAR_INPUT\n\tkmh : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t6 jan 2007\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function converts velocities from Kilometers / hour to Meters / Second\n\n*)\n\nKMH_TO_MS := kmh * 0.2777777777777;\n\n(* revision history\nhm\t4. feb 2007\t\trev 1.0\n\toriginal version\n\nhm\t6. jan 2008\t\trev 1.1\n\timproved performance\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "K_TO_C.st", - "source": "FUNCTION K_TO_C : REAL\nVAR_INPUT\n\tKelvin : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t19. aug 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function converts kelvin to celsius\n\n*)\n\nK_TO_C := Kelvin + phys.T0;\n\n\n(* revision history\n\nhm\t4. aug 2006\trev 1.0\n\toriginal version\n\nhm\t19. aug 2009\trev 1.1\n\tfixed calculation error\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "LAMBERT_W.st", - "source": "FUNCTION LAMBERT_W : REAL\nVAR_INPUT\n\tX : REAL;\nEND_VAR\nVAR\n\tw : REAL;\n\ti : INT;\n\twe: REAL;\n\tw1e: REAL;\n\tlast: DWORD;\n\tewx: REAL;\nEND_VAR\n\n\n\n(*\nversion 1.1\t10. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nthis function calculates the lambert_w function.\n\n*)\n\n(* check for valid input and return -1000 if too low *)\nIF x < -0.367879441171442 THEN\n\tLAMBERT_W := -1000.0;\n\tRETURN;\n(* return 0 if x = 0 *)\nELSIF x = 0.0 THEN\n\tRETURN;\n(* first an estimate is calculated *)\nELSIF x <= 500.0 THEN\n\tw := LN(x + 1.0);\n\tw := 0.665 * (1.0 + 0.0195 * w) * w + 0.04;\nELSE\n\tw := LN(x - 4.0) - (1.0 - 1.0/LN(x)) * LN(LN(x));\nEND_IF;\n(* use estimate to calculate exact result *)\nFOR i := 0 TO 5 DO\n\tewx := EXP(w);\n\twe := w * ewx - x;\n\tw1e := (w+1.0) * ewx;\n\tlast := REAL_TO_DW(w) AND 16#FFFF_FFFC;\n\tw := w - (we / (w1e - (w+2.0) * we / (2.0 * w + 2.0)));\n\tIF (REAL_TO_DW(w) AND 16#FFFF_FFFC) = last THEN EXIT; END_IF;\nEND_FOR;\nLAMBERT_W := w;\n\n\n(* revision hisdtory\nhm\t26. oct. 2008\trev 1.0\n\toriginal version\n\nhm\t10. mar. 2009\trev 1.1\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "LANGEVIN.st", - "source": "FUNCTION LANGEVIN : REAL\nVAR_INPUT\n\tX : REAL;\nEND_VAR\n\n\n(*\nversion 1.2\t10.mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the langevin function\n\n*)\n\nIF X = 0.0 THEN\n\tLANGEVIN := 0.0;\nELSE\n\tLANGEVIN := COTH(X) - 1.0 / X;\nEND_IF;\n\n(* revision history\nhm\t10.12.2007\trev 1.0\n\toriginal version\n\nhm\t11. mar 2008\trev 1.1\n\tchanged formula to avoid problems when x = 0\n\nhm\t10. mar. 2009\trev 1.2\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "LEAP_DAY.st", - "source": "FUNCTION LEAP_DAY : BOOL\nVAR_INPUT\n\tIDATE : DATE;\nEND_VAR\nVAR\nEND_VAR\n\n\n(*\nversion 1.2\t24. jan. 2011\nprogrammer \thugo\ntested by\toscat\n\n\nleap_day is true if the tested day is a leap day (29. of february). \n \n*)\n\nLEAP_DAY := DATE_TO_UDINT(IDATE) MOD 126230400 = 68169600;\n\n\n(* change history\n\nhm \t15. jun. 2008\trev 1.0\n\toriginal version\n\nhm\t7. oct. 2008\trev 1.1\n\tchanged function month to month_of_date\n\nhm\t24. jan. 2011\trev 1.2\n\timproved performance\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "LEAP_OF_DATE.st", - "source": "FUNCTION LEAP_OF_DATE : BOOL\nVAR_INPUT\n\tidate : DATE;\nEND_VAR\n\n\n(*\nversion 1.3\t\t28. jan. 2011\nprogrammer \thugo\ntested by\t\ttobias\n\nleap_of_date is true if current year is a leap year \n\n*)\n\nLEAP_OF_DATE := SHL(((DATE_TO_DWORD(idate) + 43200) / 31557600), 30) = 16#80000000;\n\n\n(* change history\n\n2.10.2006\t\trev 1.1\nthe function now calls leap_year to accomodate further accuracy.\nthe function now works for any year from 1970 to 2100\n\n8. jan 2008\t\trev 1.2\n\timproved code for better performance\n\n28. jan. 2011\trev 1.3\n\timproved performance\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "LEAP_YEAR.st", - "source": "FUNCTION LEAP_YEAR : BOOL\nVAR_INPUT\n\tyr : INT;\nEND_VAR\n\n\n(*\nversion 1.1\t2. oct. 2006\nprogrammer \thugo\ntested by\ttobias\n\n\nleap_year is true if the tested year is a leap year \n \n*)\n\nLEAP_YEAR := SHL(yr,14) = 0;\n\n(* this code was used prior to rev 1.1\n\nIF yr MOD 400 = 0 THEN leap_year := TRUE;\nELSIF yr MOD 100 = 0 THEN leap_year := FALSE;\nELSIF yr MOD 4 =0 THEN leap_year := TRUE;\nELSE leap_year := FALSE;\nEND_IF;\n\n*)\n\n(* change history\n\nhm \t2.10.2006\t\trev 1.1\n\tthe function now works for any year from 1970 up to 2100\n\nhm\t1. oct 2007\t\trev 1.2\n\tchaged code for higher performance\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "LENGTH.st", - "source": "FUNCTION_BLOCK LENGTH\nVAR_INPUT\n\tm : REAL;\n\tp : REAL;\n\tin : REAL;\n\tft : REAL;\n\tyd : REAL;\n\tmile : REAL;\n\tsm : REAL;\n\tfm : REAL;\nEND_VAR\nVAR_OUTPUT\n\tYm : REAL;\n\tYp : REAL;\n\tYin : REAL;\n\tYft : REAL;\n\tYyd : REAL;\n\tYmile : REAL;\n\tYsm : REAL;\n\tYfm : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t11. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nthis function converts different length units\nany unused input can simply be left open.\ndifferent inputs connected at the same time will be added up.\n\n*)\n\nYm :=\tm\n\t\t+ p * 0.000376065\n\t\t+ in * 0.0254\n\t\t+ ft * 0.3048\n\t\t+ yd * 0.9144\n\t\t+ mile * 1609.344\n\t\t+ sm * 1852.0\n\t\t+ fm * 1.829;\nYp := Ym * 2659.11478068951;\nYin := Ym * 39.37007874016;\nYft := Ym * 3.28083989501;\nYyd := Ym * 1.09361329834;\nYmile := Ym * 0.00062137119;\nYsm := Ym * 0.00053995680;\nYfm := Ym * 0.54674685621;\n\n(*\nLänge Meter m SI-Basiseinheit\nAstronomische Einheit* AE 1 AE = 149,597 870 · E9 m\nParsec pc 1 pc = 206265 AE = 30,857 · E15 m\nLichtjahr Lj 1 Lj = 9,460 530 · E15 m = 63240 AE = 0,306 59 pc\nÅngström Å 1 Å = E–l0 m\ntypograph. Punkt p 1 p = 0,376 065 mm • im Druckereigewerbe\ninch** in 1 in = 2,54 · E–2 m = 25,4 mm***\nfoot ft 1 ft = 0,3048 m = 30,48 cm\nyard yd 1 yd = 0,9144 m\nmile mile 1 mile = 1609,344 m\nInternat. Seemeile sm 1 sm = 1852 m\nFathom fm 1 fm = 1,829 m • in der Seeschifffahrt\n*)\n\n(* revision history\n\nhm\t27. mar. 2007\trev 1.0\n\toriginal version\n\nhm\t11. mar. 2009\trev 1.1\n\timproved code\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "LINEAR_INT.st", - "source": "FUNCTION LINEAR_INT : REAL\nVAR_INPUT\n\tX : REAL;\n\tXY : ARRAY[1..20,0..1] OF REAL;\n\tPts : INT;\nEND_VAR\nVAR\n\ti : INT;\nEND_VAR\n\n(*\n\tversion 1.1\t27 dec 2007\n\tprogrammer \toscat\n\ttested BY\t\toscat\n\nLINEAR_INT calculates an output based on a linear interpolation of up to 20 coordinates given in an array\nthe input coordinates have to start at the lowest array position and must be sorted ba ascending X values.\n\n*)\n\n(*make sure n is bound within the array size *)\npts := MIN(pts,20);\n\n(* calculate the linear segement interpolation *)\ni := 2;\n(* search for segment and calculate output\n\tbelow and above the defined segments we interpolate the last segment *)\nWHILE (i < pts) AND (XY[i,0] < X) DO\n\ti := i + 1;\nEND_WHILE;\n\n(* calculate the output value on the corresponding segment coordinates *)\nLINEAR_INT := ((XY[i,1] - XY[i-1,1]) * X - XY[i,1] * XY[i-1,0] + XY[i-1,1] * XY[i,0]) / (XY[i,0] - XY[i-1,0]);\n\n(* revision history\nhm\t7. oct 2007\t\trev 1.0\n\toriginal version\n\nhm\t27 dec 2007\t\trev 1.1\n\tchanged code for better performance\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "LIST_ADD.st", - "source": "FUNCTION LIST_ADD : BOOL\nVAR_INPUT\n\tSEP : BYTE;\n\tINS : STRING(LIST_LENGTH);\nEND_VAR\nVAR_IN_OUT\n\tLIST : STRING(LIST_LENGTH);\nEND_VAR\nVAR\n\tsx : STRING(1);\nEND_VAR\n\n\n(*\nversion 2.0\t\t21. mar. 2011\nprogrammer \thugo\ntested by\t\tkurt\n\nLIST_ADD hängt ein weiteres element ans ende einer liste.\ndie liste liegt als string von elementen vor die mit den zeichen SEP am anfang makiert sind.\n\n*)\n\nsx := CHR_TO_STRING(SEP);\t\t\t(* convert separation character to string *)\nINS := CONCAT(sx, INS);\t\t\t\t\t(* start element with separation character *)\n\nIF LEN(LIST) + LEN(INS) > LIST_LENGTH THEN\n\tLIST_ADD := FALSE;\t\t\t\t\t(* return false if element does not fit *)\nELSE\n\tLIST := CONCAT(LIST, INS);\n\tLIST_ADD := TRUE;\nEND_IF;\n\n\n(* revision histroy\n\nhm\t21. mar. 2011\trev 2.0\n\toriginal release\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "LIST_CLEAN.st", - "source": "FUNCTION LIST_CLEAN : BOOL\nVAR_INPUT\n\tSEP : BYTE;\nEND_VAR\nVAR_IN_OUT\n\tLIST : STRING(LIST_LENGTH);\nEND_VAR\nVAR\n\tpt : POINTER TO ARRAY[1..LIST_LENGTH] OF BYTE;\n\tread : INT := 1;\n\twrite : INT := 1;\n\tlast: BYTE;\n\tc: BYTE;\nEND_VAR\n\n\n(*\nversion 2.0\t21. mar. 2011\nprogrammer \thugo\ntested by\t\toscat\n\nLIST_CLEAN bereinigt eine liste von leeren Elementen.\ndie liste liegt als string von elementen vor die mit den zeichen SEP am anfang markiert sind.\n\n*)\n\npt := ADR(LIST);\n\nFOR read := 1 TO LIST_LENGTH DO\n\tc := pt^[read];\t\t\t\t\t\t\t\t(* read character from list *)\n\tIF c = 0 THEN EXIT;\t\t\t\t\t\t(* exit the loop if character definbes end of string *)\n\tELSIF c <> SEP OR sep <> last THEN\t(* copy element from read to write position unless a double sep character is present *)\n\t\tpt^[write] := c;\n\t\twrite := write + 1;\n\tEND_IF;\n\tlast := c;\t\t\t\t\t\t\t\t\t(* remember last character *)\nEND_FOR;\n\nIF last = SEP THEN write := write - 1; END_IF;\t\t(* if last character is sep then delete empty element at end *)\nIF write <= STRING_LENGTH THEN pt^[write] := 0;\t END_IF;\t\t(* terminate string with 0 *)\n\nLIST_CLEAN := TRUE;\t\t\t\t\t\t(* retrun TRUE *)\n\n\n(* revision histroy\nhm\t28. jun. 2008\trev 1.0\n\toriginal release\n\nhm\t19. jan. 2011\trev 1.1\n\tchanged string(255) to string(LIST_LENGTH)\n\nhm\t21. mar. 2011\trev 2.0\n\tall elements start with SEP\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "LIST_GET.st", - "source": "FUNCTION LIST_GET : STRING(LIST_LENGTH)\nVAR_INPUT\n\tSEP : BYTE;\n\tPOS : INT;\nEND_VAR\nVAR_IN_OUT\n\tLIST : STRING(LIST_LENGTH);\nEND_VAR\nVAR\n\ti : INT := 1;\n\to : INT := 1;\n\tpt : POINTER TO ARRAY[1..LIST_LENGTH] OF BYTE;\n\tpo : POINTER TO ARRAY[1..LIST_LENGTH] OF BYTE;\n\tcnt: INT := 0;\n\tc: BYTE;\nEND_VAR\n\n\n(*\nversion 2.0\t21. mar. 2011\nprogrammer \thugo\ntested by\t\toscat\n\nLIST_GET liefert das element an der stelle pos einer liste.\ndie liste liegt als string von elementen vor die mit den zeichen SEP am anfang makiert sind.\n\n*)\n\npt := ADR(LIST);\t\t\t\t\t\t\t(* load pointers *)\npo := ADR(LIST_GET);\n\nREPEAT\n\tc := pt^[i];\n\tIF cnt = pos THEN\t\t\t\t\t\t(* copy element to output string *)\n\t\tIF c = SEP THEN EXIT; END_IF;\t\t(* next element stop copy and finish *)\n\t\tpo^[o] := c;\n\t\to := o + 1;\n\tELSIF c = SEP THEN\n\t\tcnt := cnt + 1;\n\tEND_IF;\n\ti := i + 1;\nUNTIL\n\t(i = LIST_LENGTH) OR (c = 0)\nEND_REPEAT;\npo^[o] := 0;\t\t\t\t\t\t(* close the output string *)\n\n\n\n(* revision histroy\nhm\t20. jun. 2008\trev 1.0\n\toriginal release\n\nhm\t19. jan. 2011\trev 1.1\n\tchanged string(255) to strring(LIST_LENGTH)\n\nhm\t21. mar. 2011\trev 2.0\n\tall list elements start with SEP\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "LIST_INSERT.st", - "source": "FUNCTION LIST_INSERT : BOOL\nVAR_INPUT\n\tSEP : BYTE;\n\tPOS : INT;\n\tINS : STRING(LIST_LENGTH);\nEND_VAR\nVAR_IN_OUT\n\tLIST : STRING(LIST_LENGTH);\nEND_VAR\nVAR\n\tpt : POINTER TO ARRAY[1..LIST_LENGTH] OF BYTE;\n\tread : INT := 1;\n\tcnt : INT := 1;\n\tsx : STRING(1);\nEND_VAR\n\n\n(*\nversion 2.0\t21. mar. 2011\nprogrammer \thugo\ntested by\t\toscat\n\nLIST_INSERT setzt ein element an der stelle pos in eine liste ein.\ndie liste liegt als string von elementen vor die mit den zeichen SEP am anfang markiert sind.\n\n*)\n\n(* load pointers *)\npt := ADR(LIST);\n\nIF LEN(ins) + 1 + LEN(LIST) > LIST_LENGTH THEN\n\tLIST_INSERT := FALSE;\nELSE\n\tLIST_INSERT := TRUE;\n\t(* search for position *)\n\tWHILE read < LIST_LENGTH DO\n\t\tIF cnt >= POS THEN\n\t\t\tsx := CHR_TO_STRING(SEP);\n\t\t\tINS := CONCAT(sx, INS);\n\t\t\tLIST := INSERT(LIST, INS, read - 1);\n\t\t\tLIST_INSERT := TRUE;\n\t\t\tRETURN;\n\t\tEND_IF;\n\t\tIF pt^[read] = 0 THEN\t\t\t\t(* list is too short add empty element *)\n\t\t\tpt^[read] := SEP;\n\t\t\tpt^[read + 1] := 0;\n\t\tEND_IF;\n\t\tread := read + 1;\n\t\tIF pt^[read] = SEP OR pt^[read] = 0 THEN cnt := cnt + 1; END_IF;\n\tEND_WHILE;\nEND_IF;\n\n\n\n(* revision histroy\nhm\t28. jun. 2008\trev 1.0\n\toriginal release\n\nhm\t17. dec. 2008\trev 1.1\n\tchanges name of function chr to chr_to_string\n\nhm\t19. jan. 2011\trev 1.2\n\tchanged string(255) to string(LIST_LENGTH)\n\nhm\t21. mar. 2011\trev 2.0\n\tall list elements start with SEP\n\t\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "LIST_LEN.st", - "source": "FUNCTION LIST_LEN : INT\nVAR_INPUT\n\tSEP : BYTE;\nEND_VAR\nVAR_IN_OUT\n\tLIST : STRING(LIST_LENGTH);\nEND_VAR\nVAR\n\tpt : POINTER TO ARRAY[1..LIST_LENGTH] OF BYTE;\n\tpos: INT := 1;\n\tc: BYTE;\nEND_VAR\n\n\n(*\nversion 2.0\t21. mar. 2011\nprogrammer \thugo\ntested by\t\toscat\n\nLIST_LEN liefert die anzahl der elemente einer liste.\ndie liste liegt als string von elementen vor die mit den zeichen SEP am anfang markiert sind.\n\n*)\n\npt := ADR(LIST);\nLIST_LEN := 0;\nREPEAT\n\tc := pt^[pos];\n\tIF c = SEP THEN LIST_LEN := LIST_LEN + 1; END_IF;\n\tpos := pos + 1;\nUNTIL\n\tc = 0 OR pos > LIST_LENGTH\nEND_REPEAT;\n\n\n\n(* revision histroy\nhm\t25. jun. 2008\trev 1.0\n\toriginal release\n\nhm\t16. oct. 2008\trev 1.1\n\tfixed a problem where list_len would only work up to LIST_LENGTH\n\nhm\t19. jan. 2001\trev 1.2\n\tchanged string(255) to string(LIST_LENGTH)\n\nhm\t21. mar. 2011\trev 2.0\n\tall list elements start with SEP\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "LIST_NEXT.st", - "source": "FUNCTION_BLOCK LIST_NEXT\nVAR_INPUT\n\tSEP : BYTE;\n\tRST : BOOL;\nEND_VAR\nVAR_IN_OUT\n\tLIST : STRING(LIST_LENGTH);\nEND_VAR\nVAR_OUTPUT\n\tLEL : STRING(LIST_LENGTH);\n\tNUL : BOOL;\nEND_VAR\nVAR\n\tpos : INT := 1;\n\tpt : POINTER TO ARRAY[1..LIST_LENGTH] OF BYTE;\n\tpo : POINTER TO ARRAY[1..LIST_LENGTH] OF BYTE;\n\tc: BYTE;\n\twrite: INT;\nEND_VAR\n\n\n(*\nversion 2.0\t21. mar. 2011\nprogrammer \thugo\ntested by\t\toscat\n\nLIST_NEXT retrieves the next element of a list, starting from element 1 after reset or first init.\nwhen the end of the lisat is reached a '' empty string is returned and NUL is set to true.\ndie liste liegt als string von elementen vor die mit den zeichen SEP am anfang markiert sind.\n\n*)\n\npt := ADR(LIST);\npo := ADR(LEL);\n\nIF rst THEN\n\tpos := 1;\nEND_IF;\n\nIF pt^[pos] = 0 OR pos = LIST_LENGTH THEN\n\tLEL := '';\n\tNUL := TRUE;\nELSE\n\tNUL := FALSE;\n\twrite := 1;\n\tFOR pos := pos + 1 TO LIST_LENGTH DO\n\t\tc := pt^[pos];\n\t\tIF c = 0 OR c = SEP THEN\n\t\t\tpo^[write] := 0;\n\t\t\tRETURN;\n\t\tELSE\n\t\t\tpo^[write] := pt^[pos];\n\t\t\twrite := write + 1;\n\t\tEND_IF;\n\tEND_FOR;\nEND_IF;\n\n\n\n\n(* revision histroy\nhm\t25. jun. 2008\trev 1.0\n\toriginal release\n\nhm\t19. jan. 2011\trev 1.1\n\tchanged string(255) to string(LIST_LENGTH)\t\n\nhm\t21. mar. 2011\trev 2.0\n\tall elements start with SEP\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "LIST_RETRIEVE.st", - "source": "FUNCTION LIST_RETRIEVE : STRING(LIST_LENGTH)\nVAR_INPUT\n\tSEP : BYTE;\n\tPOS : INT;\nEND_VAR\nVAR_IN_OUT\n\tLIST : STRING(LIST_LENGTH);\nEND_VAR\nVAR\n\ti :\tINT;\n\to : INT := 1;\n\tw : INT := 1;\n\tpt : POINTER TO ARRAY[1..LIST_LENGTH] OF BYTE;\n\tpo : POINTER TO ARRAY[1..LIST_LENGTH] OF BYTE;\n\tcnt: INT := 0;\n\tc: BYTE;\nEND_VAR\n\n\n(*\nversion 2.0\t\t21. mar. 2011\nprogrammer \thugo\ntested by\t\toscat\n\nLIST_RETRIEVE liefert das element an der stelle pos einer liste und löscht das element aus der liste.\ndie liste liegt als string von elementen vor die mit den zeichen SEP separiert sind.\n\n*)\n\n(* load pointers *)\npt := ADR(LIST);\npo := ADR(LIST_RETRIEVE);\n\nIF pos > 0 THEN\n\tFOR i := 1 TO LIST_LENGTH DO\n\t\tc := pt^[i];\n\t\tIF c = 0 THEN\n\t\t\tpo^[o] := 0;\n\t\t\tIF cnt < pos THEN pt^[w + 1] := 0; ELSE pt^[w] := 0; END_IF;\n\t\t\tRETURN;\n\t\tELSIF cnt = pos AND c <> SEP THEN\t\t\t\t(* we have found the element *)\n\t\t\tpo^[o] := pt^[i];\n\t\t\to := o + 1;\n\t\tELSIF cnt >= pos THEN\n\t\t\tpt^[w] := c;\n\t\t\tw := w + 1;\n\t\tELSE\n\t\t\tw := i;\n\t\tEND_IF;\n\t\tIF c = sep THEN cnt := cnt + 1; END_IF;\n\tEND_FOR;\nELSE\n\tLIST_RETRIEVE := '';\nEND_IF;\n\n\n(* revision histroy\nhm\t28. jun. 2008\trev 1.0\n\toriginal release\n\nhm\t19. jan. 2011\trev 1.1\n\tchanged string(255) to string(LIST_LENGTH)\n\nhm\t21. mar. 2011\trev 2.0\n\tall elements start with SEP\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "LIST_RETRIEVE_LAST.st", - "source": "FUNCTION LIST_RETRIEVE_LAST : STRING(LIST_LENGTH)\nVAR_INPUT\n\tSEP : BYTE;\nEND_VAR\nVAR_IN_OUT\n\tLIST : STRING(LIST_LENGTH);\nEND_VAR\nVAR\n\ti :\tINT;\n\tlast : INT := 1;\n\tpt : POINTER TO ARRAY[1..LIST_LENGTH] OF BYTE;\n\tc: BYTE;\nEND_VAR\n\n\n(*\nversion 2.0\t\t21. mar. 2011\nprogrammer \thugo\ntested by\t\toscat\n\nLIST_RETRIEVE_LAST liefert das letzte element einer liste und löscht das element aus der liste.\ndie liste liegt als string von elementen vor die mit den zeichen SEP beginnen.\n\n*)\n\n(* load pointers *)\npt := ADR(LIST);\n\n(* search position of last element *)\nFOR i := 1 TO LIST_LENGTH DO\n\tc := pt^[i];\n\tIF c = 0 THEN\n\t\tEXIT;\n\tELSIF C = SEP THEN\n\t\tlast := i;\n\tEND_IF;\nEND_FOR;\n(* return last element of list *)\nLIST_RETRIEVE_LAST := MID(LIST, LIST_LENGTH, last + 1);\n(* terminate list at i *)\npt^[last] := 0;\n\n\n\n(* revision histroy\nhm\t21. mar. 2011\trev 2.0\n\tnew module\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "LOWERCASE.st", - "source": "FUNCTION LOWERCASE : STRING(STRING_LENGTH)\nVAR_INPUT\n\tstr : STRING(STRING_LENGTH);\nEND_VAR\nVAR\n\tPT : POINTER TO BYTE;\n\tpos: INT;\n\tl: INT;\nEND_VAR\n\n(*\nversion 1.3\t29. mar. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nlowercase returns str while all letters A..Z and Ä.Ö,Ü are converted to lowercase.\n\n*)\n\nPT := ADR(LOWERCASE);\nlowercase := str;\nl := LEN(str);\nFOR pos := 1 TO l DO\n\tpt^ := TO_LOWER(pt^);\n\tPT := PT + 1;\nEND_FOR;\n\n(* revision histroy\nhm\t6. oct. 2006\trev 1.0\n\toriginal release\n\nhm\t4. feb. 2008\trev 1.1\n\timproved performance\n\tadded Ä.Ö,Ü\n\nhm\t6. mar. 2008\trev 1.2\n\tadded support for exteded Ascii\n\nhm\t29. mar. 2008\trev 1.3\n\tchanged STRING to STRING(STRING_LENGTH)\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "LTCH.st", - "source": "FUNCTION_BLOCK LTCH\nVAR_INPUT\n\tD : BOOL;\n\tL : BOOL;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\nEND_VAR\n\n\n(*\nversion 1.2\t30. oct. 2008\nprogrammer \thugo\ntested by\toscat\n\nTransparent Latch with asynchronous reset\n\n\n*)\n\n(* as long as L is true, the latch is transparent and and change of D is transferred to Q *)\n(* of course only when there is no asynchronous reset *)\nIF rst THEN\t\t\t\t(* if asynchronous reset then Q=0 *)\n\tQ := FALSE;\nELSIF L THEN\t\t\t(* latch is transparent *)\n\tQ := D;\nEND_IF;\n\n\n(* revision history\nhm\t4. aug 2006\t\trev 1.0\n\toriginal version\n\nhm\t27. dec 2007\trev 1.1\n\tchanged code for better performance\n\nhm\t30. oct. 2008\trev 1.2\n\tdeleted unnecessary init with 0\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "LTCH_4.st", - "source": "FUNCTION_BLOCK LTCH_4\nVAR_INPUT\n\tD0 : BOOL;\n\tD1 : BOOL;\n\tD2 : BOOL;\n\tD3 : BOOL;\n\tL : BOOL;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tQ0 : BOOL;\n\tQ1 : BOOL;\n\tQ2 : BOOL;\n\tQ3 : BOOL;\nEND_VAR\n\n\n(*\nversion 1.3\t14. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nQuad Transparent Latch with asynchronous reset\n\n\n*)\n\n(* as long as L is true, the latch is transparent and and change of D is transferred to Q *)\n(* of course only when there is no asynchronous reset *)\nIF rst THEN\t\t\t(* if asynchronous reset then Q=0 *)\n\tQ0 := FALSE;\n\tQ1 := FALSE;\n\tQ2 := FALSE;\n\tQ3 := FALSE;\nELSIF L THEN\t\t\t(* latch is transparent *)\n\tQ0 := D0;\n\tQ1 := D1;\n\tQ2 := D2;\n\tQ3 := D3;\nEND_IF;\n\n(* revision history\nhm\t4. aug 2006\trev 1.0\n\toriginal version\n\nhm\t27. dec 2007\trev 1.1\n\tchanged code for better performance\n\nhm\t30. oct. 2008\trev 1.2\n\tdeleted unnecessary init with 0\n\nhm\t14. mar. 2009\trev 1.3\n\tremoved double assignments\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "LTIME_TO_UTC.st", - "source": "FUNCTION LTIME_TO_UTC : DT\nVAR_INPUT\n\tLTIME : DT;\n\tDST : BOOL;\n\tTIME_ZONE_OFFSET : INT;\nEND_VAR\n\n\n(*\nversion 1.7\t13. nov. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nLTIME_TO_UTC calculates UTC (World Time) from a local time LTIME. utc is calculated \nby subtracting Time_Zone_Offset from ltime and if dst it true subtracting an additional hour from ltime.\n\n*)\n\nLTIME_TO_UTC := UDINT_TO_DT(DT_TO_UDINT(LTIME) - INT_TO_UDINT(TIME_ZONE_OFFSET) * 60);\nIF DST THEN LTIME_TO_UTC := LTIME_TO_UTC - T#1h; END_IF;\n\n(* revision history\nhm 5.7.2007\t\trev 1.0\t\t\n\toriginal version\n\nhm 5.11.2007\t\trev 1.1\n\treplaced literal constant with variable because of error in möller ecp4 compiler\n\nhm\t12.nov 2007\trev 1.2\n\tchanged Type of time_zone_offset from time to int to allow for time zones with negative offset\n\nhm\t8. dec 2007\trev 1.3\n\tcorrected a problem with time_zone_offset\n\nhm\t14. oct. 2008\trev 1.4\n\tchanged time_zone_offset from int to real to allow for half hour offset\n\nhm\t20. oct. 2006\trev 1.5\n\tchanged time_zone_offset from Real to INT, now in Minutes\n\nhm\t27. feb. 2009\trev 1.6\n\tadded type conversions to avoid warnings under codesys 3.0\n\nks\t13. nov. 2009\trev 1.7\n\tcorrected error in formula\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "MANUAL.st", - "source": "FUNCTION MANUAL : BOOL\nVAR_INPUT\n\tIN : BOOL;\n\tON : BOOL;\n\tOFF : BOOL;\nEND_VAR\n\n\n(*\nversion 1.0\t21. nov. 2008\nprogrammer \thugo\ntested by\toscat\n\nMANUAL is a manual override for digital signals.\nwhen on and off = FALSE, the output follows IN.\nON = TRUE forces the output high, and OFF = TRUE forces the output low.\n\n\n*)\n\nMANUAL := NOT OFF AND (IN OR ON);\n\n\n\n(* revision history\nhm\t21. nov 2008\trev 1.0\n\toriginal version\n\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "MANUAL_1.st", - "source": "FUNCTION_BLOCK MANUAL_1\nVAR_INPUT\n\tIN : BOOL;\n\tMAN : BOOL;\n\tM_I : BOOL;\n\tSET : BOOL;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\n\tSTATUS : BYTE;\nEND_VAR\nVAR\n\tS_edge : BOOL;\n\tr_edge : BOOL;\n\tedge: BOOL;\nEND_VAR\n\n(*\nversion 1.2\t14. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nMANUAL_1 is a manual override for digital signals.\nWhen MAN = FALSE, the output follows IN and when MAN = TRUE the Output follows M_I.\n\n\n*)\n\nIF NOT man THEN\n\tQ := IN;\n\tSTATUS := 100;\n\tedge := FALSE;\nELSIF NOT s_edge AND set THEN\n\tQ := TRUE;\n\tedge := TRUE;\n\tstatus := 101;\nELSIF NOT r_edge AND rst THEN\n\tQ := FALSE;\n\tedge := TRUE;\n\tstatus := 102;\nELSIF NOT edge THEN\n\tQ := M_I;\n\tstatus := 103;\nEND_IF;\n\n(* remember levels of manual signals *)\ns_edge := SET;\nr_edge := RST;\n\n\n\n(* revision history\nhm\t17. jun 2008\trev 1.0\n\toriginal version\n\nhm\t17. oct 2008\trev 1.1\n\tdeleted unnecessary variable m_edge\n\nhm\t14. mar. 2009\trev 1.2\n\treplaced double assignments\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "MANUAL_2.st", - "source": "FUNCTION_BLOCK MANUAL_2\nVAR_INPUT\n\tIN : BOOL;\n\tENA : BOOL;\n\tON : BOOL;\n\tOFF : BOOL;\n\tMAN : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\n\tSTATUS : BYTE;\nEND_VAR\n\n\n(*\nversion 1.0\t22. sep. 2008\nprogrammer \thugo\ntested by\toscat\n\nMANUAL_2 is a manual override for boolean signals.\nit has static force high and low as well as a manual input.\n\n*)\n\nIF ena THEN\n\tIF NOT ON AND NOT OFF THEN\n\t\tQ := IN;\n\t\tSTATUS := 100;\n\tELSIF on AND NOT off THEN\n\t\tQ := TRUE;\n\t\tSTATUS := 101;\n\tELSIF NOT on AND off THEN\n\t\tq := FALSE;\n\t\tSTATUS := 102;\n\tELSE\n\t\tQ := MAN;\n\t\tSTATUS := 103;\n\tEND_IF;\nELSE\n\tQ := FALSE;\n\tSTATUS := 104;\nEND_IF;\n\n\n\n(* revision history\nhm\t22. sep. 2008\t\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "MANUAL_4.st", - "source": "FUNCTION_BLOCK MANUAL_4\nVAR_INPUT\n\tI0, I1, I2, I3 : BOOL;\n\tMAN : BOOL;\n\tSTP : BOOL;\n\tM0, M1, M2, M3 : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tQ0, Q1, Q2, Q3 : BOOL;\n\tSTATUS : BYTE;\nEND_VAR\nVAR\n\tedge: BOOL;\n\tpos : INT;\n\ttog: BOOL;\nEND_VAR\n\n\n(*\nversion 1.0\t17. jun 2008\nprogrammer \thugo\ntested by\toscat\n\nMANUAL_4 is a manual override for digital signals.\nWhen MAN = FALSE, the output follows IN and when MAN = TRUE the Output follows M_I.\n\n\n*)\n\nIF man THEN\n\tIF NOT TOG THEN\n\t\tQ0 := M0;\n\t\tQ1 := M1;\n\t\tQ2 := M2;\n\t\tQ3 := M3;\n\t\tSTATUS := 101;\n\tEND_IF;\n\tIF STP AND NOT edge THEN\n\t\ttog := TRUE;\n\t\tCASE pos OF\n\t\t\t0:\tQ0 := TRUE;\n\t\t\t\tQ1 := FALSE;\n\t\t\t\tQ2 := FALSE;\n\t\t\t\tQ3 := FALSE;\n\t\t\t\tSTATUS := 110;\n\t\t\t1:\tQ0 := FALSE;\n\t\t\t\tQ1 := TRUE;\n\t\t\t\tQ2 := FALSE;\n\t\t\t\tQ3 := FALSE;\n\t\t\t\tSTATUS := 111;\n\t\t\t2:\tQ0 := FALSE;\n\t\t\t\tQ1 := FALSE;\n\t\t\t\tQ2 := TRUE;\n\t\t\t\tQ3 := FALSE;\n\t\t\t\tSTATUS := 112;\n\t\t\t3:\tQ0 := FALSE;\n\t\t\t\tQ1 := FALSE;\n\t\t\t\tQ2 := FALSE;\n\t\t\t\tQ3 := TRUE;\n\t\t\t\tSTATUS := 113;\n\t\tEND_CASE;\n\t\tpos := INC(pos,1,3);\n\tEND_IF;\nELSE\n\tQ0 := I0;\n\tQ1 := I1;\n\tQ2 := I2;\n\tQ3 := I3;\n\tSTATUS := 100;\n\ttog := FALSE;\n\tpos := 0;\nEND_IF;\n\n(* remember status of stp *)\nedge := STP;\n\n\n\n(* revision history\nhm\t17. jun 2008\t\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "MATRIX.st", - "source": "FUNCTION_BLOCK MATRIX\nVAR_INPUT\n\tx1, x2, x3, x4, X5 : BOOL;\nEND_VAR\nVAR_INPUT CONSTANT\n\tRelease : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tcode : BYTE;\n\tTP : BOOL;\n\ty1: BOOL := TRUE;\n\ty2, y3, y4 : BOOL;\nEND_VAR\nVAR\n\tline : BYTE;\n\tX : ARRAY[0..3] OF BYTE; (* scan line inputs *)\n\tL : ARRAY[0..3] OF BYTE; (* scan line status *)\n\ti: INT;\n\ttemp: BYTE;\nEND_VAR\n\n(*\nversion 1.3\t26 oct. 2008\nprogrammer \thugo\ntested by\toscat\n\nMATRIX is a matrix keyboard encoder for 4 rows and up to 5 columns.\nmatrix can send a code while a key is pressed and it sends another code while a key is released when the setup variable 'release' is set to true.\nthe setup variable release is false the code is only sent when the key is pressed.\nthe output byte holds the 5 columns in the lowest bits 0..2 and the row number in bits 4..6, while bit 7 is true for a key pressed and false for a key released.\n\n*)\n\nTP := FALSE;\nCODE := 0;\n(* read scan lines *)\nX[line].0 := X1;\nX[line].1 := X2;\nX[line].2 := X3;\nX[line].3 := X4;\nX[line].4 := X5;\n\n(* compare for change *)\nFOR i := 0 TO 3 DO\n\tIF X[i] <> L[i] THEN\n\t\t(* scan line information has changed code need to be found and generated *)\n\t\ttemp := x[i] XOR L[i];\n\t\tIF temp.0 THEN\n\t\t\tCODE := 1;\n\t\t\tcode.7 := X[i].0;\n\t\t\tL[i].0 := X[i].0;\n\t\tELSIF temp.1 THEN\n\t\t\tcode := 2;\n\t\t\tcode.7 := X[i].1;\n\t\t\tL[i].1 := X[i].1;\n\t\tELSIF temp.2 THEN\n\t\t\tcode := 3;\n\t\t\tcode.7 := X[i].2;\n\t\t\tL[i].2 := X[i].2;\n\t\tELSIF temp.3 THEN\n\t\t\tCODE := 4;\n\t\t\tCODE.7 := X[i].3;\n\t\t\tL[i].3 := X[i].3;\n\t\tELSIF temp.4 THEN\n\t\t\tCODE := 5;\n\t\t\tCODE.7 := X[i].4;\n\t\t\tL[i].4 := X[i].4;\n\t\tEND_IF;\n\t\tTP := TRUE;\n\t\tCODE.4 := Line.0;\n\t\tCODE.5 := Line.1;\n\t\tCODE.6 := Line.2;\n\n\t\t(* check if release codes need to be killed *)\n\t\tIF NOT release AND CODE < 127 THEN\n\t\t\tCODE := 0;\n\t\t\tTP := FALSE;\n\t\tEND_IF;\n\t\tEXIT;\n\tEND_IF;\nEND_FOR;\n\n(* increment scan line every cycle *)\nline := (line + 1) AND 2#0000_0011;\ntemp := SHL(BYTE#1,line);\nY1 := temp.0;\nY2 := temp.1;\nY3 := temp.2;\nY4 := temp.3;\n\n\n\n\n(* revision history\nhm\t\t10.6.2007\trev 1.0\t\t\n\toriginal version \n\n\nhm\t\t11.9.2007\trev 1.1\t\t\n\tdeleted unused variables k and old_code\n\nhm\t\t23.12.2007\trev 1.2\n\tadded exit statement in for loop instead of i:=5\n\nhm\t\t26. oct. 2008\trev 1.3\n\tcode optimized\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "MAX3.st", - "source": "FUNCTION MAX3 : REAL\nVAR_INPUT\n\tin1 : REAL;\n\tin2 : REAL;\n\tin3 : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t18. mar. 2011\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function returns the highest of 3 real values\n\n*)\n\nMAX3 := MAX(MAX(IN1,IN2),IN3);\n\n\n(* revision history\nhm\t1.1.2007\trev 1.0\n\toriginal release\n\nhm\t18. mar. 2011\trev 1.1\n\timprove performance\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "MESSAGE_4R.st", - "source": "FUNCTION_BLOCK MESSAGE_4R\nVAR_INPUT\n\tM0 : STRING(STRING_LENGTH);\n\tM1 : STRING(STRING_LENGTH);\n\tM2 : STRING(STRING_LENGTH);\n\tM3 : STRING(STRING_LENGTH);\n\tMM : INT := 3;\n\tENQ : BOOL := TRUE;\n\tCLK : BOOL := TRUE;\n\tT1 : TIME := T#3s;\nEND_VAR\nVAR_OUTPUT\n\tMX : STRING(STRING_LENGTH);\n\tMN : INT;\n\tTR : BOOL;\nEND_VAR\nVAR\n\ttimer : TON;\n\tedge: BOOL;\nEND_VAR\n\n(*\nversion 1.1\t27. oct. 2008\nprogrammer \thugo\ntested by\ttobias\n\nthis function generates a rotation meassage with up to 4 strings.\non each rising edge of EN the next message in line will be displayed.\nwhen EN stays high longer then one cycle, the next message will be displayed automatically after the time T1 is elapsed.\nthe output MX is the generated message and CX is a counter 0..3 signaling the current message displayed.\nthe displayed messages are 0 .. MM.\n\n*)\n\n(* check for rising edge on EN *)\nTR := FALSE;\nIF ENQ THEN\n\tIF (NOT edge AND clk) OR timer.q THEN\n\t\t\tMN := INC1(MN, MM);\n\t\t\tTR := TRUE;\n\t\t\ttimer(in := FALSE);\n\t\t\tCASE MN OF\n\t\t\t\t0 : MX := M0;\n\t\t\t\t1 : MX := M1;\n\t\t\t\t2 : MX := M2;\n\t\t\t\t3 : MX := M3;\n\t\t\tEND_CASE;\n\tEND_IF;\n\tedge := clk;\n\ttimer( in := CLK, pt := T1);\nELSE\n\tMX := '';\n\tMN := 0;\nEND_IF;\n\n\n\n\n(* revision history\nhm\t8. oct. 2008\trev 1.0\n\toriginal version\n\nhm\t27. oct. 2008\trev 1.1\n\tchanged _INC to INC1\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "MESSAGE_8.st", - "source": "FUNCTION_BLOCK MESSAGE_8\nVAR_INPUT\n\tIN1 : BOOL;\n\tIN2 : BOOL;\n\tIN3 : BOOL;\n\tIN4 : BOOL;\n\tIN5 : BOOL;\n\tIN6 : BOOL;\n\tIN7 : BOOL;\n\tIN8 : BOOL;\nEND_VAR\nVAR_INPUT CONSTANT\n\tS1 : STRING(STRING_LENGTH);\n\tS2 : STRING(STRING_LENGTH);\n\tS3 : STRING(STRING_LENGTH);\n\tS4 : STRING(STRING_LENGTH);\n\tS5 : STRING(STRING_LENGTH);\n\tS6 : STRING(STRING_LENGTH);\n\tS7 : STRING(STRING_LENGTH);\n\tS8 : STRING(STRING_LENGTH);\nEND_VAR\nVAR_OUTPUT\n\tM : STRING(STRING_LENGTH);\nEND_VAR\n\n\n(*\nversion 1.1\t29. mar. 2008\nprogrammer \thugo\ntested by\ttobias\n\nthis function generates one out of 4 messages specified by S1 .. S8.\nthe selected message will be presented at the output M.\nIn1 has higher priority then In2 which has higher priority then IN3 and in8 has the lowest priority.\n*)\n\n(* check if an alarm is present if yes set the output M otherwise clear M *)\nIF in1 THEN\n\tM := S1;\nELSIF in2 THEN\n\tM := S2;\nELSIF in3 THEN\n\tM := S3;\nELSIF in4 THEN\n\tM := S4;\nELSIF in5 THEN\n\tM := S5;\nELSIF in6 THEN\n\tM := S6;\nELSIF in7 THEN\n\tM := S7;\nELSIF in8 THEN\n\tM := S8;\nELSE\n\tM := '';\nEND_IF;\n\n(* revision history\nhm\t26.12.2007\t\trev 1.0\n\toriginal version\n\nhm\t29. mar. 2008\trev 1.1\n\tchanged STRING to STRING(STRING_LENGTH)\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "METER.st", - "source": "FUNCTION_BLOCK METER\nVAR_INPUT\n\tM1, M2 : REAL;\n\tI1, I2 : BOOL;\n\tD : REAL := 1.0;\n\tRST : BOOL;\nEND_VAR\nVAR_IN_OUT\n\tMX : REAL;\nEND_VAR\nVAR\n\tMR : REAL2;\n\tMX1, MX2 : REAL; (* current consumption value on M1 and M2 *)\n\ttx: DWORD;\n\tlast: DWORD;\n\ttc: REAL;\n\tinit: BOOL;\nEND_VAR\n\n(*\n\tversion 1.4\t8. mar. 2009\n\tprogrammer \toscat\n\ttested BY\toscat\n\nMETER measures usage of power or similar values the output MX is the sum of the inputs over time.\nMX := sum over time of (I1 * P1 + I2 * P2)/D.\na simple example is the consumption counter for a 2 stage oil burner where stage 1 is 10KW and stage 2 is 20KW.\nI1 and I2 decide which value is accounted for, I1 = True only counts P1, I2 is True counts P2 \nand I1 and I2 is true counts P1 and P2.\nthe meter can be used for all kind of consumption meters. P1 and P2 can change on the fly.\n\n*)\n\n(* measure the last cycle time and make sure we onle execute once every millisecond *)\ntx := T_PLC_MS();\nIF NOT init THEN\n\tinit := TRUE;\n\tlast := tx;\n\tmr.RX := mx;\n\tmr.R1 := 0.0;\nELSIF tx = last THEN\n\tRETURN;\nELSE\n\ttc := DWORD_TO_REAL(tx - last) * 0.001;\nEND_IF;\nlast := tx;\n\n(* reset *)\nIF rst THEN\n\tmr.R1 := 0.0;\n\tmr.RX := 0.0;\nELSE\n\t(* current consumption measurement *)\n\tIF I1 THEN MX1 := M1; ELSE MX1 := 0.0; END_IF;\n\tIF I2 THEN MX2 := M2; ELSE MX2 := 0.0; END_IF;\n\t(* add up the current values in a double real *)\n\tMR := R2_ADD(MR,(SEL(I1,0.0,mx1) + SEL(I2, 0.0, mx2)) / D * TC);\n\t(* set the current output value *)\n\tMX := mr.RX;\nEND_IF;\n\n\n\n\n(* revision history\n\nhm\t16. sep.2007\t\trev 1.0\n\toriginal version\n\nhm\t7. feb 2008\t\trev 1.1\n\tuse new version of ft_int to avoid a counting stop at high values\n\tdeleted unnecessary limits\n\nhm\t24. mar. 2008\trev 1.2\n\tuse data_type real2 to extend accuracy to 15 digits total\n\tdo not use ft_int which adds unnecessary overhead\n\nhm\t8. feb. 2009\trev 1.3\n\tchanged mx to be I/O\n\tmake sure calculation works for cycle times < 1 ms\n\nhm\t8. mar. 2009\trev 1.4\n\tlast was not updated\n\tcode improvements\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "METER_STAT.st", - "source": "FUNCTION_BLOCK METER_STAT\nVAR_INPUT\n\tIN : REAL;\n\tDI : DATE;\n\tRST : BOOL;\nEND_VAR\nVAR_IN_OUT\n\tLast_Day : REAL;\n\tCurrent_Day : REAL;\n\tLast_Week : REAL;\n\tCurrent_Week : REAL;\n\tLast_Month : REAL;\n\tCurrent_Month : REAL;\n\tLast_Year : REAL;\n\tCurrent_Year : REAL;\nEND_VAR\nVAR RETAIN\n\tYear_Start : REAL;\n\tMonth_Start : REAL;\n\tWeek_Start : REAL;\n\tDay_Start : REAL;\n\tlast_run: DATE;\nEND_VAR\n\n(*\n\tversion 1.3\t18. jul. 2009\n\tprogrammer \toscat\n\ttested BY\t\toscat\n\nMETER_STAT runs statistics of a metered value, it calculates the current week, day, month and year consumption and stores the corresponding last day, week, month and year value.\n\n*)\n\nIF rst THEN\n\tLast_Day := 0.0;\n\tCurrent_Day := 0.0;\n\tDay_start := IN;\n\tLast_week := 0.0;\n\tCurrent_week := 0.0;\n\tWeek_start := in;\n\tLast_month := 0.0;\n\tCurrent_month := 0.0;\n\tmonth_start := in;\n\tlast_year := 0.0;\n\tcurrent_year := 0.0;\n\tyear_start := in;\nELSE\n\tCurrent_Day := IN - Day_Start;\n\tCurrent_Week := In - Week_Start;\n\tCurrent_Month := IN - Month_Start;\n\tCurrent_Year := IN - Year_Start;\nEND_IF;\n\nIF YEAR_OF_DATE(DI) > YEAR_OF_DATE(last_run) THEN\n\t(* a new year has started *)\n\tlast_year := current_year;\n\tcurrent_year := 0.0;\n\tyear_start := in;\n\tlast_month := current_month;\n\tcurrent_month := 0.0;\n\tmonth_start := in;\n\tlast_day := current_day;\n\tcurrent_day := 0.0;\n\tday_start := in;\nELSIF MONTH_OF_DATE(DI) > MONTH_OF_DATE(last_run) THEN\n\t(* a new month has started, january is alrerady done by year change *)\n\tlast_month := current_month;\n\tcurrent_month := 0.0;\n\tmonth_start := in;\n\tlast_day := current_day;\n\tcurrent_day := 0.0;\n\tday_start := in;\nELSIF DAY_OF_YEAR(di) > DAY_OF_YEAR(last_run) THEN\n\t(* day has chaged, first day of year and first day of month has already been taken care of *)\n\tlast_day := current_day;\n\tcurrent_day := 0.0;\n\tday_start := in;\nEND_IF;\nIF DAY_OF_WEEK(DI) < DAY_OF_WEEK(last_run) THEN\n\t(* a new week has started *)\n\tlast_week := current_week;\n\tcurrent_week := 0.0;\n\tweek_start := in;\nEND_IF;\nlast_run := di;\n\n(* revision history\nhm\t16. sep. 2007\trev 1.0\n\toriginal version\n\nhm\t7. oct. 2008\trev 1.1\n\tchanged function year_to_year_of_date\n\tchanged function month to month_of_date\n\tchanged function weekday to day_of_week\n\nhm\t11. mar. 2009\trev 1.2\n\tchanged real constants to use dot syntax\n\nhm\t18. jul. 2009\trev 1.3\n\tchanges all outputs to be I/O\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "MID3.st", - "source": "FUNCTION MID3 : REAL\nVAR_INPUT\n\tIN1 : REAL;\n\tIN2 : REAL;\n\tIN3 : REAL;\nEND_VAR\n\n\n(*\nversion 1.2\t18. mar. 2011\nprogrammer \thugo\ntested by\t\ttobias\n\nreturns the mid value of 3 real inputs.\n\n*)\n\nIF IN1 > IN2 THEN MID3 := IN1; IN1 := IN2; IN2 := MID3; END_IF;\nIF IN2 > IN3 THEN IN2 := IN3; END_IF;\nMID3 := SEL(IN1 > IN2, IN2, IN1);\n\n\n(*\nhm\t1.1.2007\trev 1.1\n\trewrote the function for better performance\n\nhm\t18. mar. 2011\trev 1.2\n\timprove performance\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "MIN3.st", - "source": "FUNCTION MIN3 : REAL\nVAR_INPUT\n\tin1 : REAL;\n\tin2 : REAL;\n\tin3 : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t18. mar. 2011\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function returns the lowest of 3 real values\n\n*)\n\nMIN3 := MIN(MIN(IN1,IN2),IN3);\n\n\n(* revision history\nhm\t1.1.2007\trev 1.0\n\toriginal release\n\nhm\t18. mar. 2011\trev 1.1\n\timprove performance\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "MINUTE.st", - "source": "FUNCTION MINUTE : INT\nVAR_INPUT\n\titod : TOD;\nEND_VAR\n\n\n(*\nversion 1.1\t2 oct 2006\nprogrammer \thugo\ntested by\ttobias\n\nextracts the minutes out of TOD truncating the seconds \n\n*)\n\nMINUTE := DWORD_TO_INT(TOD_TO_DWORD(itod) / 60000 - TOD_TO_DWORD(itod) / 3600000 * 60);\n\n\n(* change history\n\n2.10.2006 changes name of input to itod\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "MINUTE_OF_DT.st", - "source": "FUNCTION MINUTE_OF_DT : INT\nVAR_INPUT\n\tXDT : DT;\nEND_VAR\n\n\n(*\n\tversion 1.0\t6. jun. 2008\n\tprogrammer \toscat\n\ttested BY\toscat\n\nMINUTE_OF_DT returns the current minute (minute of the hour) of a DT variable\n\n*)\n\nMINUTE_OF_DT := DWORD_TO_INT(DT_TO_DWORD(XDT) MOD 3600) / 60;\n\n\n(* revision history\nhm\t\t6.9.2008\trev 1.0\n\toriginal version\n\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "MINUTE_TO_TIME.st", - "source": "FUNCTION MINUTE_TO_TIME : TIME\nVAR_INPUT\n\tIN : REAL;\nEND_VAR\n\n\n(*\nversion 1.2\t24. feb. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nconverts an amount of minutes in real to time\n\n*)\n\nMINUTE_TO_TIME := DWORD_TO_TIME(REAL_TO_DWORD(IN * 60000.0));\n\n\n(* revision history\nhm\t4. aug 2006\trev 1.0\n\toriginal version\n\nhm\t14. mar 2008\trev 1.1\n\trounded the input after the last digit\n\nhm\t24. feb. 2009\trev 1.2\n\tchanged input to IN\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "MIRROR.st", - "source": "FUNCTION MIRROR : STRING(STRING_LENGTH)\nVAR_INPUT\n\tstr : STRING(STRING_LENGTH);\nEND_VAR\nVAR\n\tpi : POINTER TO ARRAY[1..255] OF BYTE;\n\tpo : POINTER TO BYTE;\n\tlx: INT;\n\ti: INT;\nEND_VAR\n\n(*\nversion 1.1\t29. mar. 2008\nprogrammer \thugo\ntested by\ttobias\n\nthis function reverses an input string.\n\n*)\n\npi := ADR(str);\npo := ADR(mirror);\nlx := LEN(str);\nFOR i := lx TO 1 BY - 1 DO\n\tpo^ := pi^[i];\n\tpo := po + 1;\nEND_FOR;\n(* close output string *)\npo^:= 0;\n\n\n(* revision histroy\nhm\t4. feb. 2008\trev 1.0\n\toriginal release\n\nhm\t29. mar. 2008\trev 1.1\n\tchanged STRING to STRING(STRING_LENGTH)\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "MIX.st", - "source": "FUNCTION MIX : REAL\nVAR_INPUT\n\tA, B : REAL;\n\tM : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nMIX is an analog Mixer. The Output is (1-M)*A + M*B.\n\n*)\n\nMIX := (1.0 - M) * A + M * B;\n\n(* revision history\nhm\t19. Nov 2007\trev 1.0\n\toriginal version\n\nhm\t10. mar 2009\trev 1.1\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "MODR.st", - "source": "FUNCTION MODR : REAL\nVAR_INPUT\n\tIN : REAL;\n\tDIVI : REAL;\nEND_VAR\n\n\n(*\nversion 1.5\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis is a modulo funtion for real numbers\nmodr(5.5,2.5) = 0.5\n\n*)\n\nIF divi = 0.0 THEN\n\tMODR := 0.0;\nELSE\n\tMODR := in - DINT_TO_REAL(FLOOR2(in / divi)) * divi;\nEND_IF;\n\n(* revision history\n\nhm\t4. aug.2006\t\trev 1.0\n\nhm\t28. jan.2007\trev 1.1\n\tmodr(x,0) will deliver the result 0\n\nhm\t21. mar 2008\trev 1.2\n\tuse D_trunc for compatibility reasons\n\nhm\t4. apr. 2008\trev 1.3\n\tadded type conversion to avoid warnings under codesys 3.0\n\nhm\t31. oct. 2008\trev 1.4\n\tchanged algorithm to the more common version using floor instead of TRUNC\n\nhm\t10. mar. 2009\trev 1.5\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "MONTH_BEGIN.st", - "source": "FUNCTION MONTH_BEGIN : DATE\nVAR_INPUT\n\tidate : DATE;\nEND_VAR\n\n\n(*\nversion 1.0\t15. jun. 2008\nprogrammer \thugo\ntested by\toscat\n\nreturns the date for the first day of the current month in the current year.\n\n*)\n\nMONTH_BEGIN := DWORD_TO_DATE(DATE_TO_DWORD(idate) - INT_TO_DWORD(DAY_OF_MONTH(idate) - 1) * 86400);\n\n(* revision history\nhm\t15. jun. 2008\trev 1.0\n\toriginal version\t\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "MONTH_END.st", - "source": "FUNCTION MONTH_END : DATE\nVAR_INPUT\n\tIDATE : DATE;\nEND_VAR\n\n\n(*\nversion 1.1\t7. oct. 2008\nprogrammer \thugo\ntested by\toscat\n\nreturns the date for the last day of the current month in the current year.\n\n*)\n\nMONTH_END := DWORD_TO_DATE(DATE_TO_DWORD(SET_DATE(YEAR_OF_DATE(idate),MONTH_OF_DATE(idate)+1,1)) - 86400);\n\n\n\n(* revision history\nhm\t15. jun. 2008\trev 1.0\n\toriginal version\t\n\nhm\t7. oct. 2008\trev 1.1\n\tchanged function year to year_of_date\n\tchanged function month to month_of_date\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "MONTH_OF_DATE.st", - "source": "FUNCTION MONTH_OF_DATE : INT\nVAR_INPUT\n\tIDATE : DATE;\nEND_VAR\n\n\n(*\nversion 1.3\t27. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nreturns the current month of the year.\n\n*)\n\nMONTH_OF_DATE := DAY_OF_YEAR(idate);\nIF MONTH_OF_DATE < 32 THEN\n\tMONTH_OF_DATE := 1;\nELSIF LEAP_OF_DATE(IDATE) THEN\n\tMONTH_OF_DATE := (MONTH_OF_DATE * 53 + 1668) / 1623;\nELSE\n\tMONTH_OF_DATE := (MONTH_OF_DATE * 53 + 1700) / 1620;\nEND_IF;\n\n\n(* code for rev 1.2\nMONTH_OF_DATE := DAY_OF_YEAR(IDATE);\nIF LEAP_OF_DATE(IDATE) THEN\n\tCASE MONTH_OF_DATE OF\n\t\t1..31 \t:\tMONTH_OF_DATE := 1;\n\t\t32..60\t:\tMONTH_OF_DATE := 2;\n\t\t61..91\t:\tMONTH_OF_DATE := 3;\n\t\t92..121 :\tMONTH_OF_DATE := 4;\n\t\t122..152:\tMONTH_OF_DATE := 5;\n\t\t153..182:\tMONTH_OF_DATE := 6;\n\t\t183..213:\tMONTH_OF_DATE := 7;\n\t\t214..244:\tMONTH_OF_DATE := 8;\n\t\t245..274:\tMONTH_OF_DATE := 9;\n\t\t275..305:\tMONTH_OF_DATE := 10;\n\t\t306..335:\tMONTH_OF_DATE := 11;\n\t\t336..366:\tMONTH_OF_DATE := 12;\n\tEND_CASE;\nELSE\n\tCASE MONTH_OF_DATE OF\n\t\t1..31 \t:\tMONTH_OF_DATE := 1;\n\t\t32..59\t:\tMONTH_OF_DATE := 2;\n\t\t60..90\t:\tMONTH_OF_DATE := 3;\n\t\t91..120 :\tMONTH_OF_DATE := 4;\n\t\t121..151:\tMONTH_OF_DATE := 5;\n\t\t152..181:\tMONTH_OF_DATE := 6;\n\t\t182..212:\tMONTH_OF_DATE := 7;\n\t\t213..243:\tMONTH_OF_DATE := 8;\n\t\t244..273:\tMONTH_OF_DATE := 9;\n\t\t274..304:\tMONTH_OF_DATE := 10;\n\t\t305..334:\tMONTH_OF_DATE := 11;\n\t\t335..365:\tMONTH_OF_DATE := 12;\n\tEND_CASE;\nEND_IF;\n*)\n\n\n(* revision history\nhm\t1. aug 2006\trev 1.0\n\toriginal version\t\n\nhm\t1. okt 2007\trev 1.1\n\treplaced old code (string conversion) with mathematics\n\tthe execution time is now multiple times faster.\n\nhm\t7. oct. 2008\trev 1.2\n\tchanged name of function from month to MONTH_OF_DATE\n\nhm\t27. mar. 2009\trev 1.3\n\tnew improved code\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "MONTH_TO_STRING.st", - "source": "FUNCTION MONTH_TO_STRING : STRING(10)\nVAR_INPUT\n\tMTH : INT;\n\tLANG : INT;\n\tLX : INT;\nEND_VAR\nVAR\n\tly : INT;\nEND_VAR\n\n(*\nversion 1.2\t16. jul. 2024\nprogrammer \thugo\ntested by\toscat\n\nMONTH_TO_STRING converts an Integer 1..12 into a String with the Names of the corresponding Month.\nthe decoding is according to the language setup in global vars\n\n*)\n\nIF LANG <= 0 THEN Ly := LANGUAGE.DEFAULT; ELSE ly := MIN(LANG, language.LMAX); END_IF;\nIF MTH < 1 OR MTH > 12 THEN\n\tRETURN;\nELSIF LX = 0 THEN\n\tMONTH_TO_STRING := language.MONTHS[ly, MTH];\nELSIF Lx = 3 THEN\n\tMONTH_TO_STRING := language.MONTHS3[ly, MTH];\nEND_IF;\n\n\n(* revisison history\n\nhm\t21. sep. 2008\trev 1.0\n\toriginal version\n\nhm\t19. oct. 2008\trev 1.1\n\tchanged language setup constants\n\nhm 16. jul 2024 rev 1.2\n addaed boundary check to respect array limits\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "MS_TO_BFT.st", - "source": "FUNCTION MS_TO_BFT : INT\nVAR_INPUT\n\tMS : REAL;\nEND_VAR\n\n\n(*\nversion 1.0\t12. jun 2008\nprogrammer \thugo\ntested by\toscdat\n\nthis function converts wind speed from M/s to beaufort\n*)\n\nMS_TO_BFT := REAL_TO_INT(EXPT(MS * 1.196172, 0.666667));\n\n\n(* revision history\nhm\t12. 6. 2008\t\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "MS_TO_KMH.st", - "source": "FUNCTION MS_TO_KMH : REAL\nVAR_INPUT\n\tms : REAL;\nEND_VAR\n\n\n(*\nversion 1.0\t4 Feb 2007\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function converts velocities from Meters / Second to Kilometers / hour.\n\n*)\n\nMS_TO_KMH := ms * 3.6;\n\nEND_FUNCTION\n" - }, - { - "fileName": "MULTIME.st", - "source": "FUNCTION MULTIME : TIME\nVAR_INPUT\n\tt : TIME;\n\tM : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t14 mar 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nmultiplies a time by a real number and returns a time\n*)\n\nMULTIME := DWORD_TO_TIME(REAL_TO_DWORD(DWORD_TO_REAL(TIME_TO_DWORD(t))*M));\n\n(* revision history\nhm\t\t2. oct 2006\trev 1.0\n\toriginal version\n\nhm\t\t14. mar 2008\trev 1.1\n\trounded the result after the last digit\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "MULTI_IN.st", - "source": "FUNCTION MULTI_IN : REAL\nVAR_INPUT\n\tin_1 : REAL;\n\tin_2 : REAL;\n\tin_3 : REAL;\n\tdefault : REAL;\n\tin_min : REAL;\n\tin_max : REAL;\n\tmode : BYTE;\nEND_VAR\nVAR\n\tcount: INT;\n\tF1: BOOL;\n\tF2: BOOL;\n\tF3: BOOL;\nEND_VAR\n\n(*\n\nversion 1.4\t18. jul. 2009\nprogrammer \toscat\ntested by\t\toscat\n\nmulti_in is a signal conditioning function which can be configured in 8 different ways.\nit is used to read multiple sensors for the same value and protect the user from broken sensors or invalid data from sensors.\n\nmulti_in can be configured in different ways:\n\tmode = 0 means the the avg of the 3 inputs is used, this mode is the default mode.\n\tmode = 1 means in_1 is used.\n\tmode = 2 means in_2 is used.\n\tmode = 3 means in_3 is used.\n\tmode = 4 means default is used.\n\tmode = 5 means the lowest of the 3 external temperatures is used.\n\tmode = 6 means the higest externnal temperature is used.\n\tmode = 7 means the midlle input is used, if there are only two working, the lowest input is used.\n\tmode > 7 ,eans output is 0 at all times.\n\tin any config mode, an input higher then in_max or lower then in_min is ignored to prevent values from broken sensors or wires.\n\tif all inputs are higher then in_max or lower then in_min, a default value (default) is used.\n*)\n\nF1 := in_1 > in_min AND in_1 < in_max;\nF2 := in_2 > in_min AND in_2 < in_max;\nF3 := in_3 > in_min AND in_3 < in_max;\n\nCASE mode OF\n0:\tcount := 0;\n\tIF F1 THEN\n\t\tcount := count + 1;\n\t\tMULTI_IN := in_1;\n\tELSE\n\t\tMULTI_IN := 0.0;\n\tEND_IF;\n\tIF F2 THEN\n\t\tcount := count + 1;\n\t\tMULTI_IN := MULTI_IN + in_2;\n\tEND_IF;\n\tIF F3 THEN\n\t\tcount := count + 1;\n\t\tMULTI_IN := MULTI_IN + in_3;\n\tEND_IF;\n\tMULTI_IN := SEL(count = 0, MULTI_IN / INT_TO_REAL(count), default);\n\n1:\tMULTI_IN := SEL(F1, default, IN_1);\n\n2:\tMULTI_IN := SEL(F2, default, IN_2);\n\n3:\tMULTI_IN := SEL(F3, default, IN_3);\n\n4:\tMULTI_IN := default;\n\n5:\tMULTI_IN := SEL(F1, in_max, IN_1);\n\tIF F2 AND in_2 < MULTI_IN THEN MULTI_IN := in_2; END_IF;\n\tIF F3 AND in_3 < MULTI_IN THEN MULTI_IN := in_3; END_IF;\n\tIF MULTI_IN = in_max THEN MULTI_IN := default; END_IF;\n\n6:\tMULTI_IN := SEL(F1, in_min, IN_1);\n\tIF F2 AND in_2 > MULTI_IN THEN MULTI_IN := in_2; END_IF;\n\tIF F3 AND in_3 > MULTI_IN THEN MULTI_IN := in_3; END_IF;\n\tIF MULTI_IN = in_min THEN MULTI_IN := default; END_IF;\n\n7:\tIF F1 AND F2 AND F3 THEN MULTI_IN := MID3(in_1, in_2, in_3);\n\tELSIF F1 AND F2 THEN MULTI_IN := MIN(in_1, in_2);\n\tELSIF F1 AND F3 THEN MULTI_IN := MIN(in_1, in_3);\n\tELSIF F2 AND F3 THEN MULTI_IN := MIN(in_2, in_3);\n\tELSIF F1 THEN MULTI_IN := in_1;\n\tELSIF F2 THEN MULTI_IN := in_2;\n\tELSIF F3 THEN MULTI_IN := in_3;\n\tELSE MULTI_IN := default;\n\tEND_IF;\n\nEND_CASE;\n\n(*\nhm 1.1.2007\t\trev 1.1\n\tchanged midr to mid3 function\n\nhm\t14. 10. 2008\trev 1.2\n\tcorrected an error for in_3 overrange detection\n\timproved performance\n\nhm\t11. mar. 2009\trev 1.3\n\tchanged real constants to use dot syntax\n\nhm\t18. jul. 2009\trev 1.4\n\timproved performance\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "MUL_ADD.st", - "source": "FUNCTION MUL_ADD : REAL\nVAR_INPUT\n\tX : REAL;\n\tK : REAL;\n\tO : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t11 nov 2007\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function multiplies an input X with K and adds Offset O to the result.\n\n*)\n\nMUL_ADD := X * K + O;\n\n(* revision history\nhm\t28. feb 2007\n\toriginal version\n\nhm\t11.nov 2007\t\trev 1.1\n\tdeleted preset values for K and O this makes no sense for a function\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "MUX_2.st", - "source": "FUNCTION MUX_2 : BOOL\nVAR_INPUT\n\tD0: BOOL;\n\tD1: BOOL;\n\tA0: BOOL;\nEND_VAR\n\n\n(*\n\tversion 1.2\t16. oct. 2008\n\tprogrammer \thugo\n\ttested BY\toscat\n\n\tdual input multiplexer\n\tdepending on the value of A0, D0 or D1 will be switched to the Output\n\n\texecutioin TIME on wago 750-841 = 7us\n*)\n\nMUX_2 := SEL(A0, D0, D1);\n\n\n(*\nrevision history:\nhm\t5.10.2006\t\trev 1.1\n\tchanged to ST Langage for better portability.\n\nhm\t16. oct. 2008\trev 1.2\n\timproved performance\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "MUX_4.st", - "source": "FUNCTION MUX_4 : BOOL\nVAR_INPUT\n\tD0: BOOL;\n\tD1: BOOL;\n\tD2: BOOL;\n\tD3: BOOL;\n\tA0: BOOL;\n\tA1: BOOL;\nEND_VAR\n\n\n(*\nversion 1.2\t16. oct. 2008\nprogrammer \thugo\ntested BY\toscat\n\nquad input multiplexer\ndepending on the value of A0 and A1, one of the 4 inputs will be switched to the Output\n\n\n*)\n\nIF A1 THEN\n\tMUX_4 := SEL(A0, D2, D3);\nELSE\n\tMUX_4 := SEL(A0, D0, D1);\nEND_IF;\n\n\n(*\nrevision history:\nhm \t5.10.2006\t\trev 1.1\n\trewritten to ST for better portability\n\nhm\t16. oct. 2008\trev 1.2\n\timproved performance\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "MUX_R2.st", - "source": "FUNCTION MUX_R2 : REAL\nVAR_INPUT\n\tIN0 : REAL;\n\tIN1 : REAL;\n\tA : BOOL;\nEND_VAR\n\n\n(*\nversion 1.1\t16. oct. 2008\nprogrammer \toscat\ntested by\toscat\n\nMUX_R2 is an analog Multiplexer.\none of 2 real inputs are selected and put through to out.\nThe Adress input A selects between 2 Real inputs IN0 and IN1, A=0 > In0, A=1 > in1.\n\n*)\n\nMUX_R2 := SEL(A, IN0, IN1);\n\n\n(* revision history\nhm\t19. jan. 2007\trev 1.0\n\toriginal version\n\nhm\t16. oct. 2008\trev 1.1\n\timproved performance\n\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "MUX_R4.st", - "source": "FUNCTION MUX_R4 : REAL\nVAR_INPUT\n\tIN0 : REAL;\n\tIN1 : REAL;\n\tIN2 : REAL;\n\tIN3 : REAL;\n\tA0 : BOOL;\n\tA1 : BOOL;\nEND_VAR\n\n\n(*\nversion 1.1\t16. oct. 2008\nprogrammer \toscat\ntested by\toscat\n\nMUX_R4 is an analog Multiplexer.\none of 4 real inputs are selected and put through to out.\nThe Adress input A0 and A1 selects between the 4 Real inputs IN0.. IN1.\n\n*)\n\nIF A1 THEN\n\tMUX_R4 := SEL(A0, IN2, IN3);\nELSE\n\tMUX_R4 := SEL(A0, IN0, IN1);\nEND_IF;\n\n\n\n(* revision history\nhm\t19. jan 2007\trev 1.0\n\toriginal version\n\nhm\t16. oct. 2008\trev 1.1\n\timproved performance\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "M_D.st", - "source": "FUNCTION_BLOCK M_D\nVAR_INPUT\n\tstart : BOOL;\n\tstop : BOOL;\n\ttmax : TIME := t#10d;\n\trst: BOOL;\nEND_VAR\nVAR_OUTPUT\n\tPT : TIME;\n\tET : TIME;\n\trun : BOOL;\nEND_VAR\nVAR\n\tedge : BOOL;\n\tT0 : TIME;\n\ttx: TIME;\n\tstartup: BOOL;\nEND_VAR\n\n(*\n\tversion 1.2\t27. feb. 2009\n\tprogrammer \thugo\n\ttested BY\toscat\n\nm_d measures the time between a rising edge on start to a rising edge on stop and returs the last measured value on the output PT.\na second output ET is starting from 0 at the rising edge of start and is counting up until the rising edge of stop occurs.\nthe asynchronous input rst can reset the outputs at any time.\ntmax defines a timeout wich is the maximum measurable time between start and stop, if this time is exceeded the outputs will stay at 0.\n*)\n\n(* check for rst input *)\nIF rst OR et >= tmax THEN\n\tpt := t#0ms;\n\tet := t#0ms;\n\tstartup := FALSE;\n\trun := FALSE;\nEND_IF;\n\n(* avoid timers to start when input is true at startup *)\nIF NOT startup THEN\n\tedge := start;\n\tstartup := TRUE;\nEND_IF;\n\n(* read system timer *)\ntx := DWORD_TO_TIME(T_PLC_MS());\n\n(* detect rising edge on start *)\nIF start AND NOT edge AND NOT stop THEN\n\tt0 := tx;\n\trun := TRUE;\n\tpt := t#0s;\nELSIF stop AND run THEN\n\tpt := et;\n\trun := FALSE;\nEND_IF;\nedge := start;\nIF run THEN et := tx - t0; END_IF;\n\n(* revision history\nhm\t\t2.5.2007\trev 1.0\n\toriginal version\n\nhm\t\t16.9.2007\trev 1.1\n\tchanges time() to T_plc_ms() for compatibility reasons\n\nhm\t27. feb 2009\trev 1.2\n\tdeleted unnecessary init with 0\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "M_T.st", - "source": "FUNCTION_BLOCK M_T\nVAR_INPUT\n\tIN : BOOL;\n\tTMAX : TIME := t#10d;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tPT : TIME;\n\tET: TIME;\nEND_VAR\nVAR\n\tedge : BOOL;\n\tstart : TIME;\n\ttx: TIME;\nEND_VAR\n\n(*\nversion 1.4\t10. mar. 2009\nprogrammer \thugo\ntested BY\t\toscat\n\nm_t measures the with of a high pulse and returs the last measured pulse width on output PT.\na second output ET is starting from 0 at the rising edge and counting up until the falling edge occurs and resetts et to 0.\nthe asynchrtonous input rst can reset the outputs at any time.\ntmax defines a maximum measurable time, if this value is exceeded the outputs will be reset to 0.\n\n*)\n\n(* read system time *)\ntx := DWORD_TO_TIME(T_PLC_MS());\n\nIF RST OR ET >= TMAX THEN\n\tPT := t#0s;\n\tET := t#0s;\nELSIF IN THEN\n\tIF NOT edge THEN start := tx; END_IF;\n\tET := tx - start;\nELSE\n\tPT := ET;\nEND_IF;\nedge := IN;\n\n\n\n(* revision history\nhm\t4. aug. 2006\trev 1.0\n\toriginal version\n\nhm\t2. may. 2007\trev 1.1\n\tadded init variable to avoid unreasonable measurement if falling edge occurs first.\n\tadded et (elapsed time) output to count from 0 at rising edge until a falling edge resets et to 0.\n\tadded reset input.\n\nhm\t16. sep. 2007\trev 1.2\n\tchanges time() to T_plc_ms() for compatibility reasons\n\nhm\t17. dec. 2008\trev 1.3\n\tcode optimized\n\nhm\t10. mar. 2009\trev 1.4\n\tremoved nested comments\n\tremoved double assignments\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "M_TX.st", - "source": "FUNCTION_BLOCK M_TX\nVAR_INPUT\n\tin: BOOL;\n\ttmax : TIME := t#10d;\n\trst : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tTH : TIME;\n\tTL : TIME;\n\tDC : REAL;\n\tF: REAL;\n\tET : TIME;\nEND_VAR\nVAR\n\tedge : BOOL;\n\tstart: TIME;\n\tstop:TIME;\n\ttx: TIME;\n\trise : BOOL;\n\tfall : BOOL;\n\tstartup: BOOL;\nEND_VAR\n\n(*\n\tversion 1.4\t11. mar. 2009\n\tprogrammer \toscat\n\ttested BY\t\toscat\n\nthis measures the timing of a signal\nTH is the high pulse width\nTL is the low pulse width\nDC is the duty cycle\nF is the frequency\nET will start at 0 with a rising edge and count up till the next rising edge starts from 0 again. \nthe acuracy depends on the cycle time of the sps and is limited to 1ms resolution.\nan asynchronous reset can reset all outputs to 0 at any time.\nthe input tmax can configure a timeout for ET where the function block will outomatically reset itself.\ntmx is predefined to 10 days.\n*)\n\n(* check FOR rst input *)\nIF rst OR (et >= tmax) THEN\n\trise := FALSE;\n\tfall := FALSE;\n\tstartup := FALSE;\n\tth := t#0ms;\n\ttl := t#0ms;\n\tDC := 0.0;\n\tF := 0.0;\n\tET := t#0s;\nEND_IF;\n\n(* avoid timers to start when input is true at startup *)\nIF NOT startup THEN\n\tedge := in;\n\tstartup := TRUE;\nEND_IF;\n\n(* read system timer *)\ntx := DWORD_TO_TIME(T_PLC_MS());\n\n(* edge trigger rising and falling edge *)\nIF in XOR edge THEN\n\tedge := in;\n\t(* rising edge starts measurement *)\n\tIF in THEN\n\t\tstart := Tx;\n\t\trise := TRUE;\n\t\tIF fall THEN tl := start - stop; END_IF;\n\t\tIF th > t#0ms AND tl > t#0ms THEN\n\t\t\tdc := TIME_TO_REAL(th) / TIME_TO_REAL(th+tl);\n\t\t\tf := 1000.0 / TIME_TO_REAL(th + tl);\n\t\tEND_IF;\n\t(* falling edge starts second cycle measurement *)\n\tELSE\n\t\tstop := Tx;\n\t\tfall := TRUE;\n\t\tIF rise THEN th := stop - start; END_IF;\n\t\tIF th > t#0ms AND tl > t#0ms THEN\n\t\t\tdc := TIME_TO_REAL(th) / TIME_TO_REAL(th+tl);\n\t\t\tf := 1000.0 / TIME_TO_REAL(th + tl);\n\t\tEND_IF;\n\tEND_IF;\nEND_IF;\nIF rise THEN et := tx - start; END_IF;\n\n(* revision history\nhm\t4. aug. 2006\trev 1.0\n\toriginal version\n\nhm\t2. mai. 2007\trev 1.1\n\tmade sure that no undefined values would be measured at startup conditions\n\tadded output et\n\tadded rst input\n\tadded tmax input\n\nhm\t16. sep. 2007\trev 1.2\n\tchanges time() to T_plc_ms() for compatibility reasons\n\nhm\t27. feb. 2009\trev 1.3\n\tdeleted unnecessary init with 0\n\nhm\t11. mar. 2009\trev 1.4\n\tchanged real constants to use dot syntax\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "NEGX.st", - "source": "FUNCTION NEGX : REAL\nVAR_INPUT\n\tX : REAL;\nEND_VAR\n\n\n(*\nversion 1.0\t26. oct. 2008\nprogrammer \thugo\ntested by\ttobias\n\nThis function returns -X\n\n*)\n\nNEGX := -X;\n\n\n(* revision history\nhm\t26. oct. 2008\trev 1.0\n\toriginal version\n\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "OCT_TO_BYTE.st", - "source": "FUNCTION OCT_TO_BYTE : BYTE\nVAR_INPUT\n\tOCT : STRING(10);\nEND_VAR\nVAR\n\tpt : POINTER TO BYTE;\n\ti: INT;\n\tX: BYTE;\n\tstop: INT;\nEND_VAR\n\n(*\nversion 1.1\t20. sep. 2008\nprogrammer \thugo\ntested by\t\toscat\n\nOCT_TO_BYTE converts a octagonal string into a byte.\n\n*)\n\npt := ADR(oct);\nstop := LEN(oct);\nFOR I := 1 TO stop DO\n\t(* read the first character and subtract 48 to get value in decimal 0 = 48 *)\n\tx := pt^;\n\t(* calculate the value of the digit *)\n\tIF X > 47 AND x < 56 THEN\n\t\tOCT_TO_BYTE := SHL(OCT_TO_BYTE,3) + X - 48;\n\tEND_IF;\n\tpt := pt + 1;\nEND_FOR;\n\n\n\n(* revision histroy\nhm\t18. jun. 2008\trev 1.0\n\toriginal release\n\nhm\t20. sep. 2008\trev 1.1\n\tchanged length of input string from 20 to 10\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "OCT_TO_DWORD.st", - "source": "FUNCTION OCT_TO_DWORD : DWORD\nVAR_INPUT\n\tOCT : STRING(20);\nEND_VAR\nVAR\n\tpt : POINTER TO BYTE;\n\ti: INT;\n\tX: BYTE;\n\tstop: INT;\nEND_VAR\n\n(*\nversion 1.0\t18. jun 2008\nprogrammer \thugo\ntested by\toscat\n\nOCT_TO_DWORD converts a octagonal string into a dword.\n\n*)\n\npt := ADR(oct);\nstop := LEN(oct);\nFOR I := 1 TO stop DO\n\t(* read the first character and subtract 48 to get value in decimal 0 = 48 *)\n\tx := pt^;\n\t(* calculate the value of the digit *)\n\tIF X > 47 AND x < 56 THEN\n\t\tOCT_TO_DWORD := SHL(OCT_TO_DWORD,3) + X - 48;\n\tEND_IF;\n\tpt := pt + 1;\nEND_FOR;\n\n\n\n\n(* revision histroy\nhm\t18. jun. 2008\trev 1.0\n\toriginal release\n\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "OFFSET.st", - "source": "FUNCTION OFFSET : REAL\nVAR_INPUT\n\tX : REAL;\n\tO1, O2, O3, O4 : BOOL;\n\tD : BOOL;\nEND_VAR\nVAR_INPUT CONSTANT\n\tOffset_1 : REAL;\n\tOffset_2 : REAL;\n\tOffset_3 : REAL;\n\tOffset_4 : REAL;\n\tdefault : REAL;\nEND_VAR\n\n(*\nversion 1.0\t12 jan 2007\nprogrammer \toscat\ntested by\toscat\n\nThe Function offset adds offsets to an analog signal depending on digital inputs.\nall selected offsets are added at the same time.\nwith the input D a default value instead of the input X can be used.\n\n*)\n\nIF D THEN OFFSET := default; ELSE OFFSET := X; END_IF;\nIF O1 THEN OFFSET := OFFSET + offset_1; END_IF;\nIF O2 THEN OFFSET := OFFSET + offset_2; END_IF;\nIF O3 THEN OFFSET := OFFSET + offset_3; END_IF;\nIF O4 THEN OFFSET := OFFSET + offset_4; END_IF;\n\n\n\n(* revision history\nhm\t12. jan 2007\n\toriginal version\n\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "OFFSET2.st", - "source": "FUNCTION OFFSET2 : REAL\nVAR_INPUT\n\tX : REAL;\n\tO1, O2, O3, O4 : BOOL;\n\tD : BOOL;\nEND_VAR\nVAR_INPUT CONSTANT\n\tOffset_1 : REAL;\n\tOffset_2 : REAL;\n\tOffset_3 : REAL;\n\tOffset_4 : REAL;\n\tdefault : REAL;\nEND_VAR\n\n(*\nversion 1.0\t12 jan 2007\nprogrammer \toscat\ntested by\t\ttobias\n\nThe Function offset adds offsets to an analog signal depending on digital inputs.\none offset can be added at the same time, if more then one input is true, the one with the highest number (o1 .. o4) will be used.\nThe input D will select a default value instead of X for input.\n\n*)\n\nIF D THEN OFFSET2 := default; ELSE OFFSET2 := X; END_IF;\nIF O4 THEN OFFSET2 := OFFSET2 + offset_4;\nELSIF O3 THEN OFFSET2 := OFFSET2 + offset_3;\nELSIF O2 THEN OFFSET2 := OFFSET2 + offset_2;\nELSIF O1 THEN OFFSET2 := OFFSET2 + offset_1;\nEND_IF;\n\nEND_FUNCTION\n" - }, - { - "fileName": "OM_TO_F.st", - "source": "FUNCTION OM_TO_F : REAL\nVAR_INPUT\n\tOM : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t18. oct. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function converts Omega F to frequency\nF = OM / (2*PI)\n*)\n\nOM_TO_F := OM / math.PI2;\n\n\n(* revision history\nhm\t22. jan. 2007\trev 1.0\n\toriginal version\n\nhm\t18. oct. 2008\trev 1.1\n\tusing math constants\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "ONTIME.st", - "source": "FUNCTION_BLOCK ONTIME\nVAR_INPUT\n\tIN : BOOL;\n\tRST : BOOL;\nEND_VAR\nVAR_IN_OUT\n\tSECONDS : UDINT;\n\tCYCLES : UDINT;\nEND_VAR\nVAR\n\ttx: DWORD;\n\tlast : DWORD;\n\tedge : BOOL;\n\tinit: BOOL;\n\tms: DWORD;\nEND_VAR\n\n(*\nversion 2.5\t18. mar. 2011\nprogrammer \toscat\ntested by\t\ttobias\n\nONTIME measures the ontime of a signal in seconds.\nthe output SECONDS is of type DWORD which results in a total measurement range of 1 second up to 136 years.\ninternally ontime works with a resolution of milliseconds\n\n*)\n\n(* read system time *)\ntx := T_PLC_MS();\n\n(* make sure the first cycle works correctly *)\nIF NOT init THEN\n\tinit := TRUE;\n\tlast := tx;\n\tms := 0;\nEND_IF;\nIF RST THEN\n\tSECONDS := 0;\n\tCYCLES := 0;\n\tlast := tx;\n\tms := 0;\nELSIF IN THEN\n\t(* add the current milliseconds *)\n\tms := (tx - last) + ms;\n\tIF ms >= 1000 THEN\n\t\tseconds := seconds + 1;\n\t\tms := ms - 1000;\n\tEND_IF;\n\tcycles := cycles + BOOL_TO_UINT(NOT edge);\nEND_IF;\nlast := tx;\nedge := in;\n\n\n(* revision history\nhm 22.2.2007\t\trev 1.1\n\tchanged VAR RETAIN PERSISTENT to VAR RETAIN for better compatibility\n\twago lon contollers do not support persisitent\n\nhm 2.8.2007\t\trev 1.2\n\tadding time up in a real number will automatically lead to the point where \n\tsmall time scales like the cycle time will be below the resolution of real and therefore\n\tontime would not increase in small steps as necessary\n\tthe time is now measured internally in two dwords and be converted to real only for\n\toutput purposes.\n\tdeleted the variable power because it was unnecessary\n\nhm\t16.9.2007\t\trev 1.3\n\tchanges time() to T_plc_ms() for compatibility reasons\n\nhm\t2. dec. 2007\trev 1.4\n\tchaged code for better performance\n\nhm\t16. mar. 2008\trev 1.5\n\tadded type conversions to avoid warnings under codesys 3.0\n\nhm\t21. oct. 2008\trev 2.0\n\tchanged module for much better performance and allow for external result storage\n\nhm\t10. nov. 2008\trev 2.1\n\tincreased internal resolution to milliseconds\n\nhm\t16. nov. 2008\trev 2.2\n\tchanged typecast to avoid warnings\n\nhm\t17. dec. 2008\trev 2.3\n\tfixed an error when in would be true for more then 49 days\n\nhm\t17. jan 2011\trev 2.4\n\tinit will not clear seconds and cycles, only rst clears these values\t\n\nhm\t18. mar. 2011\trev 2.5\n\treset was not working\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "OSCAT_VERSION.st", - "source": "FUNCTION OSCAT_VERSION : DWORD\nVAR_INPUT\n\tIN : BOOL;\nEND_VAR\n\n\n(*\nversion 1.1\t16 dec 2007\nprogrammer \thugo\ntested by\t\toscat\n\noscat_version returns the version number in dword format\n132 is library version 1.32\nif IN = true, the release date will be returned\n\n*)\n\nIF in THEN\n\tOSCAT_VERSION := DATE_TO_DWORD(D#2024-07-16);\nELSE\n\tOSCAT_VERSION := 335;\nEND_IF;\n\n(* revision history\nhm\t6. oct 2006\trev 1.0\n\toriginal version\n\nhm\t16. dec 2007\trev 1.1\n\tadded possibility to return date and version depending on IN.\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "OVERRIDE.st", - "source": "FUNCTION OVERRIDE : REAL\nVAR_INPUT\n\tX1, X2, X3 : REAL;\n\tE1 : BOOL;\n\tE2 : BOOL;\n\tE3 : BOOL;\nEND_VAR\n\n\n(*\nversion 1.0\t4 nov 2007\nprogrammer \toscat\ntested by\ttobias\n\nOVERRIDE deliveres the maximum absolute value of the 3 inputs X1, X2 and X3.\nwith the inputs E1, E2 and E3 each of the 3 inputs can be turned on or off.\n\n*)\n\nIF E1 THEN OVERRIDE := X1; END_IF;\nIF E2 AND ABS(x2) > ABS(OVERRIDE) THEN OVERRIDE := X2; END_IF;\nIF E3 AND ABS(x3) > ABS(OVERRIDE) THEN OVERRIDE := X3; END_IF;\n\n(* revision history\nhm\t4.11.2007\t\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "PARITY.st", - "source": "FUNCTION PARITY : BOOL\nVAR_INPUT\n\tin : DWORD;\nEND_VAR\n\n\n(*\n\tversion 1.3\t18 feb 2008\n\tprogrammer \thugo\n\ttested BY\t\thans\n\nthis function calculates the even parity of an input Dword\nthe output will be true if the amount of high bits are an odd number.\n\n*)\n\nWHILE in > 0 DO\n\tPARITY := PARITY XOR in.0 XOR in.1 XOR in.2 XOR in.3;\n\tin := SHR(in,4);\nEND_WHILE;\n\n(* code before rev 1.2\nWHILE in > 0 DO\n\tIF in.0 THEN cnt := cnt +1; END_IF;\n\tin := SHR(in,1);\nEND_WHILE;\nIF (cnt MOD 2) = 1 THEN parity := TRUE; ELSE parity := FALSE; END_IF;\n*)\n\n(* revision history\n\nrev 1.0 hm 1 sep 2006\n\toriginal version\n\nrev 1.1 hm 10.9.2007\n\tchanged algorithm to improve performance\n\nrev 1.2\thm\t8 dec 2007\n\tchanged algorithm to improve performance\n\nrev 1.3\thm\t18 feb 2008\n\tchanged algorithm to improve performance\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "PARSET.st", - "source": "FUNCTION_BLOCK PARSET\nVAR_INPUT\n\tA0, A1 : BOOL;\nEND_VAR\nVAR_INPUT CONSTANT\n\tX01, X02, X03, X04 : REAL;\n\tX11, X12, X13, X14 : REAL;\n\tX21, X22, X23, X24 : REAL;\n\tX31, X32, X33, X34 : REAL;\n\tTC : TIME;\nEND_VAR\nVAR_OUTPUT\n\tP1, P2, P3, P4 : REAL;\nEND_VAR\nVAR\n\tX : ARRAY[0..3,1..4] OF REAL;\n\tS1, S2, S3, S4 : REAL;\n\ttx, last : DWORD;\n\tstart : BOOL;\n\tset : BYTE;\n\tinit: BOOL;\nEND_VAR\n\n(*\nversion 1.1\t16. mar. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nparset selects on of 4 parameter sets adressed by the inputs A0 and A1. if TC is specified, the change of the outputs\nis ramped by the time tc\n*)\n\n(* read system_time *)\ntx := T_PLC_MS();\n\n(* init sequence *)\nIF NOT init THEN\n\tset.0 := NOT A0;\n\tinit := TRUE;\n\tX[0,1] := X01;\n\tX[0,2] := X02;\n\tX[0,3] := X03;\n\tX[0,4] := X04;\n\tX[1,1] := X11;\n\tX[1,2] := X12;\n\tX[1,3] := X13;\n\tX[1,4] := X14;\n\tX[2,1] := X21;\n\tX[2,2] := X22;\n\tX[2,3] := X23;\n\tX[2,4] := X24;\n\tX[3,1] := X31;\n\tX[3,2] := X32;\n\tX[3,3] := X33;\n\tX[3,4] := X34;\n\tP1 := X01;\n\tP2 := X02;\n\tP3 := X03;\n\tP4 := X04;\nEND_IF;\n\n(* check for input change *)\nIF (A0 XOR set.0) OR (A1 XOR set.1) THEN\n\t(* a new set is selected *)\n\tset.0 := A0;\n\tset.1 := A1;\n\tIF tc > t#0s THEN\n\t\tstart := TRUE;\n\t\tlast := tx;\n\t\t(* save the step speed for the output changes in S *)\n\t\tS1 := (X[set,1] - P1)/DWORD_TO_REAL(TIME_TO_DWORD(tc));\n\t\tS2 := (X[set,2] - P2)/DWORD_TO_REAL(TIME_TO_DWORD(tc));\n\t\tS3 := (X[set,3] - P3)/DWORD_TO_REAL(TIME_TO_DWORD(tc));\n\t\tS4 := (X[set,4] - P4)/DWORD_TO_REAL(TIME_TO_DWORD(tc));\n\tEND_IF;\nELSIF start AND tx - last < TIME_TO_DWORD(tc) THEN\n\t(* ramp the outputs to the new value *)\n\tP1 := X[set,1] - S1 * DWORD_TO_REAL(TIME_TO_DWORD(Tc) - tx + last);\n\tP2 := X[set,2] - S2 * DWORD_TO_REAL(TIME_TO_DWORD(Tc) - tx + last);\n\tP3 := X[set,3] - S3 * DWORD_TO_REAL(TIME_TO_DWORD(Tc) - tx + last);\n\tP4 := X[set,4] - S4 * DWORD_TO_REAL(TIME_TO_DWORD(Tc) - tx + last);\nELSE\n\t(* make sure outputs match the correct set values *)\n\tstart := FALSE;\n\tP1 := X[set,1];\n\tP2 := X[set,2];\n\tP3 := X[set,3];\n\tP4 := X[set,4];\nEND_IF;\n\n(* revision history\nhm\t2.11.2007\t\trev 1.0\n\toriginal version\n\nhm\t16. mar. 2008\trev 1.1\n\tadded type conversions to avoid warnings under codesys 3.0\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "PARSET2.st", - "source": "FUNCTION_BLOCK PARSET2\nVAR_INPUT\n\tX : REAL;\nEND_VAR\nVAR_INPUT CONSTANT\n\tX01, X02, X03, X04 : REAL;\n\tX11, X12, X13, X14 : REAL;\n\tX21, X22, X23, X24 : REAL;\n\tX31, X32, X33, X34 : REAL;\n\tL1, L2, L3 : REAL;\n\tTC : TIME;\nEND_VAR\nVAR_OUTPUT\n\tP1,P2,P3,P4 : REAL;\nEND_VAR\nVAR\n\tPset : parset;\n\tinit: BOOL;\nEND_VAR\n\n(*\nversion 1.0\t3 nov 2007\nprogrammer \thugo\ntested by\ttobias\n\nparset2 selects on of 4 parameter sets depending on the value of X. if TC is specified, the change of the outputs\nis ramped by the time TC\n*)\n\n(* init sequence *)\nIF NOT init THEN\n\tinit := TRUE;\n\tpset(TC:=TC, X01:=X01, X02:=X02, X03:=X03, X04:=X04, X11:=X11, X12:=X12, X13:=X13, X14:=X14, X21:=X21, X22:=X22, X23:=X23, X24:=X24, X31:=X31, X32:=X32, X33:=X33, X34:=X34);\nEND_IF;\nIF ABS(X) < L1 THEN\n\tpset(A0 := FALSE, A1 := FALSE);\nELSIF ABS(X) < L2 THEN\n\tpset(A0 := TRUE, A1 := FALSE);\nELSIF ABS(x) < L3 THEN\n\tpset(A0 := FALSE, A1 := TRUE);\nELSE\n\tpset(A0 := TRUE, A1 := TRUE);\nEND_IF;\nP1 := pset.P1;\nP2 := pset.P2;\nP3 := pset.P3;\nP4 := pset.P4;\n\n(* revision history\nhm\t\t3.11.2007\t\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "PERIOD.st", - "source": "FUNCTION PERIOD : BOOL\nVAR_INPUT\n\td1 : DATE;\n\tdx : DATE;\n\td2 : DATE;\nEND_VAR\nVAR\n\tday1, day2, dayx : INT;\nEND_VAR\n\n(*\nversion 1.3\t22. mar. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nPERIOD checks if a given date is between two dates (d1 and d2) d1 is the starting date and d2 the last date for the period.\nthe years of the dates are ignored, so the function period cheks for a time period within a year independet of the year.\n\n*)\n\nday1 := DAY_OF_YEAR(d1);\nday2 := DAY_OF_YEAR(d2);\ndayx := DAY_OF_YEAR(dx);\nIF NOT LEAP_OF_DATE(dx) AND dayx > 58 THEN dayx := dayx + 1; END_IF;\nIF NOT LEAP_OF_DATE(d1) AND day1 > 58 THEN day1 := day1 + 1; END_IF;\nIF NOT LEAP_OF_DATE(d2) AND day2 > 58 THEN day2 := day2 + 1; END_IF;\n\nIF day2 < day1 THEN\n\t(* the period spans over the new year *)\n\tPERIOD := dayx <= day2 OR dayx >= day1;\nELSE\n\tPERIOD := dayx >= day1 AND dayx <= day2;\nEND_IF;\n\n(* code before rev 1.2\nyx := year(dx);\np1 := date_add(d1,0,0,0,yx - year(d1));\np2 := date_add(d2,0,0,0,yx - year(d2));\n\nIF p2 >= p1 THEN\n\tperiod := dx <= p2 AND dx >= p1;\nELSE\n\tperiod := dx <= p2 OR dx >= p1;\nEND_IF;\n*)\n\n\n(* revision history\n\nhm\t\t19. sep 2007\trev 1.0\n\toriginal version\n\nhm\t\t20. sep 2007\trev 1.1\n\tcorrected a problem with leap year\n\nhm\t\t4. jan 2008\t\trev 1.2\n\tchanged code for better performance\n\nhm\t\t22. mar. 2008\trev 1.3\n\tfunction would deliver wrong results when d1, d2 or dx are a leap_year\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "PERIOD2.st", - "source": "FUNCTION PERIOD2 : BOOL\nVAR_INPUT\n\tDP : ARRAY[0..3,0..1] OF DATE;\n\tDX : DATE;\nEND_VAR\n\n\n(*\nversion 1.0\t27. apr. 2008\nprogrammer \thugo\ntested by\ttobias\n\nPERIOD2 checks if DX is within one of 4 periods and sets the output true if so.\n\n*)\n\nPERIOD2 := \t(DX >= DP[0,0] AND DX <= DP[0,1]) OR\n\t\t\t(DX >= DP[1,0] AND DX <= DP[1,1]) OR\n\t\t\t(DX >= DP[2,0] AND DX <= DP[2,1]) OR\n\t\t\t(DX >= DP[3,0] AND DX <= DP[3,1]);\n\n\n(* revision history\n\nhm\t\t27. apr 2008\trev 1.0\n\toriginal version\n\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "PIN_CODE.st", - "source": "FUNCTION_BLOCK PIN_CODE\nVAR_INPUT\n\tCB : BYTE;\n\tE : BOOL;\nEND_VAR\nVAR_INPUT CONSTANT\n\tPIN : STRING(8);\nEND_VAR\nVAR_OUTPUT\n\tTP : BOOL;\nEND_VAR\nVAR\n\tPOS: INT := 1;\nEND_VAR\n\n(*\nversion 1.0\t30. oct. 2008\nprogrammer \thugo\ntested by\toscat\n\nMATRIX_CODE scans the input of a key_pad (MATRIX) for a sequence of characters.\n\n*)\n\ntp := FALSE;\nIF e THEN\n\tIF CB = CODE(pin, pos) THEN\n\t\tpos := pos + 1;\n\t\tIF pos > LEN(PIN) THEN\n\t\t\t(* proper code is detected *)\n\t\t\tTP := TRUE;\n\t\t\tpos := 1;\n\t\tEND_IF;\n\tELSE\n\t\tpos := 1;\n\tEND_IF;\nEND_IF;\n\n\n(* revision history\nhm\t30. oct. 2008\trev 1.0\t\t\n\toriginal version \n\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "POLYNOM_INT.st", - "source": "FUNCTION POLYNOM_INT : REAL\nVAR_INPUT\n\tX : REAL;\n\tXY : ARRAY[1..5,0..1] OF REAL;\n\tPts : INT;\nEND_VAR\nVAR\n\tI, J : INT;\n\tstop: INT;\nEND_VAR\n\n(*\n\tversion 1.3\t10. mar. 2009\n\tprogrammer \toscat\n\ttested BY\t\toscat\n\nPOLYNOM_INT calculates an output based on a Polynom interpolation of up to 5 coordinates given in an array\nthe indut coordinates have to start at the lowest array position and must be sorted ba ascending X values.\n\n*)\n\n(*make sure n is bound within the array size *)\npts := MIN(pts, 5);\n\n(* this part is only to calculate the polynom parameters, which are then stores in the Y array\n\tthe array values, it is not needed during runtime, unless the parameters will change during runtime\n\tthe remaining code without this setup code can be used within a function to calculate specific functions\n\tthe content of the arrays is then used as constant values within the function *)\n\nFOR i := 1 TO pts DO\n\tstop := i + 1;\n \tFOR j := pts TO stop BY -1 DO\n \t\tXY[j,1] := (XY[j,1] - XY[j-1,1]) / (XY[j,0] - XY[j-i,0]);\n\tEND_FOR;\nEND_FOR;\n\n\n(* this part is the actual calculation *)\nPOLYNOM_INT := 0.0;\nFOR i := pts TO 1 BY -1 DO\n POLYNOM_INT := POLYNOM_INT * (X - XY[i,0]) + XY[i,1];\nEND_FOR;\n\n\n(* revision history\nhm\t8. okt 2007\trev 1.0\n\toriginal version\n\nhm\t17. dec 2007\trev 1.1\n\tinit makes no sense for a function\n\nhm\t22. feb 2008\trev 1.2\n\timproved performance\n\nhm\t10. mar. 2009\trev 1.3\n\tchanged syntax of real constants to 0.0\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "PRESSURE.st", - "source": "FUNCTION_BLOCK PRESSURE\nVAR_INPUT\n\tmws : REAL;\n\ttorr : REAL;\n\tatt : REAL;\n\tatm : REAL;\n\tpa : REAL;\n\tbar : REAL;\nEND_VAR\nVAR_OUTPUT\n\tYmws : REAL;\n\tYtorr : REAL;\n\tYatt : REAL;\n\tYatm : REAL;\n\tYpa : REAL;\n\tYbar : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t11. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nthis function converts different pressure units\nany unused input can simply be left open.\ndifferent inputs connected at the same time will be added up.\n*)\n\nYbar := bar +\n\t\tpa * 1.0E-5 +\n\t\t0.980665 * att +\n\t\t1.01325 * atm +\n\t\t0.001333224 * torr +\n\t\t0.0980665 * mws;\nYmws := ybar * 10.1971621297793;\nYtorr := ybar * 750.0615050434140;\nYatt := ybar * 1.0197162129779;\nyatm := ybar * 0.9869232667160;\nYpa := ybar * 100000.0;\n\n\n(*\nDruck, Pascal Pa 1 Pa = 1 N/m2 = 1 kg/(s2 E m) . 0,75 E 10.2 mmHg\nmechanische 1 MPa = 1 N/mm2 . fur Festigkeitsangaben\nSpannung Bar bar 1 bar = 105 Pa = 103 mbar = 105 kg/(s2 E m)\nMillimeter- mmHg 1 mmHg = 133,322 Pa = 1,333 22 mbar\nQuecksilbersaule . nur in Heilkunde zulassig\nphysik. Atmosphare atm 1 atm = 1,013 25 bar\ntechn. Atmosphare at 1 at = 1 kp/cm2 = 0,980665 bar\nTorr Torr 1 Torr = (101325/760) Pa = 1,333224 mbar\nMeter-Wassersaule mWS 1 mWS = 9806,65 Pa = 98,0665 mbar\npsi lbf/in2 1 lbf/in2 = 68,947 57 mbar = 6894,757 Pa\n\n*)\n\n(* revision history\n\nhm\t27. mar. 2007\trev 1.0\n\toriginal version\n\nhm\t11. mar. 2009\trev 1.1\n\timproved code\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "PT_TO_F.st", - "source": "FUNCTION PT_TO_F : REAL\nVAR_INPUT\n\tPT : TIME;\nEND_VAR\n\n\n(*\nversion 1.1\t11. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function converts periode time to frequency\n*)\n\nPT_TO_F := 1000.0 / DWORD_TO_REAL(TIME_TO_DWORD(PT));\n\n\n(*\trevision history\nhm\t4. aug. 2006\trev 1.0\n\toriginal version\n\nhm\t11. mar. 2009\trev 1.1\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "PWM_DC.st", - "source": "FUNCTION_BLOCK PWM_DC\nVAR_INPUT\n\tF : REAL;\n\tDC : REAL;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\nEND_VAR\nVAR\n\tclk: CLK_PRG;\n\tpulse: TP_X;\n\ttmp: REAL;\nEND_VAR\n\n(*\nversion 1.4\t11. mar. 2009\nprogrammer \toscat\ntested BY\t\toscat\n\nthis signal generator generates a square wave signal which is specified by the frequency and the duty cycle\n*)\n\nIF F > 0.0 THEN\n\ttmp := 1000.0 / F;\n\tCLK(PT := REAL_TO_TIME(tmp));\n\tPulse(in := clk.Q, pt := REAL_TO_TIME(tmp * DC));\n\tQ := pulse.Q;\nEND_IF;\n\n(* revision history\n\nhm\t25. feb 2007\trev 1.1\n\trecoded in st for better performance and better portability\n\nhm\t27. nov 2007\trev 1.2\n\tavoid divide by 0 when F = 0\n\nhm\t19. oct. 2008\trev 1.3\n\tchanged type TP_R to TP_X because of name change\n\timproved performance\n\nhm\t11. mar. 2009\trev 1.4\n\tchanged real constants to use dot syntax\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "PWM_PW.st", - "source": "FUNCTION_BLOCK PWM_PW\nVAR_INPUT\n\tF : REAL;\n\tPW : TIME;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\nEND_VAR\nVAR\n\tclk: CLK_PRG;\n\tpulse: TP_X;\nEND_VAR\n\n(*\nversion 1.5\t11. mar. 2009\nprogrammer \toscat\ntested BY\t\toscat\n\nthis signal generator generates a square wave signal which is specified by the frequency and the pulse width.\n*)\n\nIF F > 0.0 THEN\n\tCLK(PT := REAL_TO_TIME(1000.0 / F));\n\tPulse(in := clk.Q, pt := pw);\n\tQ := pulse.Q;\nEND_IF;\n\n(* revision history\n\nhm\t25. feb 2007\trev 1.1\n\trecoded in st for better performance and better portability\n\nhm\t27. nov 2007\trev 1.2\n\tavoid divide by 0 when F = 0\n\nhm\t9. dec 2007\t\trev 1.3\n\tcorrected an error with F = 0\n\nhm\t19. oct. 2008\trev 1.4\n\tchanged type tp_r to TP_x brecause of name change\n\nhm\t11. mar. 2009\trev 1.5\n\tchanged real constants to use dot syntax\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "R2_ABS.st", - "source": "FUNCTION R2_ABS : REAL2\nVAR_INPUT\n\tX : REAL2;\nEND_VAR\n\n\n(*\nversion 1.1\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nR2_abs returns the absulute value of a double precision real.\n\n*)\n\nIF X.RX >= 0.0 THEN\n\tR2_ABS.RX := X.RX;\n\tR2_ABS.R1 := X.R1;\nELSE\n\tR2_ABS.RX := -X.RX;\n\tR2_ABS.R1 := -X.R1;\nEND_IF;\n\n\n(* revision history\nhm\t21. mar. 2008\trev 1.0\n\toriginal version\n\nhm\t10. mar. 2009 rev 1.1\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "R2_ADD.st", - "source": "FUNCTION R2_ADD : REAL2\nVAR_INPUT\n\tX : Real2;\n\tY : REAL;\nEND_VAR\nVAR\n\ttemp: REAL;\nEND_VAR\n\n(*\nversion 1.0\t20. mar. 2008\nprogrammer \thugo\ntested by\ttobias\n\nR2_add adds a real to a double real which extends the accuracy of a real to twice as many digits\n\n*)\n\ntemp := X.RX;\nR2_ADD.RX := Y + X.R1 + X.RX;\nR2_ADD.R1 := temp - R2_ADD.RX + Y + X.R1;\n\n\n(* revision history\nhm\t\t20.3.2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "R2_ADD2.st", - "source": "FUNCTION R2_ADD2 : REAL2\nVAR_INPUT\n\tX : Real2;\n\tY : REAL2;\nEND_VAR\n\n\n(*\nversion 1.0\t20. mar. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nR2_add2 adds a double precision real to a double precision real which extends the accuracy of a real to twice as many digits\n\n*)\n\nR2_ADD2.R1 := X.R1 + Y.R1;\nR2_ADD2.RX := X.RX + Y.RX;\n\n\n(* revision history\nhm\t\t20.3.2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "R2_MUL.st", - "source": "FUNCTION R2_MUL : REAL2\nVAR_INPUT\n\tX : REAL2;\n\tY : REAL;\nEND_VAR\n\n\n(*\nversion 1.0\t20. mar. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nR2_mul multiplies a real with a double real which extends the accuracy of a real to twice as many digits\n\n*)\n\nR2_MUL.RX := X.RX * Y;\nR2_MUL.R1 := X.R1 * Y;\n\n\n(* revision history\nhm\t\t20.3.2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "R2_SET.st", - "source": "FUNCTION R2_SET : REAL2\nVAR_INPUT\n\tX : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nR2_set sets a double precision real to a single real value.\n\n*)\n\nR2_SET.RX := X;\nR2_SET.R1 := 0.0;\n\n\n(* revision history\nhm\t2. jun. 2008\trev 1.0\n\toriginal version\n\nhm\t10. mar. 2009\trev 1.1\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "RAD.st", - "source": "FUNCTION RAD : REAL\nVAR_INPUT\n\tDEG : REAL;\nEND_VAR\n\n\n(*\nversion 1.2\t18. oct. 2008\nprogrammer \thugo\ntested by\ttobias\n\nthis function converts Radiant to degrees\n\n*)\n\nRAD := MODR(0.0174532925199433 * DEG, math.PI2);\n\n(* revision history\nhm\t4. aug 2006\t\trev 1.0\n\toriginal version\n\nhm \t16. oct 2007\trev 1.1\n\tadded modr statement which prohibits rad to become bigger than 2PI\n\nhm\t18. oct 2008\trev 1.2\n\tusing math constants\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "RANGE_TO_BYTE.st", - "source": "FUNCTION RANGE_TO_BYTE : BYTE\nVAR_INPUT\n\tX : REAL;\n\tlow : REAL;\n\thigh : REAL;\nEND_VAR\n\n\n(*\nversion 1.0\t9. jan 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nRange_to_byte converts a real value between low and high into a byte\n\n*)\n\nRANGE_TO_BYTE := INT_TO_BYTE(TRUNC((LIMIT(low, X, high) - low) * 255.0 / (high - low)));\n\n\n(* revision history\nhm\t9. jan 2008\t\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "RANGE_TO_WORD.st", - "source": "FUNCTION RANGE_TO_WORD : WORD\nVAR_INPUT\n\tX : REAL;\n\tlow : REAL;\n\thigh : REAL;\nEND_VAR\n\n\n(*\nversion 1.0\t9. jan 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nRange_to_word converts a real value between low and high into a byte\n\n*)\n\nRANGE_TO_WORD := DINT_TO_WORD(TRUNC((LIMIT(low,X,high)-low) * 65535.0 / (high - low)));\n\n\n(* revision history\nhm\t9. jan 2008\t\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "RDM.st", - "source": "FUNCTION RDM : REAL\nVAR_INPUT\n\tlast : REAL;\nEND_VAR\nVAR\n\ttn : DWORD;\n\ttc : INT;\nEND_VAR\n\n\n(*\nversion 1.9\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates a pseudo random number\nto generate the number it reads the sps timer and calculates a random number between 0 and 1:\nin order to use rdm more then once within one sps cycle it need to be called with different seed numbers LAST.\n\n*)\n\ntn := T_PLC_MS();\ntc := BIT_COUNT(tn);\ntn.31 := tn.2;\ntn.30 := tn.5;\ntn.29 := tn.4;\ntn.28 := tn.1;\ntn.27 := tn.0;\ntn.26 := tn.7;\ntn.25 := tn.6;\ntn.24 := tn.3;\ntn := ROL(tn,BIT_COUNT(tn)) OR 16#80000001;\ntn := tn MOD 71474513 + INT_TO_DWORD(tc + 77);\nRDM := FRACT(DWORD_TO_REAL(tn) / 10000000.0 * (math.E - LIMIT(0.0,last,1.0)));\n\n\n(*\npt := ADR(temp);\npt^ := (T_PLC_MS() AND 16#007FFFFF) OR 16#3D000000;\nRDM := fract(modR(temp*e+pi1, PI1-last) + modR(temp*PI1+e + last,e-last));\n*)\n\n(* revision history\nhm\t\t16. jan 2007\t\trev 1.0\n\toriginal version\n\nhm\t\t11. nov 2007\t\trev 1.1\n\tchanged time() into t_plc_ms()\n\nhm\t\t20. nov 2007\t\trev 1.2\n\tchanged code of temp calculation to avoid overflow in modr due to resuclt would not fit DINT for high timeer values\n\nhm\t\t5. jan 2008\t\trev 1.3\n\tchanged calculation of temp to avoid problem with high values of t_plc_ms\n\nhm\t\t2. feb 2008\t\trev 1.4\n\tchanged algorithm to avoind non iec functions and guarantee more randomness\n\nhm\t10. mar. 2008\t\trev 1.5\n\tmake sure last will be between 0 and 1 to avoid invalid results\n\nhm\t16. mar. 2008\t\trev 1.6\n\tadded conversion for tc to avoid warnings under codesys 3.0\n\nhm\t18. may. 2008\t\trev 1.7\n\tchanged constant E to E1\n\nhm\t18. oct. 2008\t\trev 1.8\n\tusing math constants\n\nhm\t10. mar. 2009\t\trev 1.9\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "RDM2.st", - "source": "FUNCTION RDM2 : INT\nVAR_INPUT\n\tlast : INT;\n\tlow : INT;\n\thigh : INT;\nEND_VAR\n\n\n(*\nversion 1.1\t18. oct. 2008\nprogrammer \thugo\ntested by\ttobias\n\nthis function calculates an integer pseudo random number\nthe random number will be in the range of low <= rdm2 <= high.\n\n*)\n\nRDM2 := TRUNC(RDM(FRACT(last * math.PI)) * (high - low + 1)) + low;\n\n(* revision history\nhm\t\t29. feb 2008\t\trev 1.0\n\toriginal version\n\nhm\t\t18. oct. 2008\t\trev 1.1\n\tusing math constants\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "RDMDW.st", - "source": "FUNCTION RDMDW : DWORD\nVAR_INPUT\n\tlast : DWORD;\nEND_VAR\nVAR\n\tRX: REAL;\n\tM: REAL;\nEND_VAR\n\n\n\n\n(*\nversion 1.2\t18. oct. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates a DWORD pseudo random number.\n\n*)\n\nM := BIT_COUNT(last);\nRX := RDM(FRACT(M * math.PI));\nRDMDW := SHL(REAL_TO_DWORD(rx*65535),16);\nRX := RDM(FRACT(M * math.E));\nRDMDW := RDMDW OR (REAL_TO_DWORD(rx*65535) AND 16#0000FFFF);\n\n\n\n(* revision history\nhm\t\t14. mar 2008\t\trev 1.0\n\toriginal version\n\nhm\t\t18. may. 2008\t\trev 1.1\n\tchanged constant E to E1\n\nhm\t\t18. oct. 2008\t\trev 1.2\n\tusing math constants\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "REAL2.st", - "source": "TYPE REAL2 :\nSTRUCT\n\tR1 : REAL;\t(* small value *)\n\tRX : REAL;\t(* big value *)\nEND_STRUCT\nEND_TYPE\n" - }, - { - "fileName": "REAL_TO_DW.st", - "source": "FUNCTION REAL_TO_DW : DWORD\nVAR_INPUT\n\tX : REAL;\nEND_VAR\nVAR\n\tpt : POINTER TO DWORD;\nEND_VAR\n\n(*\nversion 1.0\t18. apr. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function converts a 32 Bit Real to a dword in a bitwise manner.\n*)\n\npt := ADR(X);\nREAL_TO_DW := pt^;\n\n(* revision history\nhm\t18. apr. 2008\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "REAL_TO_FRAC.st", - "source": "FUNCTION REAL_TO_FRAC : FRACTION\nVAR_INPUT\n\tX : REAL;\t\t\t\t\t(* in einen Bruch umzuwandelnder Wert *)\n\tN : INT;\t\t\t\t\t(* maximale Größe des Nenners *)\nEND_VAR\nVAR\n\ttemp : DINT;\t\t\t\t(* Merker für Berechnungen *)\n\n\tsign: BOOL;\t\t\t\t\t(* Vorzeichen vom Eingangswert *)\n\tX_gerundet: DINT;\t\t\t(* Wert von Bruch, auf ganze Zahl gerundet *)\n\tX_ohne_Nachkomma: REAL;\t\t(* Wert von Bruch, ohne Nachkommastellen *)\n\tNumerator: DINT := 1;\t(* Initialwert Zaehler *)\n\tDenominator: DINT := 0;\t(* Initialwert Nenner *)\n\tNumerator_old: DINT := 0;\t(* Initialwert Zaehler der letzten Berechnung *)\n\tDenominator_old: DINT := 1;\t(* Initialwert Zaehler der letzten Berechnung *)\n\nEND_VAR\n\n(*\nversion 1.1\t\t06. apr. 2011\nprogrammer \talexander\ntested by\t\thugo\n\nthis function calculates the closest fraction for a real number\n\n*)\n\nIF X < 0.0 THEN\n\tsign := TRUE;\t\t\t\t\t\t\t\t(* Vorzeichen merken *)\n\tX := ABS(X);\t\t\t\t\t\t\t\t(* Absolutwert berechnen *)\nEND_IF;\n\nREPEAT\n\tX_gerundet := REAL_TO_DINT(X);\n\n\t(* Zaehler berechnen *)\n\ttemp := numerator * X_gerundet + numerator_old;\t\t(* Zaehler um Vorkammawert erweitern *)\n\tnumerator_old := numerator;\t\t\t\t\t\t\t(* Zaehler der letzten Berechnung speichern *)\n\tnumerator := temp;\t\t\t\t\t\t\t\t\t(* Zaehler dieser Berechnung speichern *)\n\n\t(* Nenner berechnen *)\n\ttemp := denominator * X_gerundet + denominator_old;\t(* Nenner um Vorkammawert erweitern *)\n\tdenominator_old := denominator;\t\t\t\t\t\t(* Nenner der letzten Berechnung speichern *)\n\tdenominator := temp;\t\t\t\t\t\t\t\t(* Nenner dieser Berechnung speichern *)\n\n\t(* Restwert berechnen *)\n\tX_ohne_Nachkomma := DINT_TO_REAL(X_gerundet);\n\tIF X = X_ohne_Nachkomma THEN\t\t\t\t\t\t(* Bruch geht ohne Rest auf *)\n\t\tIF ABS(denominator) <= N THEN\t\t\t\t\t\t(* kein Rundungsfehler *)\n\t\t\tnumerator_old := numerator;\t\t\t\t\t(* Numerator_old wird von Funktion zurückgegeben *)\n\t\t\tdenominator_old := denominator;\t\t\t(* Denominator_old wird von Funktion zurückgegeben *)\n\t\tEND_IF\n\t\tEXIT;\t\t\t\t\t\t\t\t\t\t\t(* keine weitere Berechnung notwendig *)\n\tELSE\n\t\tX := 1.0 / (X - X_ohne_Nachkomma);\t\t\t\t(* Kehrwert vom Rest -> Neuer Bruch *)\n\tEND_IF\n\nUNTIL\n\tABS(Denominator) > N\nEND_REPEAT\n\n(* correct sign if X was negative *)\nIF sign THEN\n\tREAL_TO_FRAC.NUMERATOR := -1 * ABS(DINT_TO_INT(numerator_old));\nELSE\n\tREAL_TO_FRAC.NUMERATOR := ABS(DINT_TO_INT(numerator_old));\nEND_IF\nREAL_TO_FRAC.DENOMINATOR := ABS(DINT_TO_INT(denominator_old));\n\n\n(* revision history\nhm\t\t19. jan. 2011\trev 1.0\n\toriginal version\n\nad\t\t06. apr. 2011\trev 1.1\n\toptimized code\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "REAL_TO_STRF.st", - "source": "FUNCTION REAL_TO_STRF : STRING(20)\nVAR_INPUT\n\tIN : REAL;\n\tN : INT;\n\tD : STRING(1);\nEND_VAR\nVAR\n\tO: REAL;\n\ti: INT;\nEND_VAR\n\n(*\nversion 1.8\t2. jan 2012\nprogrammer \thugo\ntested by\toscat\n\nReal_to_strf converts a Real to a fixed length String.\nthe string will be filles with zeroes to achieve the fixed length N after the decimal separator.\nthe input parameter specifies the decimal separator to be used in the output string.\n\n*)\n\n(* LIMIT N to 0 .. 7 *)\nN := LIMIT(0,N,7);\n(* round the input to N digits and convert to string *)\nO := ABS(in) * EXP10(N);\nREAL_TO_STRF := DINT_TO_STRING(REAL_TO_DINT(O));\n(* add zeroes in front to make sure sting is at least 8 digits long *)\nFOR i := LEN(REAL_TO_STRF) TO N DO REAL_TO_STRF := CONCAT('0', REAL_TO_STRF); END_FOR;\n(* add a dot if n > 0 *)\nIF n > 0 THEN REAL_TO_STRF := INSERT(REAL_TO_STRF, D, LEN(REAL_TO_STRF) - N); END_IF;\n(* add a minus sign if in is negative *)\nIF in < 0 THEN REAL_TO_STRF := CONCAT('-', REAL_TO_STRF); END_IF;\n\n\n(* revision history\nhm\t26 jan 2007\trev 1.0\n\toriginal version\n\nhm\t20. nov. 2007\trev 1.1\n\twhen N=0 ther will be no dot at the end of the string.\n\nhm\t15. dec. 2007\trev 1.2\n\tchanged code for better performance\n\nhm\t4. mar. 2008\trev 1.3\n\tresult is now rounded instead of trunc\n\nhm\t20. mar. 2008\trev 1.4\n\tchanged trunc to real_to_dint because trunc was generating wrong values on wago 842\n\nhm\t29. mar. 2008\trev 1.5\n\tchanged STRING to STRING(20)\n\nhm\t4. apr. 2008\trev 1.6\n\tadded variable O to avoid an error uner CoDeSys SP PLCWinNT V2.4\n\nhm\t27. feb. 2009\trev 1.7\n\tadded a missing zero for IN < 1\n\nhm 2. jan 2012\trev 1.8\n\tadded input parameter D to specify decimal separator\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "REFLECT.st", - "source": "FUNCTION REFLECT : DWORD\nVAR_INPUT\n\tD : DWORD;\n\tL : INT;\nEND_VAR\nVAR\n\ti : INT;\nEND_VAR\n\n\n(*\n\tversion 1.0\t16. jan 2011\n\tprogrammer \thugo\n\ttested BY\t\ttobias\n\nThis function reverses the specified amount of bits from bit 0 to bit n within a dword while L specifies the amount of Bits to be reflected.\n\n*)\n\nREFLECT := 0;\nFOR i := 1 TO L DO\n\tREFLECT := SHL(REFLECT, 1) OR BOOL_TO_DWORD(D.0);\n\tD := SHR(D, 1);\nEND_FOR;\nREFLECT := REFLECT OR SHL(D, L);\n\n(* revision history\nhm\t 16. jan 2011\n\tnew module\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "REFRACTION.st", - "source": "FUNCTION REFRACTION : REAL\nVAR_INPUT\n\tELEV : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t7. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nREFRACTION calculates the atmospheric refraction in degrees.\nthe input angle goes from 0 at the hirizon to 90 at midday.\n\n*)\n\nelev := LIMIT(-1.9, elev, 80.0);\nREFRACTION := 0.0174532925199433 / TAN(0.0174532925199433 * (ELEV + 10.3 / (ELEV + 5.11)));\n\n\n(* revision histroy\nhm\t14. jul. 2008\trev 1.0\n\toriginal release\n\nhm\t7. mar. 2009\trev 1.1\n\tusing new formula\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "REPLACE_ALL.st", - "source": "FUNCTION REPLACE_ALL : STRING(STRING_LENGTH)\nVAR_INPUT\n\tstr : STRING(STRING_LENGTH);\n\tsrc : STRING(STRING_LENGTH);\n\trep : STRING(STRING_LENGTH);\nEND_VAR\nVAR\n\tpos: INT;\n\tlp : INT;\n\tlx : INT;\nEND_VAR\n\n(*\nversion 1.1\t29. mar. 2008\nprogrammer \thugo\ntested by\ttobias\n\nthe function replace_all replaces all occurences of src in str and replaces them by rep.\n\n*)\n\nREPLACE_ALL := str;\nlx := LEN(src);\nlp := LEN(rep);\npos := FINDP(REPLACE_ALL, src, 1);\nWHILE pos > 0 DO\n\tREPLACE_ALL := REPLACE(REPLACE_ALL,rep,lx, pos);\n\tpos := FINDP(REPLACE_ALL, src, pos + lp);\nEND_WHILE;\n\n(* revision histroy\nhm\t4. feb. 2008\trev 1.0\n\toriginal release\n\nhm\t29. mar. 2008\trev 1.1\n\tchanged STRING to STRING(STRING_LENGTH)\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "REPLACE_CHARS.st", - "source": "FUNCTION REPLACE_CHARS : STRING(STRING_LENGTH)\nVAR_INPUT\n\tSTR : STRING(STRING_LENGTH);\n\tSRC : STRING;\n\tREP : STRING;\nEND_VAR\nVAR\n\ta, b : INT;\n\tc: STRING(1);\n\tstp: INT;\nEND_VAR\n\n(*\nversion 1.0\t\t14. may. 2008\nprogrammer \t\thugo\ntested by\t\t\thugo\n\nREPLACE_CHARS erstezt alle character die im string src aufgeführt sind mit dem an der selben stelle im string rep gelisteten character.\n\n*)\n\nREPLACE_CHARS := STR;\n(* make sure rep and src are of same length and length is > 0 *)\na := LEN(src);\nb := LEN(rep);\nIF a < b THEN\n\trep := LEFT(rep, a);\nELSIF b < a THEN\n\tsrc := LEFT(src, b);\nEND_IF;\n\n(* search the string and replace if necessary *)\nstp := LEN(str);\nFOR a := 1 TO stp DO\n\tc := MID(REPLACE_CHARS, 1, a);\n\tb := FIND(src, c);\n\tIF b > 0 THEN\n\t\tREPLACE_CHARS := REPLACE(REPLACE_CHARS, MID(rep, 1, b), 1, a);\n\tEND_IF;\nEND_FOR;\n\n\n\n(* revision history\nhm\t14. may. 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "REPLACE_UML.st", - "source": "FUNCTION REPLACE_UML : STRING(STRING_LENGTH)\nVAR_INPUT\n\tstr : STRING(STRING_LENGTH);\nEND_VAR\nVAR\n\tL : INT;\n\tpt : POINTER TO BYTE;\n\tpto : POINTER TO BYTE;\n\tptm : POINTER TO BYTE;\n\tpt1, pt2 : POINTER TO BYTE;\n\tsu : STRING(2);\n\tpos : INT;\nEND_VAR\n\n(*\nversion 1.1\t29. mar. 2008\nprogrammer \t\tkurt\ntested by\t\thugo\n\nREPLACE_UML replaces all occurences of Ä,Ö,Ü and ä,ö,ü,ß with Ae, ae, Oe, oe, Ue, ue and ss.\n\n*)\n\nPT := ADR(str);\npto := ADR(REPLACE_UML);\nptm := pto + INT_TO_DWORD(string_length);\npt1 := ADR(su);\npt2 := pt1 + 1;\nL := LEN(str);\nWHILE pos < L AND pos < string_length DO\n\tIF pt^ < 127 THEN\n\t\t(* no uml character simlply copy the character*)\n\t\tpto^ := pt^;\n\tELSE\n\t\t(* convert the uml character *)\n\t\tsu := TO_UML(pt^);\n\t\t(* we must make sure pointer are not out of range *)\n\t\tpto^ := pt1^;\n\t\tIF pto < ptm AND pt2^ > 0 THEN\n\t\t\tpto := pto + 1;\n\t\t\tpto^ := pt2^;\n\t\tEND_IF;\n\tEND_IF;\n\t(* increment pointers *)\n\tpt := pt + 1;\n\tpto := pto + 1;\n\tpos := pos + 1;\nEND_WHILE;\n\n(* properly close the output string *)\npto^ := 0;\n\n\n(* revision history\nhm\t29. feb 2008\trev 1.0\n\toriginal version\n\nhm\t29. mar. 2008\trev 1.1\n\tchanged STRING to STRING(STRING_LENGTH)\n\tnew code to avoid pointer out of range\n\tuse new function to_uml\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "RES_NI.st", - "source": "FUNCTION RES_NI : REAL\nVAR_INPUT\n\tT : REAL;\n\tR0 : REAL;\nEND_VAR\nVAR CONSTANT\n\tA : REAL := 0.5485;\n\tB : REAL := 0.665E-3;\n\tC : REAL := 2.805E-9;\nEND_VAR\nVAR\n\tT2: REAL;\nEND_VAR\n\n(*\nversion 1.2\t2 dec 2007\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function returs the resistance for a nickel sensor for a temperature range from -60..+180 °C *)\n\nT2 := T * T;\nRES_NI := R0 + A * T + B * T2 + C * T2 * T2;\n\n(* revision history\n\nhm\t4.8.2006\t\trev 1.0\n\toriginal version\n\nhm\t13.9.2007\t\trev 1.1\n\tchanged coding for better performance\n\nhm\t2. dec. 2007\trev 1.2\n\tchanged code for better performance\n*)\n\n(*\n\n Auszug aus DIN 43760 für Ni100\n\n°C\t\tR\t\t°C\t\tR\t\t°C\tR\t\t°C\t\tR\t\t°C\t\tR\n\n-60 \t69,5 \t-10 \t94,6 \t40 \t123,0 \t90 \t\t154,9 \t140 \t190,9\n-55 \t71,9 \t-5 \t\t97,3 \t45 \t126,0 \t95 \t\t158,3 \t145 \t194,8\n-50 \t74,3 \t0 \t\t100,0 \t50 \t129,1 \t100 \t161,8 \t150 \t198,7\n-45 \t76,7 \t5 \t\t102,8 \t55 \t132,2 \t105 \t165,3 \t155 \t202,6\n-40 \t79,1 \t10 \t\t105,6 \t60 \t135,3 \t110 \t168,8 \t160 \t206,6\n-35 \t81,6 \t15 \t\t108,4 \t65 \t138,5 \t115 \t172,4 \t165 \t210,7\n-30 \t84,2 \t20 \t\t111,2 \t70 \t141,7 \t120 \t176,0 \t170 \t214,8\n-25 \t86,7 \t25 \t\t114,1 \t75 \t145,0 \t125 \t179,6 \t175 \t219,0\n-20 \t89,3 \t30 \t\t117,1 \t80 \t148,3 \t130 \t183,3 \t180 \t223,2\n-15 \t91,9 \t35 \t\t120,0 \t85 \t151,6 \t135 \t187,1 \t \t \n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "RES_NTC.st", - "source": "FUNCTION RES_NTC : REAL\nVAR_INPUT\n\tT : REAL;\n\tRN : REAL;\n\tB : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t11. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function returs the resistance for a NTC sensor for a given temperature in °C.\nRN is the resistance at 25 °C and B is a constant for the given sensor.\n\n*)\n\nRES_NTC := RN * EXP(B * (1.0 / (T+273.15) - 0.00335401643468053));\n\n\n\n(* revision history\n\nhm 30. dec. 2008\trev 1.0\n\toriginal version\n\nhm\t11. mar. 2009\trev 1.1\n\tchanged real constants to use dot syntax\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "RES_PT.st", - "source": "FUNCTION RES_PT : REAL\nVAR_INPUT\n\tT : REAL;\n\tR0 : REAL;\nEND_VAR\nVAR CONSTANT\n\tA : REAL := 3.90802E-3 ;\n\tB : REAL := -5.802E-7;\n\tC : REAL := -4.27350E-12;\nEND_VAR\nVAR\n\tT2: REAL;\nEND_VAR\n\n(*\nversion 1.3\t11. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\n\nthis function returs the resistance for a platinum sensor for a temperature range from -200..+850 °C *)\n\nT2 := T * T;\n\nIF T >= 0.0 THEN\n\tRES_PT := R0 * ( 1.0 + A * T + B * T2);\nELSE\n\tRES_PT := R0 * ( 1.0 + A * T + B * T2 + C * (T - 100.0) * T2 * T);\nEND_IF;\n\n\n\n(* revision history\nhm\t4. aug. 2006\trev 1.1\n\toriginal version\n\nhm\t2. dec 2007\trev 1.2\n\tchanged code for better performance\n\nhm\t11. mar. 2009\trev 1.3\n\tchanged real constants to use dot syntax\n\n*)\n\n\n(*\n Auszug aus DIN 43760 für Pt100\n\n°C\t\tR\t\t°C\t\tR\t\t°C\tR\t\t\t°C\t\tR\t\t\t°C\t\tR\t\t\t°C\t\tR\n\n-200 \t18,49 \t-100 \t60,25 \t0 \t100,00 \t100 \t138,50 \t200 \t175,84 \t300 \t212,02\n-195 \t20,65 \t-95 \t62,28 \t5 \t101,95 \t105 \t140,39 \t205 \t177,68 \t305 \t213,80\n-190 \t22,80 \t-90 \t64,30 \t10 \t103,90 \t110 \t142,29 \t210 \t179,51 \t310 \t215,57\n-185 \t24,94 \t-85 \t66,31 \t15 \t105,85 \t115 \t144,17 \t215 \t181,34 \t315 \t217,35\n-180 \t27,08 \t-80 \t68,33 \t20 \t107,79 \t120 \t146,06 \t220 \t183,17 \t320 \t219,12\n-175 \t29,20 \t-75 \t70,33 \t25 \t109,73 \t125 \t147,94 \t225 \t184,99 \t325 \t220,88\n-170 \t31,32 \t-70 \t72,33 \t30 \t111,67 \t130 \t149,82 \t230 \t186,82 \t330 \t222,65\n-165 \t33,43 \t-65 \t74,33 \t35 \t113,61 \t135 \t151,70 \t235 \t188,63 \t335 \t224,41\n-160 \t35,33 \t-60 \t76,33 \t40 \t115,54 \t140 \t153,58 \t240 \t190,45 \t340 \t226,17\n-155 \t37,63 \t-55 \t78,32 \t45 \t117,47 \t145 \t155,45 \t245 \t192,26 \t345 \t227,92\n-150 \t39,71 \t-50 \t80,31 \t50 \t119,40 \t150 \t157,31 \t250 \t194,07 \t350 \t229,67\n-145 \t41,79 \t-45 \t82,29 \t55 \t121,32 \t155 \t159,18 \t255 \t195,88 \t355 \t231,42\n-140 \t43,87 \t-40 \t84,27 \t60 \t123,24 \t160 \t161,04 \t260 \t197,69 \t360 \t233,17\n-135 \t45,94 \t-35 \t86,25 \t65 \t125,16 \t165 \t162,90 \t265 \t199,49 \t365 \t234,91\n-130 \t48,00 \t-30 \t88,22 \t70 \t127,07 \t170 \t164,76 \t270 \t201,29 \t370 \t236,65\n-125 \t50,06 \t-25 \t90,19 \t75 \t128,98 \t175 \t166,61 \t275 \t203,08 \t375 \t238,39\n-120 \t52,11 \t-20 \t92,16 \t80 \t130,89 \t180 \t168,46 \t280 \t204,88 \t380 \t240,13\n-115 \t54,15 \t-15 \t94,12 \t85 \t132,80 \t185 \t170,31 \t285 \t206,67 \t385 \t241,86\n-110 \t56,19 \t-10 \t96,09 \t90 \t134,70 \t190 \t172,16 \t290 \t208,45 \t390 \t243,59\n-105 \t58,22 \t-5 \t\t98,04 \t95 \t136,60 \t195 \t174,00 \t295 \t210,24 \t395 \t245,31\n\n*)\n(*\nrevision history\n\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "RES_SI.st", - "source": "FUNCTION RES_SI : REAL\nVAR_INPUT\n\tT : REAL;\n\tRS : REAL;\n\tTS : REAL;\nEND_VAR\nVAR CONSTANT\n\tA : REAL := 7.64E-3;\n\tB : REAL := 1.66E-5;\nEND_VAR\nVAR\n\tTX: REAL;\nEND_VAR\n\n(*\nversion 1.2\t11. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function returs the resistance for a silicon sensor for a temperature range from -50..+150 °C\nfor example KTY10 normaly Rs at 25 °C\n*)\n\nTX := T - TS;\nRES_SI := RS * ( 1.0 + A * TX + B * TX * TX);\n\n(* revision history\nhm\t4. aug 2006\trev 1.0\n\toriginal version\n\nhm\t2. dec 2007\trev 1.1\n\tchanged code for better performance\n\nhm\t11. mar. 2009\trev 1.2\n\tchanged real constants to use dot syntax\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "REVERSE.st", - "source": "FUNCTION REVERSE : BYTE\nVAR_INPUT\n\tIN : BYTE;\nEND_VAR\n\n\n(*\n\tversion 1.2\t3. feb 2021\n\tprogrammer \thugo\n\ttested BY\t\ttobias\n\nThis function reverses the bits of a byte so that after execution bit 7 is at bit 0 location and so forth.\n\n*)\n\n(* new code donated by rebler wolfgang *)\nREVERSE := ROR(in,1) AND 2#10001000 OR ROL(in,1) AND 2#00010001 OR ROR(in,3) AND 2#01000100 OR ROL(in,3) AND 2#00100010;\n\n(* old code\nREVERSE := SHL(in,7) OR SHR(in,7) OR (ROR(in,3) AND 2#01000100) OR (ROL(in,3) AND 2#00100010)\n\tOR (SHL(in,1) AND 2#00010000) OR (SHR(in,1) AND 2#00001000);\n*)\n\n(* revision history\nhm\t\t9.oct 2007\t\trev 1.0\n\toriginal version\n\nhm\t\t18. feb 2008\trev 1.1\n\timproved performance\n\nRW 3. feb. 2021 \trev 1.2\n\timproved performance\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "RMP_B.st", - "source": "FUNCTION_BLOCK RMP_B\nVAR_INPUT\n\tSET : BOOL;\n\tPT : TIME;\n\tE : BOOL := TRUE;\n\tUP : BOOL := TRUE;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tOUT : BYTE;\n\tBUSY: BOOL;\n\tHIGH : BOOL;\n\tLOW : BOOL;\nEND_VAR\nVAR\n\trmp : _RMP_B;\nEND_VAR\n\n\n(*\nversion 2.0\t23. oct. 2008\nprogrammer \toscat\ntested BY\toscat\n\nthis ramp generator generates a byte wide ramp with 255 steps\nthe generator has an asynchronous set and reset\nthe ramp is controlled by PT which is the total ramp time for a full sweep from 0..255\nan UD input controlls the direction Up or Down and the E input enables the ramp generation\na busy output indicates that the ramp is running, busy false means output is stable.\nthe outputs low and high will be true when the output has reached its max or min value.\n\n*)\n\n(* generate ramp *)\nrmp(dir := UP, E := E, TR := PT, rmp := out);\n\n(* set or reset operation *)\nIF RST THEN\n\tout := 0;\nELSIF SET THEN\n\tout := 255;\nEND_IF;\n\n(* checks for outputs stable and reset or set busy flag *)\nlow := out = 0;\nhigh := out = 255;\nbusy := NOT (low OR high) AND E;\n\n\n(* revision history\n\nhm 5.10.2006\trev 1.1\n\tadded busy output\nhm 17.1.2007\trev 1.2\n\trenamed input ud to up for better usability\n\tdeleted unused variable step\n\nhm\t17.9.2007\t\trev 1.3\n\treplaced time() with t_plc_ms() for compatibility reasons\n\nhm\t28. sep 2007\trev 1.4\n\tadded outputs on and off\n\tbusy is now disabled while en is false\n\tnew coding for higher accuracy and performance\n\nhm\t5. oct 2007\trev 1.5\n\tadded statements to allow for PT to be t#0s output jumps to max or min immediately\n\nhm\t25. dec 2007\trev 1.6\n\timproved code for better performance\n\nhm\t16. oct. 2008\trev 1.7\n\timproved code for better performance\n\nhm\t18. oct. 2008\trev 1.8\n\tadded type conversion to avoid warnings\n\tchanged input en to e for compatibility reasons\n\nhm\t23. oct. 2008\tREV \t2.0\n\tnew code using _RMP_B\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "RMP_SOFT.st", - "source": "FUNCTION_BLOCK RMP_SOFT\nVAR_INPUT\n\tIN : BOOL;\n\tVAL : BYTE;\nEND_VAR\nVAR_INPUT CONSTANT\n\tPT_ON: TIME;\n\tPT_OFF : TIME;\nEND_VAR\nVAR_OUTPUT\n\tOUT : BYTE;\nEND_VAR\nVAR\n\trmp : _RMP_B;\n\ttmp: BYTE;\nEND_VAR\n\n(*\nversion 2.0\t26. oct. 2008\nprogrammer \toscat\ntested BY\t\toscat\n\nthis soft on/off ramp generator generates a soft on and soft off ramp while the max on value is set by the input\nthe time for a full ramp can be set by config variables for up and down ramp.\n\n*)\n\ntmp := SEL(in, 0, val);\nIF tmp > out THEN\n\t(* we need to ramp down *)\n\trmp(dir := TRUE, E := TRUE, TR := PT_ON, rmp := out);\n\t(* make sure out does not surpass tmp *)\n\tout := MIN(out, tmp);\nELSIF tmp < out THEN\n\t(* we need to ramp up *)\n\trmp(dir := FALSE, E := TRUE, TR := PT_OFF, rmp := out);\n\t(* make sure out does not surpass tmp *)\n\tout := MAX(out, tmp);\nELSE\n\t(* no ramp necessary *)\n\trmp(E := FALSE, rmp := out);\nEND_IF;\n\n\n(* revision history\n\nhm 22.1.2007\trev 1.1\n\tdeleted unused variables X1 and I, X2 and X3\n\nhm\t17.9.2007\trev 1.2\n\treplaced time() with t_plc_ms() for compatibility reasons\n\nhm\t26. oct. 2008\t2.0\n\tnew code using _rmp_b\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "RMP_W.st", - "source": "FUNCTION_BLOCK RMP_W\nVAR_INPUT\n\tSET : BOOL;\n\tPT : TIME;\n\tE : BOOL := TRUE;\n\tUP : BOOL := TRUE;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tout : WORD;\n\tbusy : BOOL;\n\thigh : BOOL;\n\tlow : BOOL;\nEND_VAR\nVAR\n\trmp : _RMP_W;\nEND_VAR\n\n(*\nversion 2.0\t23. oct. 2008\nprogrammer \toscat\ntested BY\toscat\n\nthis ramp generator generates a Word wide ramp with 65535 steps\nthe generator has an asynchronous set and reset\nthe ramp is controlled by PT which is the total ramp time for a full sweep from 0..65535\nan UD input controlls the direction Up or Down and the E input enables the ramp generation\na busy output indicates that the ramp is running, busy false means output is stable.\nthe outputs low and high will be true when the output has reached its max or min value.\n*)\n\n(* generate ramp *)\nrmp(dir := UP, E := E, TR := PT, rmp := out);\n\n(* set or reset operation *)\nIF RST THEN\n\tout := 0;\nELSIF SET THEN\n\tout := 65535;\nEND_IF;\n\n(* checks for outputs stable and reset or set busy flag *)\nlow := out = 0;\nhigh := out = 65535;\nbusy := NOT (low OR high) AND E;\n\n\n(* revision history:\n\nhm 4.10.2006\t\trev 1.1\n\tadded the busy output which signals that the ramp is running.\n\nhm 22.1.2007\t\trev 1.2\n\tdeleted unused variable step\n\nhm\t17.9.2007\t\trev 1.3\n\treplaced time() with t_plc_ms() for compatibility reasons\n\nhm\t28. sep 2007\trev 1.4\n\tadded outputs on and off\n\tbusy is now disabled while en is false\n\tnew coding for higher accuracy and performance\n\nhm\t5. oct 2007\trev 1.5\n\tadded statements to allow for PT to be t#0s output jumps to max or min immediately\n\nhm\t2. dec 2007\trev 1.6\n\tcorrected an error in calculation of step response\n\nhm\t25. dec 2007\trev 1.7\n\tcorrected an error while step response was too slow for fast rise times\n\nhm\t16. oct. 2008\trev 1.8\n\timproved performance\n\nhm\t18. oct. 2008\trev 1.9\n\trenamed inout EN to E for compatibility reasons\n\nhm\t23. oct. 2008\trev 2.0\n\tnew code using _RMP_W\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "RND.st", - "source": "FUNCTION RND : REAL\nVAR_INPUT\n\tX : REAL;\n\tN : INT;\nEND_VAR\nVAR\n\tM : REAL;\nEND_VAR\n\n(*\nversion 1.2\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function rounds a real down to n digits total.\nround(3.1415,2) = 3.1\n\n*)\n\nIF X = 0.0 THEN\n\tRND := 0.0;\nELSE\n\tM := EXPN(10.0,N - CEIL(LOG(ABS(X))));\n\tRND := DINT_TO_REAL(REAL_TO_DINT(X * M)) / M;\nEND_IF;\n\n\n(* revision history\nhm\t11. mar 2008\trev 1.0\n\toriginal version\n\nhm\t26. oct. 2008\trev 1.1\n\tcode optimization\n\nhm\t10. mar. 2009\trev 1.2\n\treal constants updated to new systax using dot\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "ROUND.st", - "source": "FUNCTION ROUND : REAL\nVAR_INPUT\n\tin : REAL;\n\tN : INT;\nEND_VAR\nVAR\n\tX: REAL;\nEND_VAR\n\n\n(*\nversion 1.5\t25. oct. 2008\nprogrammer \thugo\ntested by\ttobias\n\nthis function rounds a real down to n digits behind the comma.\n\n\n*)\n\nX := setup.DECADES[LIMIT(0,N,8)];\nROUND := DINT_TO_REAL(REAL_TO_DINT(in * X)) / X;\n\n\n\n(* revision history\nhm\t1. sep 2006\trev 1.0\n\toriginal version\n\nhm\t2. dec 2007\trev 1.1\n\tchanged code for better performance\n\nhm\t8. jan 2008\trev 1.2\n\tfurther improvement in performance\n\nhm 11. mar. 2008\trev 1.3\n\tcorrected an error with negative numbers\n\tuse real_to_dint instead of trunc\n\nhm\t16. mar 2008\trev 1.4\n\tadded type conversion to avoid warning under codesys 3.0\n\nhm\t25. oct. 2008\trev 1.5\n\tnew code using global constants decades\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "RTC_2.st", - "source": "FUNCTION_BLOCK RTC_2\nVAR_INPUT\n\tSET : BOOL;\n\tSDT : DT;\n\tSMS : INT;\n\tDEN : BOOL;\n\tOFS : INT;\nEND_VAR\nVAR_OUTPUT\n\tUDT : DT;\n\tLOCAL_DT : DT;\n\tDSO : BOOL;\n\tXMS : INT;\nEND_VAR\nVAR\n\tRT : RTC_MS;\nEND_VAR\n\n(*\nversion 1.5\t3. Feb. 2021\nprogrammer \thugo\ntested by\t\ttobias\n\nRTC_2 is a real time clock module which runs utc and generates local time from utc.\ndaylight savings time can be enabled with den and an additional local time is generated with a delay of ofs im minutes.\n\n*)\n\n(* call rtc *)\nRT(SET := SET, SDT := SDT, SMS := SMS);\nUDT := rt.xdt;\nXMS := rt.XMS;\n\n(* check for daylight savings time and set dso output *)\nDSO := DST(udt) AND DEN;\n\n(* calculate time offset and set ldt output *)\nLOCAL_DT := DWORD_TO_DT(DT_TO_DWORD(UDT) + INT_TO_DWORD(ofs + BOOL_TO_INT(DSO)*60) * 60);\n\n\n(* revision history\nhm\t\t20. jan. 2008\trev 1.0\n\toriginal version\n\nhm\t\t20. feb. 2008\trev 1.1\n\tadded Millisecond Set input\n\nhm\t\t12. jun. 2008\trev 1.2\n\timproved performance\n\nhm\t\t20. jan. 2011\trev 1.3\n\tchanged offset to be in minutes\n\nhm\t\t27. apr. 2011\trev 1.4\n\tfixed error with local time calculation\n\nhm 3. Feb 2021 rev 1.5\n changed LDT to LOCAL_DT for compatibility with IEC61131-3\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "RTC_MS.st", - "source": "FUNCTION_BLOCK RTC_MS\nVAR_INPUT\n\tSET : BOOL;\n\tSDT : DT;\n\tSMS : INT;\nEND_VAR\nVAR_OUTPUT\n\tXDT : DT;\n\tXMS : INT;\nEND_VAR\nVAR\n\tinit: BOOL;\n\tlast: DWORD;\n\tTx: DWORD;\nEND_VAR\n\n(*\nversion 1.1\t20. feb. 2008\nprogrammer \thugo\ntested by\ttobias\n\nRTC_MS is a real time clock module which can be set to SDT when set is TRUE and the outputs XDT and XT present the DateTime and TOD with a resolution of milliseconds.\n\n*)\n\ntx := T_PLC_MS();\nIF set OR NOT init THEN\n\t(* clock needs to be set when set is true or after power up *)\n\tinit := TRUE;\n\txdt := SDT;\n\tXMS := SMS;\nELSE\n\tXMS := XMS + DWORD_TO_INT(tx - last);\n\t(* check if one second has expired *)\n\tIF XMS > 999 THEN\n\t\tXDT := XDT + T#1s;\n\t\tXMS := XMS - 1000;\n\tEND_IF;\nEND_IF;\nlast := tx;\n\n\n(* revision history\nhm\t\t20. jan. 2008\trev 1.0\n\toriginal version\n\nhm\t\t20. feb. 2008\trev 1.1\n\tadded Millisecond Set input\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "SCALE.st", - "source": "FUNCTION SCALE : REAL\nVAR_INPUT\n\tX : REAL;\n\tK : REAL;\n\tO : REAL;\n\tMX : REAL;\n\tMN : REAL;\nEND_VAR\n\n\n(*\nversion 1.0\t16. may. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nScale is used to translate an input x to output by the formula Y = X*K + O.\nat the same time the output is limited to MN and MX.\n\n*)\n\nSCALE := LIMIT(MN, X * K + O, MX);\n\n\n(* revision history\nhm\t16. may. 2008\t\trev 1.0\n\toriginal version\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "SCALE_B.st", - "source": "FUNCTION SCALE_B : REAL\nVAR_INPUT\n\tX : BYTE;\n\tI_LO : BYTE;\n\tI_HI : BYTE;\n\tO_LO : REAL;\n\tO_HI : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t18. jan. 2011\nprogrammer \thugo\ntested by\t\ttobias\n\nScale_B is used to translate and scale a byte input x to a real output.\n\n*)\n\nIF I_HI = I_LO THEN\n\tSCALE_B := O_LO;\nELSE\n\tSCALE_B := (O_HI - O_LO) / BYTE_TO_REAL(I_HI - I_LO) * BYTE_TO_REAL(LIMIT(I_LO, X, I_HI));\nEND_IF\n\n(* revision history\nhm\t18. may. 2008\t\trev 1.0\n\toriginal version\n\nhm\t18. jan 2011\t\trev 1.1\n\tavoid division by 0\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "SCALE_B2.st", - "source": "FUNCTION SCALE_B2 : REAL\nVAR_INPUT\n\tin1: BYTE;\n\tin2: BYTE;\n\tK : REAL;\n\tO : REAL;\nEND_VAR\nVAR_INPUT CONSTANT\n\tin1_min: REAL;\n\tin1_max: REAL := 1000.0;\n\tin2_min: REAL;\n\tin2_max: REAL := 1000.0;\nEND_VAR\n\n(*\nversion 1.4\t3. nov. 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function block can scale up to two inputs.\ninputs have their min value at 0 and their max value at 255 while the min and max value can be either positive or negative.\ninputs ramp between min and max values for the respective inputs to be between (0..255).\nthe summed output is then scaled by an scale input K and a offset O can be added to the output.\nmin and max input configurations can be edited in the cfc editor by double clicking the symbol body.\n\n*)\n\nSCALE_B2 := \t(((in1_max - in1_min)* in1 + (in2_max - in2_min)* in2) * 0.003921569 + in1_min + in2_min) * K + O;\n\n\n(* revision History\nhm 19.1.2007\t\trev 1.1\n\tchanged outputs to real to avoid overflow of integer\n\tadded offset for better cascading of scale functions\n\tchanged from FB to function\n\nhm\t6. jan 2008\t\trev 1.2\n\timproved performance\n\nhm\t26. oct. 2008\trev 1.3\n\tcode optimization\n\nhm\t3. nov. 2008\trev 1.4\n\tused wrong factor in formula\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "SCALE_B4.st", - "source": "FUNCTION SCALE_B4 : REAL\nVAR_INPUT\n\tin1: BYTE;\n\tin2: BYTE;\n\tin3: BYTE;\n\tin4: BYTE;\n\tK : REAL;\n\tO : REAL;\nEND_VAR\nVAR_INPUT CONSTANT\n\tin1_min: REAL;\n\tin1_max: REAL := 1000.0;\n\tin2_min: REAL;\n\tin2_max: REAL := 1000.0;\n\tin3_min: REAL;\n\tin3_max: REAL := 1000.0;\n\tin4_min: REAL;\n\tin4_max: REAL := 1000.0;\nEND_VAR\n\n(*\nversion 1.4\t3. nov. 2008\nprogrammer \thugo\ntested by\ttobias\n\n\tthis functiob block can scale up to 4 inputs.\n\tthe inputs have their min value at 0 and their max value at 255 while the min and max value can be either positive or negative.\n\tthe inputs ramp between min and max values for the respective inputs to be between (0..255).\n\tthe summed output is then scaled by an scale input K and a offset O can be added to the output.\n\tthe min and max input configurations can be edited in the cfc editor by double clicking the symbol body.\n\n*)\n\nSCALE_B4 := \t(((in1_max - in1_min)* in1 + (in2_max - in2_min)* in2 + (in3_max - in3_min)* in3 + (in4_max - in4_min)* in4)* 0.003921569 + in1_min + in2_min + in3_min + in4_min) * K + O;\n\n\n(* revision History\nhm 19.1.2007\t\trev 1.1\n\tchanged outputs to real to avoid overflow of integer\n\tadded offset for better cascading of scale functions\n\tchanged from fb to function\n\nhm\t6. jan 2008\t\trev 1.2\n\timproved performance\n\nhm\t26. oct. 2008\trev 1.3\n\toptimized code\n\nhm\t3. nov. 2008\trev 1.4\n\tused wrong factor in formula\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "SCALE_B8.st", - "source": "FUNCTION SCALE_B8 : REAL\nVAR_INPUT\n\tin1: BYTE;\n\tin2: BYTE;\n\tin3: BYTE;\n\tin4: BYTE;\n\tin5: BYTE;\n\tin6: BYTE;\n\tin7: BYTE;\n\tin8: BYTE;\n\tK : REAL;\n\tO : REAL;\nEND_VAR\nVAR_INPUT CONSTANT\n\tin1_min: REAL;\n\tin1_max: REAL := 1000.0;\n\tin2_min: REAL;\n\tin2_max: REAL := 1000.0;\n\tin3_min: REAL;\n\tin3_max: REAL := 1000.0;\n\tin4_min: REAL;\n\tin4_max: REAL := 1000.0;\n\tin5_min: REAL;\n\tin5_max: REAL := 1000.0;\n\tin6_min: REAL;\n\tin6_max: REAL := 1000.0;\n\tin7_min: REAL;\n\tin7_max: REAL := 1000.0;\n\tin8_min: REAL;\n\tin8_max: REAL := 1000.0;\nEND_VAR\n\n(*\nversion 1.4\t3. nov. 2008\nprogrammer \thugo\ntested by\toscat\n\nthis functiob block can scale up to 8 inputs.\nthe inputs have their min value at 0 and their max value at 255 while the min and max value can be either positive or negative.\nthe inputs ramp between min and max values for the respective inputs to be between (0..255).\nthe summed output is then scaled by an scale input K and a offset O can be added to the output.\nthe min and max input configurations can be edited in the cfc editor by double clicking the symbol body.\n\n*)\n\nSCALE_B8 := \t(((in1_max - in1_min)* in1 + (in2_max - in2_min)* in2 + (in3_max - in3_min)* in3 + (in4_max - in4_min)* in4 +\n\t\t\t\t(in5_max - in5_min)* in5 + (in6_max - in6_min)* in6 + (in7_max - in7_min)* in7 + (in8_max - in8_min)* in8) * 0.003921569\n\t\t\t\t + in1_min + in2_min + in3_min + in4_min + in5_min + in6_min + in7_min + in8_min) * K + O;\n\n\n(* revision History\nhm\t19. jan.2007\trev 1.1\n\tchanged outputs to real to avoid overflow of integer\n\tadded offset for better cascading of scale functions\n\nhm\t6. jan. 2008\trev 1.2\n\timproved performance\n\nhm\t26. oct. 2008\trev 1.3\n\tcode optimization\n\nhm\t3. nov. 2008\trev 1.4\n\tused wrong factor in formula\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "SCALE_D.st", - "source": "FUNCTION SCALE_D : REAL\nVAR_INPUT\n\tX : DWORD;\n\tI_LO : DWORD;\n\tI_HI : DWORD;\n\tO_LO : REAL;\n\tO_HI : REAL;\nEND_VAR\n\n\n(*\nversion 1.2\t11. jan. 2011\nprogrammer \thugo\ntested by\t\toscat\n\nScale_D is used to translate and scale a DWORD input x to a real output.\nthe input is limited to I_LO <= X <= I_HI.\n\n*)\n\nIF I_HI = I_LO THEN\n\tSCALE_D := O_LO;\nELSE\n\tSCALE_D := (O_HI - O_LO) / DWORD_TO_REAL(I_HI - I_LO) * DWORD_TO_REAL(LIMIT(I_LO, X, I_HI) - I_LO) + O_LO;\nEND_IF;\n\n(* revision history\nhm\t18. may. 2008\trev 1.0\n\toriginal version\n\nhm\t13. nov. 2008\trev 1.1\n\tcorrected formula for negative gradient\n\nhm\t11. jan 2011\trev 1.2\n\tavoid division by 0\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "SCALE_R.st", - "source": "FUNCTION SCALE_R : REAL\nVAR_INPUT\n\tX : REAL;\n\tI_LO : REAL;\n\tI_HI : REAL;\n\tO_LO : REAL;\n\tO_HI : REAL;\nEND_VAR\n\n\n(*\nversion 1.2\t11. jan. 2011\nprogrammer \thugo\ntested by\t\toscat\n\nScale_R is used to translate and scale a REAL input x to a real output.\nthe input is limited to I_LO <= X <= I_HI.\n\n*)\n\nIF I_LO = I_HI THEN\n\tSCALE_R := O_LO;\nELSE\n\tSCALE_R := (O_HI - O_LO) / (I_HI - I_LO) * (LIMIT(I_LO, X, I_HI) - I_LO) + O_LO;\nEND_IF;\n\n\n(* revision history\nhm\t18. may. 2008\trev 1.0\n\toriginal version\n\nhm\t13. nov. 2008\trev 1.1\n\tcorrected formula for negative gradient\n\nhm\t11. jan 2011\trev 1.2\n\tavoid division by 0\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "SCALE_X2.st", - "source": "FUNCTION SCALE_X2 : REAL\nVAR_INPUT\n\tIN1: BOOL;\n\tIN2: BOOL;\n\tK : REAL;\n\tO : REAL;\nEND_VAR\nVAR_INPUT CONSTANT\n\tIN1_MIN: REAL;\n\tIN1_MAX: REAL := 1000.0;\n\tIN2_MIN: REAL;\n\tIN2_MAX: REAL := 1000.0;\nEND_VAR\n\n(*\nversion 1.1\t26. oct. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\n\tthis functiob block can scale up to two inputs.\n\tthe input can select between two values with true or false.\n\tthe summed output is then scaled by an scale input K and a offset O can be added to the output.\n\tthe min and max input configurations can be edited in the cfc editor by double clicking the symbol body.\n\n*)\n\nSCALE_X2 := (SEL(IN1, IN1_MIN, IN1_MAX)+ SEL(IN2, IN2_MIN, IN2_MAX)) * k + o;\n\n\n(* revision history\nhm\t19. jan, 2007\trev 1.0\n\toriginal version\n\nhm\t26. oct. 2008\trev 1.1\n\tcode optimized\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "SCALE_X4.st", - "source": "FUNCTION SCALE_X4 : REAL\nVAR_INPUT\n\tIN1: BOOL;\n\tIN2: BOOL;\n\tIN3: BOOL;\n\tIN4: BOOL;\n\tK : REAL;\n\tO : REAL;\nEND_VAR\nVAR_INPUT CONSTANT\n\tIN1_MIN: REAL;\n\tIN1_MAX: REAL := 1000.0;\n\tIN2_MIN: REAL;\n\tIN2_MAX: REAL := 1000.0;\n\tIN3_MIN: REAL;\n\tIN3_MAX: REAL := 1000.0;\n\tIN4_MIN: REAL;\n\tIN4_MAX: REAL := 1000.0;\nEND_VAR\n\n(*\nversion 1.1\t26. oct. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\n\tthis function can scale up to 4 inputs.\n\tthe input can select between two values with true or false.\n\tthe summed output is then scaled by an scale input K and a offset O can be added to the output.\n\tthe min and max input configurations can be edited in the cfc editor by double clicking the symbol body.\n\n*)\n\nSCALE_X4 := (SEL(IN1,IN1_MIN, IN1_MAX) + SEL(IN2, IN2_MIN, IN2_MAX)+SEL(IN3, IN3_MIN, IN3_MAX)+ SEL(IN4, IN4_MIN, IN4_MAX)) * k + o;\n\n\n(* revision history\nhm\t19. jan. 2008\trev 1.0\n\toriginal version\n\nhm\t26. oct. 2008\trev 1.1\n\toptimized code\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "SCALE_X8.st", - "source": "FUNCTION SCALE_X8 : REAL\nVAR_INPUT\n\tin1: BOOL;\n\tin2: BOOL;\n\tin3: BOOL;\n\tin4: BOOL;\n\tin5: BOOL;\n\tin6: BOOL;\n\tin7: BOOL;\n\tin8: BOOL;\n\tK : REAL;\n\tO : REAL;\nEND_VAR\nVAR_INPUT CONSTANT\n\tin1_min: REAL;\n\tin1_max: REAL := 1000.0;\n\tin2_min: REAL;\n\tin2_max: REAL := 1000.0;\n\tin3_min: REAL;\n\tin3_max: REAL := 1000.0;\n\tin4_min: REAL;\n\tin4_max: REAL := 1000.0;\n\tin5_min: REAL;\n\tin5_max: REAL := 1000.0;\n\tin6_min: REAL;\n\tin6_max: REAL := 1000.0;\n\tin7_min: REAL;\n\tin7_max: REAL := 1000.0;\n\tin8_min: REAL;\n\tin8_max: REAL := 1000.0;\nEND_VAR\n\n(*\nversion 1.2\t24. jan. 2009\nprogrammer \thugo\ntested by\toscat\n\nthis function can scale up to 4 inputs.\nthe input can select between two values with true or false.\nthe summed output is then scaled by an scale input K and a offset O can be added to the output.\nthe min and max input configurations can be edited in the cfc editor by double clicking the symbol body.\n\n*)\n\nSCALE_X8 := (SEL(IN1,IN1_MIN, IN1_MAX)+ SEL(IN2,IN2_MIN, IN2_MAX)+SEL(IN3,IN3_MIN, IN3_MAX)+ SEL(IN4,IN4_MIN, IN4_MAX)\n\t\t\t\t+SEL(IN5,IN5_MIN, IN5_MAX)+ SEL(IN6,IN6_MIN, IN6_MAX)+SEL(IN7,IN7_MIN, IN7_MAX)+ SEL(IN8,IN8_MIN, IN8_MAX)) * k + o;\n\n\n\n(* revision history\nhm\t19. jan. 2008\trev 1.0\n\toriginal version\n\nhm\t26. oct. 2008\trev 1.1\n\toptimized code\n\nhm\t24. jan. 2008\trev 1.2\n\tcorrected error in formula\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "SCHEDULER.st", - "source": "FUNCTION_BLOCK SCHEDULER\nVAR_INPUT\n\tE0 : BOOL;\n\tE1 : BOOL;\n\tE2 : BOOL;\n\tE3 : BOOL;\nEND_VAR\nVAR_INPUT CONSTANT\n\tT0, T1, T2, T3 : TIME;\nEND_VAR\nVAR_OUTPUT\n\tQ0, Q1, Q2, Q3 : BOOL;\nEND_VAR\nVAR\n\tinit : BOOL;\n\ts0, s1, s2, s3 : TIME;\n\ttx : TIME;\n\tc : INT;\nEND_VAR\n\n\n(*\nversion 1.1\t14. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nSCHEDULER is used to call programs or function blocks at specific intervals.\nT0..T3 defines the interval times.\n\n*)\n\n(* read system_time *)\ntx := DWORD_TO_TIME(T_PLC_MS());\n\nIF NOT init THEN\n\tinit := TRUE;\n\ts0 := tx - T0;\n\ts1 := tx - T1;\n\ts2 := tx - T2;\n\ts3 := tx - T3;\nEND_IF;\n\nQ0 := FALSE;\nQ1 := FALSE;\nQ2 := FALSE;\nQ3 :=FALSE;\n\nCASE c OF\n\t0: \tIF tx - s0 >= T0 THEN\n\t\t\tQ0 := E0;\n\t\t\ts0 := tx;\n\t\tEND_IF;\n\t\tc := 1;\n\t1: \tIF tx - s1 >= T1 THEN\n\t\t\tQ1 := E1;\n\t\t\ts1 := tx;\n\t\tEND_IF;\n\t\tc := 2;\n\t2: \tIF tx - s2 >= T2 THEN\n\t\t\tQ2 := E2;\n\t\t\ts2 := tx;\n\t\tEND_IF;\n\t\tc := 3;\n\t3: \tIF tx - s3 >= T3 THEN\n\t\t\tQ3 := E3;\n\t\t\ts3 := tx;\n\t\tEND_IF;\n\t\tc := 0;\nEND_CASE;\n\n\n(* revision history\n\nhm 28. sep. 2008\trev 1.0\n\toriginal version\n\nhm\t14. mar. 2009\trev 1.1\n\tremoved double assignments\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "SCHEDULER_2.st", - "source": "FUNCTION_BLOCK SCHEDULER_2\nVAR_INPUT\n\tE0 : BOOL;\n\tE1 : BOOL;\n\tE2 : BOOL;\n\tE3 : BOOL;\nEND_VAR\nVAR_INPUT CONSTANT\n\tC0, C1, C2, C3 : UINT;\n\tO0, O1, O2, O3 : UINT;\nEND_VAR\nVAR_OUTPUT\n\tQ0, Q1, Q2, Q3 : BOOL;\nEND_VAR\nVAR\n\tsx : UINT;\nEND_VAR\n\n\n(*\nversion 1.0\t29. sep 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nSCHEDULER_2 is used to call programs or function blocks at specific cycles.\nC0..C3 defines after how many cycles the output becomes active.\nO0..O3 defines a cycle offset at startup.\n\n*)\n\nQ0 := E0 AND (sx MOD C0 - O0 = 0);\nQ1 := E1 AND (sx MOD C1 - O1 = 0);\nQ2 := E2 AND (sx MOD C2 - O2 = 0);\nQ3 := E3 AND (sx MOD C3 - O3 = 0);\n\n(* increment cycle counter every cycle *)\nsx := sx + 1;\n\n\n(* revision history\nhm 29. sep. 2008\t\trev 1.0\n\toriginal version\n\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "SDT.st", - "source": "TYPE SDT :\nSTRUCT\n\tYEAR : INT;\n\tMONTH : INT;\n\tDAY : INT;\n\tWEEKDAY : INT;\n\tHOUR : INT;\n\tMINUTE : INT;\n\tSECOND : INT;\n\tMS : INT;\nEND_STRUCT\nEND_TYPE\n" - }, - { - "fileName": "SDT_TO_DATE.st", - "source": "FUNCTION SDT_TO_DATE : DATE\nVAR_INPUT\n\tDTI : SDT;\nEND_VAR\n\n\n(*\nversion 1.0\t18. oct 2008\nprogrammer \thugo\ntested by\toscat\n\nconverts Structured date time (SDT) to Date Time\n\n*)\n\nSDT_TO_DATE := SET_DATE(DTI.YEAR, DTI.MONTH, DTI.DAY);\n\n\n\n(* revision history\n\nhm 18. oct. 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "SDT_TO_DT.st", - "source": "FUNCTION SDT_TO_DT : DT\nVAR_INPUT\n\tDTI : SDT;\nEND_VAR\n\n\n(*\nversion 1.0\t18. oct 2008\nprogrammer \thugo\ntested by\toscat\n\nconverts Structured date time (SDT) to Date Time\n\n*)\n\nSDT_TO_DT := SET_DT(DTI.YEAR, DTI.MONTH, DTI.DAY, DTI.HOUR, DTI.MINUTE, DTI.SECOND);\n\n\n\n(* revision history\n\nhm 18. oct. 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "SDT_TO_TOD.st", - "source": "FUNCTION SDT_TO_TOD : TOD\nVAR_INPUT\n\tDTI : SDT;\nEND_VAR\n\n\n(*\nversion 1.1\t16. nov. 2008\nprogrammer \thugo\ntested by\toscat\n\nconverts Structured date time (SDT) to Date Time\n\n*)\n\nSDT_TO_TOD := DWORD_TO_TOD(INT_TO_DWORD(DTI.HOUR) * 3600000 + INT_TO_DWORD(DTI.MINUTE) * 60000 + INT_TO_DWORD(DTI.SECOND) * 1000 + INT_TO_DWORD(DTI.MS));\n\n\n\n(* revision history\n\nhm 18. oct. 2008\trev 1.0\n\toriginal version\n\nhm\t16. nov. 2008\trev 1.1\n\tadded typecasts to avoid warnings\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "SECOND.st", - "source": "FUNCTION SECOND : REAL\nVAR_INPUT\n\titod : TOD;\nEND_VAR\n\n\n(*\nversion 1.1\t2 oct 2006\nprogrammer \thugo\ntested by\toscat\n\nreturns the seconds and milliseconds as real of TOD \n \n*)\n\nSECOND := DWORD_TO_REAL(TOD_TO_DWORD(itod) - TOD_TO_DWORD(itod)/60000 * 60000) / 1000.0;\n\n\n\n(* change history\n\nhm\t2. oct. 2006 rev 1.1 \n\tchanged name of input to itod\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "SECOND_OF_DT.st", - "source": "FUNCTION SECOND_OF_DT : INT\nVAR_INPUT\n\tXDT : DT;\nEND_VAR\n\n\n(*\n\tversion 1.0\t6. jun. 2008\n\tprogrammer \toscat\n\ttested BY\toscat\n\nSECOND_OF_DT returns the current second (second of minute) of a DT variable\n\n*)\n\nSECOND_OF_DT := DWORD_TO_INT(DT_TO_DWORD(XDT) MOD 60);\n\n(* revision history\nhm\t\t6.9.2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "SECOND_TO_TIME.st", - "source": "FUNCTION SECOND_TO_TIME : TIME\nVAR_INPUT\n\tIN : REAL;\nEND_VAR\n\n\n(*\nversion 1.2\t24. feb. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nconverts an amount of seconds in real to time\nexecution TIME on wago 750-841 = 17us \n\n*)\n\nSECOND_TO_TIME := DWORD_TO_TIME(REAL_TO_DWORD(IN * 1000.0));\n\n(* revision history\nhm\t4. aug. 2006\trev 1.0\n\toriginal version\n\nhm\t14. mar. 2008\trev 1.1\n\trounded the input after the last digit\n\nhm\t24. feb. 2009\trev 1.2\n\tchanged input to IN\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "SEL2_OF_3.st", - "source": "FUNCTION_BLOCK SEL2_OF_3\nVAR_INPUT\n\tIN1 : REAL;\n\tIN2 : REAL;\n\tIN3 : REAL;\n\tD : REAL;\nEND_VAR\nVAR_OUTPUT\n\tY : REAL;\n\tW : INT;\n\tE : BOOL;\nEND_VAR\nVAR\n\tD12: BOOL;\n\tD23: BOOL;\n\tD31: BOOL;\nEND_VAR\n\n(*\n\tversion 1.1\t10. mar. 2009\n\tprogrammer \toscat\n\ttested BY\t\toscat\n\nSEL2_OF_3 checks if 3 input Signals are within a distance D from each other and calculates the average of the 3 inputs do not offset more than D from each other.\nIf 1 input is more than D greater or smaller than any other input it will be ignored and the average will be calcualted from the remaining 2 Inputs.\nIn the case the Output is only calculated from 2 Inputs a Warning Output W will display the Number of the discarded Input. if none of the 3 Inputs are within the allowed Delata D from each other, \nan Error Output E is set True and the last valid Output will remain active until at least 2 Inputs are within a valid Range from each other.\n\n*)\n\nD12 := ABS(IN1-IN2) <= D;\nD23 := ABS(IN2-IN3) <= D;\nD31 := ABS(IN3-IN1) <= D;\n\nIF (D12 AND D23) OR (D12 AND D31) OR (D23 AND D31) THEN\n\t(* all 3 inputs are valid *)\n\tY := (IN1 + IN2 + IN3) * 0.333333333333;\n\tE := FALSE;\n\tW := 0;\nELSIF D12 THEN\n\t(* only inut 1 and 2 are valid *)\n\tY := (In1 + IN2) * 0.5;\n\tE := FALSE;\n\tW := 3;\nELSIF D23 THEN\n\t(* only inut 2 and 3 are valid *)\n\tY := (In2 + IN3) * 0.5;\n\tE := FALSE;\n\tW := 1;\nELSIF D31 THEN\n\t(* only inut 3 and 1 are valid *)\n\tY := (In3 + IN1) * 0.5;\n\tE := FALSE;\n\tW := 2;\nELSE\n\t(* no calculation possible *)\n\tE := TRUE;\n\tW := 4;\nEND_IF;\n\n\n(* revision history\nhm\t18. may 2008\trev 1.0\n\toriginal version\n\nhm\t10. mar. 2009\trev 1.1\n\timproved code\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "SEL2_OF_3B.st", - "source": "FUNCTION_BLOCK SEL2_OF_3B\nVAR_INPUT\n\tIN1 : BOOL;\n\tIN2 : BOOL;\n\tIN3 : BOOL;\n\tTD : TIME;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\n\tW : BOOL;\nEND_VAR\nVAR\n\tTDEL : TON;\nEND_VAR\n\n(*\n\tversion 1.0\t19. may. 2008\n\tprogrammer \toscat\n\ttested BY\t\toscat\n\nSEL2_OF_3B is used to connect 3 binary sensors to one signal. the output Q reflects the state of at least two inputs.\nif two or more of the 3 inputs ate TRUE then Q will be TRUE and if two or more of the three inputs are FALSE then Q will be false.\nthe main putrpose is the connection of 3 redundant binary sensors. \nThe output W will be active when one of the 3 inputs is of different state.\nto avoid flickering while the sensors are switching the output W will become active after a programmed delay of TD.\n\n*)\n\nQ := (IN1 AND IN2) OR (IN1 AND IN3) OR (IN2 AND IN3);\nTDEL(IN := (in1 XOR in2) OR (in1 XOR in3) OR (in2 XOR in3), PT := TD);\nW := TDEL.Q;\n\n\n(* revision history\nhm\t\t19. may 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "SELECT_8.st", - "source": "FUNCTION_BLOCK SELECT_8\nVAR_INPUT\n\tE : BOOL;\n\tSET : BOOL;\n\tIN : BYTE;\n\tUP : BOOL;\n\tDN : BOOL;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tQ0, Q1, Q2, Q3, Q4, Q5, Q6, Q7 : BOOL;\n\tSTATE : INT;\nEND_VAR\nVAR\n\tlast_up: BOOL;\n\tlast_dn : BOOL;\nEND_VAR\n\n(*\n\tversion 1.1\t27. feb. 2009\n\tprogrammer \thugo\n\ttested BY\t\toscat\n\nselect_8 selects one of 8 outputs at any time. the outputscan be selected by up or down keys and an independent anable switches all outouts off if set false\n\n\n*)\n\nIF rst THEN\n\tstate := 0;\nELSIF set THEN\n\tstate := IN;\nELSIF up AND NOT last_up THEN\n\tstate := inc(state,1,7);\nELSIF dn AND NOT last_dn THEN\n\tstate := inc(state,-1,7);\nEND_IF;\nlast_UP := UP;\nlast_DN := DN;\n\nQ0 := FALSE;\nQ1 := FALSE;\nQ2 := FALSE;\nQ3 := FALSE;\nQ4 := FALSE;\nQ5 := FALSE;\nQ6 := FALSE;\nQ7 := FALSE;\n\nIF E THEN\n\tCASE state OF\n\t\t0: Q0 := TRUE;\n\t\t1: Q1 := TRUE;\n\t\t2: Q2 := TRUE;\n\t\t3: Q3 := TRUE;\n\t\t4: Q4 := TRUE;\n\t\t5: Q5 := TRUE;\n\t\t6: Q6 := TRUE;\n\t\t7: Q7 := TRUE;\n\tEND_CASE;\nEND_IF;\n\n(* revision history\nhm\t16. jan 2008\trev 1.0\n\toriginal version\n\nhm\t27. feb. 2009\trev 1.1\n\trenamed input en to e\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "SENSOR_INT.st", - "source": "FUNCTION SENSOR_INT : REAL\nVAR_INPUT\n\tVoltage : REAL;\n\tCurrent : REAL;\n\tRP : REAL;\n\tRS : REAL;\nEND_VAR\nVAR\n\tRG: REAL;\nEND_VAR\n\n(*\nversion 1.3\t11. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the real resistance of a sensor RX given a parasitic resistor in parallel to the sensor and an additional serial resistor.\nfor example a parasitic parallel resistor for a PT100 can be ignored but a series resistor is the cable to the sensor.\nfor a humidity sensor, the parallel resistor is more dramatic and needs to be considered.\nthe function allows to consider a parallel and serial resistor at the same time.\nwith this function and known parasitic serial and parallel resistors the true resistance of the sensor can be calculated.\n\n*)\n\nIF current <> 0.0 THEN\n\tRG := voltage / current;\n\tSENSOR_INT := RP * ( RG - RS) / ( RP + RS - RG);\nEND_IF;\n\n(* revisaion history\n\nhm 20.1.2007\t\trev 1.1\n\tdeleted input R0 which was not needed.\n\nhm\t2. dec 2007\trev 1.2\n\tcorrected an error in formula and improoved speed\n\nhm\t11. mar. 2009\trev 1.3\n\tchanged real constants to use dot syntax\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "SEQUENCE_4.st", - "source": "FUNCTION_BLOCK SEQUENCE_4\nVAR_INPUT\n\tin0 : BOOL := TRUE;\n\tin1 : BOOL := TRUE;\n\tin2 : BOOL := TRUE;\n\tin3 : BOOL := TRUE;\n\tstart : BOOL;\n\trst : BOOL;\n\twait0 : TIME;\n\tdelay0 : TIME;\n\twait1 : TIME;\n\tdelay1 : TIME;\n\twait2 : TIME;\n\tdelay2 : TIME;\n\twait3 : TIME;\n\tdelay3 : TIME;\nEND_VAR\nVAR_INPUT CONSTANT\n\tstop_on_error : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tQ0 : BOOL;\n\tQ1 : BOOL;\n\tQ2 : BOOL;\n\tQ3 : BOOL;\n\tQX : BOOL;\n\trun: BOOL;\n\tstep : INT := -1;\n\tstatus : BYTE;\nEND_VAR\nVAR\n\tlast : TIME;\n\tedge : BOOL;\n\ttx: TIME;\n\tinit: BOOL;\nEND_VAR\n\n(*\nversion 1.5\t13. mar. 2009\nprogrammer \toscat\ntested by\t\thans\n\nsequence_4 enables run when a low to high transition is present on start.\na low to high transition on start will restart the sequencer at any time while a rst will hold the sequencer in reset while true.\nafter run is enabled with a rising edge on start the sequencer waits for wait0 on in0 to enable q0 which stays on for delay0.\nthe next cycle starts with wait1, continues with delay 1 and so on...\nif an edge is not detected during the wait period, the sequencer will then display the error number on the status output.\nthe status numbers 1..4 are errors in step 0..3.\nafter the last step that sets q3, the sequencer leaves q3 on for delay3 and then resets to the initial state.\na step output will indicate the current step of the sequencer and will also be present with a fault condition.\nafter the first output is turened on the sequencer switches from q0 to q1 and so on, at any time there is only one output enabled.\nif an input signal is not detected during a wait period, the sequencer will display the error number ( 1 for in0, 2 for in1 .... ).\nwhen an error is present and the config variable stop_on_error is set then the sequencer will stop. otherwise it will continue.\nThe status output will also display 110 for waiting and 111 for sequence running.\n*)\n\n(* read sps timer *)\ntx := DWORD_TO_TIME(T_PLC_MS());\n\n(* initialize on startup *)\nIF NOT init THEN\n\tlast := tx;\n\tinit := TRUE;\n\tstatus := 110;\nEND_IF;\n\n(* asynchronous reset *)\nIF rst THEN\n\tstep := -1;\n\tQ0 := 0;\n\tQ1 := 0;\n\tQ2 := 0;\n\tQ3 := 0;\n\tstatus := 110;\n\trun := 0;\n\n(* edge on start input restarts the sequencer *)\nELSIF start AND NOT edge THEN\n\tstep := 0;\n\tlast := tx;\n\tstatus := 111;\n\tQ0 := 0;\n\tQ1 := 0;\n\tQ2 := 0;\n\tQ3 := 0;\n\trun := 1;\nEND_IF;\nedge := start;\n\n(* check if stop on status is necessary *)\nIF status > 0 AND status < 100 AND stop_on_error THEN RETURN; END_IF;\n\n(* sequence is running *)\nIF run AND step = 0 THEN\n\tIF NOT q0 AND in0 AND tx - last <= wait0 THEN\n\t\tQ0 := TRUE;\n\t\tlast := tx;\n\tELSIF NOT q0 AND tx - last > wait0 THEN\n\t\tstatus := 1;\n\t\trun := FALSE;\n\tELSIF q0 AND tx - last >= delay0 THEN\n\t\tstep := 1;\n\t\tlast := tx;\n\tEND_IF;\nEND_IF;\nIF run AND step = 1 THEN\n\tIF NOT q1 AND in1 AND tx - last <= wait1 THEN\n\t\tQ0 := FALSE;\n\t\tQ1 := TRUE;\n\t\tlast := tx;\n\tELSIF NOT q1 AND Tx - last > wait1 THEN\n\t\tstatus := 2;\n\t\tq0 := FALSE;\n\t\trun := FALSE;\n\tELSIF q1 AND tx - last >= delay1 THEN\n\t\tstep := 2;\n\t\tlast := tx;\n\tEND_IF;\nEND_IF;\nIF run AND step = 2 THEN\n\tIF NOT q2 AND in2 AND tx - last <= wait2 THEN\n\t\tQ1 := FALSE;\n\t\tQ2 := TRUE;\n\t\tlast := tx;\n\tELSIF NOT q2 AND Tx - last > wait2 THEN\n\t\tstatus := 3;\n\t\tq1 := FALSE;\n\t\trun := FALSE;\n\tELSIF q2 AND tx - last >= delay2 THEN\n\t\tstep := 3;\n\t\tlast := tx;\n\tEND_IF;\nEND_IF;\nIF run AND step = 3 THEN\n\tIF NOT q3 AND in3 AND tx - last <= wait3 THEN\n\t\tQ2 := FALSE;\n\t\tQ3 := TRUE;\n\t\tlast := tx;\n\tELSIF NOT q3 AND Tx - last > wait3 THEN\n\t\tstatus := 4;\n\t\tq2 := FALSE;\n\t\trun := FALSE;\n\tELSIF q3 AND tx - last >= delay3 THEN\n\t\tstep := -1;\n\t\tq3 := FALSE;\n\t\trun := FALSE;\n\t\tstatus := 110;\n\tEND_IF;\nEND_IF;\nQX := q0 OR q1 OR q2 OR q3;\n\n(*\nhm 1.10.06\t\trev 1.1\n\tcorrected delay logic to be after event and not before\n\tadded any output\n\nhm 1.12.06\t\trev 1.2\n\tcorrected failure in sequence logic.\n\tadded init at startup to prevent from initial error after start.\n\nhm 17.1.2007\t\trev 1.3\n\tchanged output fault to status for better compatibility with other modules (ESR).\n\tadded stop on error functionality and setup variable\n\tdefault for inputs in0..3 is true.\n\trenamed variable state to step\n\nhm\t17.sep 2007\trev 1.4\n\treplaced time() with T_PLC_MS() for compatibility reasons\n\nhm\t13. mar. 2009\trev 1.5\n\trenamed output any to qx for compatibility resons\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "SEQUENCE_8.st", - "source": "FUNCTION_BLOCK SEQUENCE_8\nVAR_INPUT\n\tin0 : BOOL := TRUE;\n\tin1 : BOOL := TRUE;\n\tin2 : BOOL := TRUE;\n\tin3 : BOOL := TRUE;\n\tin4 : BOOL := TRUE;\n\tin5 : BOOL := TRUE;\n\tin6 : BOOL := TRUE;\n\tin7 : BOOL := TRUE;\n\tstart : BOOL;\n\trst : BOOL;\n\twait0 : TIME;\n\tdelay0 : TIME;\n\twait1 : TIME;\n\tdelay1 : TIME;\n\twait2 : TIME;\n\tdelay2 : TIME;\n\twait3 : TIME;\n\tdelay3 : TIME;\n\twait4 : TIME;\n\tdelay4 : TIME;\n\twait5 : TIME;\n\tdelay5 : TIME;\n\twait6 : TIME;\n\tdelay6 : TIME;\n\twait7 : TIME;\n\tdelay7 : TIME;\nEND_VAR\nVAR_INPUT CONSTANT\n\tstop_on_error : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tQ0 : BOOL;\n\tQ1 : BOOL;\n\tQ2 : BOOL;\n\tQ3 : BOOL;\n\tQ4 : BOOL;\n\tQ5 : BOOL;\n\tQ6 : BOOL;\n\tQ7 : BOOL;\n\tQX : BOOL;\n\trun: BOOL;\n\tstep : INT := -1;\n\tstatus : BYTE;\nEND_VAR\nVAR\n\tlast : TIME;\n\tedge : BOOL;\n\ttx: TIME;\n\tinit: BOOL;\nEND_VAR\n\n(*\nversion 1.5\t13. mar. 2009\nprogrammer \toscat\ntested by\t\thans\n\nsequence_8 enables run when a low to high transition is present on start.\na low to high transition on start will restart the sequencer at any time while a rst will hold the sequencer in reset while true.\nafter run is enabled with a rising edge on start the sequencer waits for wait0 on in0 to enable q0 which stays on for delay0.\nthe next cycle starts with wait1, continues with delay 1 and so on...\nif an edge is not detected during the wait period, the sequencer will then display the error number on the status output.\nThe status numbers are 1 .. 8 for erros in step 0..7.\nafter the last step that sets q7, the sequencer leaves q7 on for delay7 and then resets to the initial state.\na step output will indicate the current step of the sequencer and will also be present with a fault condition.\nafter the first output is turened on the sequencer switches from q0 to q1 and so on, at any time there is only one output enabled.\nif an input signal is not detected during a wait period, the sequencer will display the error number ( 1 for in0, 2 for in1 .... ).\nwhen an error is present and the config variable stop_on_error is set then the sequencer will stop. otherwise it will continue.\nThe status output will also display 110 for waiting and 111 sequece running.\n\n*)\n\n(* read sps timer *)\ntx := DWORD_TO_TIME(T_PLC_MS());\n\n(* initialize on startup *)\nIF NOT init THEN\n\tlast := tx;\n\tinit := TRUE;\n\tstatus := 110;\nEND_IF;\n\n(* asynchronous reset *)\nIF rst THEN\n\tstep := -1;\n\tQ0 := 0;\n\tQ1 := 0;\n\tQ2 := 0;\n\tQ3 := 0;\n\tQ4 := 0;\n\tQ5 := 0;\n\tQ6 := 0;\n\tQ7 := 0;\n\tstatus := 110;\n\trun := 0;\n\n(* edge on start input restarts the sequencer *)\nELSIF start AND NOT edge THEN\n\tstep := 0;\n\tlast := tx;\n\tstatus := 111;\n\tQ0 := 0;\n\tQ1 := 0;\n\tQ2 := 0;\n\tQ3 := 0;\n\tQ4 := 0;\n\tQ5 := 0;\n\tQ6 := 0;\n\tQ7 := 0;\n\trun := 1;\nEND_IF;\nedge := start;\n\n(* check if stop on error is necessary *)\nIF status > 0 AND status < 100 AND stop_on_error THEN RETURN; END_IF;\n\n(* sequence is running *)\nIF run AND step = 0 THEN\n\tIF NOT q0 AND in0 AND tx - last <= wait0 THEN\n\t\tQ0 := TRUE;\n\t\tlast := tx;\n\tELSIF NOT q0 AND tx - last > wait0 THEN\n\t\tstatus := 1;\n\t\trun := FALSE;\n\tELSIF q0 AND tx - last >= delay0 THEN\n\t\tstep := 1;\n\t\tlast := tx;\n\tEND_IF;\nEND_IF;\nIF run AND step = 1 THEN\n\tIF NOT q1 AND in1 AND tx - last <= wait1 THEN\n\t\tQ0 := FALSE;\n\t\tQ1 := TRUE;\n\t\tlast := tx;\n\tELSIF NOT q1 AND Tx - last > wait1 THEN\n\t\tstatus := 2;\n\t\tq0 := FALSE;\n\t\trun := FALSE;\n\tELSIF q1 AND tx - last >= delay1 THEN\n\t\tstep := 2;\n\t\tlast := tx;\n\tEND_IF;\nEND_IF;\nIF run AND step = 2 THEN\n\tIF NOT q2 AND in2 AND tx - last <= wait2 THEN\n\t\tQ1 := FALSE;\n\t\tQ2 := TRUE;\n\t\tlast := tx;\n\tELSIF NOT q2 AND Tx - last > wait2 THEN\n\t\tstatus := 3;\n\t\tq1 := FALSE;\n\t\trun := FALSE;\n\tELSIF q2 AND tx - last >= delay2 THEN\n\t\tstep := 3;\n\t\tlast := tx;\n\tEND_IF;\nEND_IF;\nIF run AND step = 3 THEN\n\tIF NOT q3 AND in3 AND tx - last <= wait3 THEN\n\t\tQ2 := FALSE;\n\t\tQ3 := TRUE;\n\t\tlast := tx;\n\tELSIF NOT q3 AND Tx - last > wait3 THEN\n\t\tstatus := 4;\n\t\tq2 := FALSE;\n\t\trun := FALSE;\n\tELSIF q3 AND tx - last >= delay3 THEN\n\t\tstep := 4;\n\t\tlast := tx;\n\tEND_IF;\nEND_IF;\nIF run AND step = 4 THEN\n\tIF NOT q4 AND in4 AND tx - last <= wait4 THEN\n\t\tQ3 := FALSE;\n\t\tQ4 := TRUE;\n\t\tlast := tx;\n\tELSIF NOT q4 AND Tx - last > wait4 THEN\n\t\tstatus := 5;\n\t\tq3 := FALSE;\n\t\trun := FALSE;\n\tELSIF q4 AND tx - last >= delay4 THEN\n\t\tstep := 5;\n\t\tlast := tx;\n\tEND_IF;\nEND_IF;\nIF run AND step = 5 THEN\n\tIF NOT q5 AND in5 AND tx - last <= wait5 THEN\n\t\tQ4 := FALSE;\n\t\tQ5 := TRUE;\n\t\tlast := tx;\n\tELSIF NOT q5 AND Tx - last > wait5 THEN\n\t\tstatus := 6;\n\t\tq4 := FALSE;\n\t\trun := FALSE;\n\tELSIF q5 AND tx - last >= delay5 THEN\n\t\tstep := 6;\n\t\tlast := tx;\n\tEND_IF;\nEND_IF;\nIF run AND step = 6 THEN\n\tIF NOT q6 AND in6 AND tx - last <= wait6 THEN\n\t\tQ5 := FALSE;\n\t\tQ6 := TRUE;\n\t\tlast := tx;\n\tELSIF NOT q6 AND Tx - last > wait6 THEN\n\t\tstatus := 7;\n\t\tq5 := FALSE;\n\t\trun := FALSE;\n\tELSIF q6 AND tx - last >= delay6 THEN\n\t\tstep := 7;\n\t\tlast := tx;\n\tEND_IF;\nEND_IF;\nIF run AND step = 7 THEN\n\tIF NOT q7 AND in7 AND tx - last <= wait7 THEN\n\t\tQ6 := FALSE;\n\t\tQ7 := TRUE;\n\t\tlast := tx;\n\tELSIF NOT q7 AND Tx - last > wait7 THEN\n\t\tstatus := 8;\n\t\tq6 := FALSE;\n\t\trun := FALSE;\n\tELSIF q7 AND tx - last >= delay7 THEN\n\t\tstep := -1;\n\t\tQ7 := FALSE;\n\t\tRun := FALSE;\n\t\tstatus := 110;\n\tEND_IF;\nEND_IF;\nQX := q0 OR q1 OR q2 OR q3 OR q4 OR q5 OR q6 OR q7;\n\n(*\nhm 1.10.06\t\trev 1.1\n\tcorrected delay logic to be after event and not before\n\tadded any output\n\nhm 1.12.06\t\trev 1.2\n\tcorrected failure in sequence logic.\n\tadded init at startup to prevent from initial statuss after start.\n\nhm 17.1.2007\t\trev 1.3\n\tchanged output fault to status for better compatibility with other modules (ESR)\n\tadded stop on error functionality and setup variable\n\tdefault for inputs in0..7 is true.\n\trenames variable state to step\n\nhm\t17.sep 2007\trev 1.4\n\treplaced time() with T_PLC_MS() for compatibility reasons\n\nhm\t13. mar. 2009\trev 1.5\n\trenamed output any to qx for compatibility resons\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "SET_DATE.st", - "source": "FUNCTION SET_DATE : DATE\nVAR_INPUT\n\tYEAR : INT;\n\tMONTH : INT;\n\tDAY : INT;\nEND_VAR\nVAR\n\tcount : INT;\n\tofs: ARRAY[1..12] OF INT := 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334;\n\n\tENDIF: BOOL;\nEND_VAR\n\n(*\nversion 2.4\t3. feb. 2021\nprogrammer \thugo\ntested by\ttobias\n\ncreates a date output from year, month and day of month \n\n*)\n\nIF (MONTH > 2) AND (SHL(YEAR,14) = 0)\nTHEN (* we add one day for leap year *)\n\tSET_DATE := DWORD_TO_DATE((INT_TO_DWORD(ofs[MONTH] + day ) + SHR(INT_TO_DWORD(year) * 1461 - 2878169, 2))*86400);\nELSE\n\tSET_DATE := DWORD_TO_DATE((INT_TO_DWORD(ofs[MONTH] + day - 1 ) + SHR(INT_TO_DWORD(year) * 1461 - 2878169, 2))*86400);\nEND_IF;\n\n\n(* old code\nIF month > 2 THEN\n\tcount := (month - 1) * 30;\n\tIF month > 7 THEN count := count + SHR(month - 3,1); ELSE count := count + SHR(month - 4,1); END_IF;\n\t(* chech for leap year and add one day if true *)\n\tIF SHL(year,14) = 0 THEN count := count + 1; END_IF;\nELSE\n\tcount := (month - 1) * 31;\nEND_IF;\n\nSET_DATE := DWORD_TO_DATE((INT_TO_DWORD(count + day - 1) + SHR(INT_TO_DWORD(year) * 1461 - 2878169, 2)) * 86400);\n*)\n\n(* revision history\nhm\t4. aug. 2006\trev 1.0\n\toriginal version\n\nhm\t19 sep. 2007\trev 1.1\n\tuse function leap_year to calculate leap year, more exceptions are handled\n\nhm\t1. okt\t2007\trev 1.2\n\tadded compatibility to step7\n\nhm\t16.dec 2007\t\trev 1.3\n\tchanged code to improove performance\n\nhm\t3. jan. 2008\trev 1.4\n\tfurther improvements in performance\n\nhm\t16. mar. 2008\trev 1.5\n\tadded type conversions to avoid warnings under codesys 3.0\n\nhm\t7. apr. 2008\trev 1.6\n\tdeleted unused step7 code\n\nhm\t14. oct. 2008\trev 1.7\n\toptimized code for better performance\n\nhm\t25. oct. 2008\trev 2.0\n\tnew code using setup constants\n\nhm\t16. nov. 2008\trev 2.1\n\tadded typecasts to avoid warnings\n\nhm\t22. jan. 2011\trev 2.2\n\timproved performance\n\nhm\t29. dec. 2011\trev 2.3\n\timproved performance\n\nhm 3. FEB 2021 rev 2.4\n\tnew code to be more readable\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "SET_DT.st", - "source": "FUNCTION SET_DT : DT\nVAR_INPUT\n\tyear : INT;\n\tmonth : INT;\n\tday : INT;\n\thour : INT;\n\tminute : INT;\n\tsecond : INT;\nEND_VAR\n\n\n(*\nversion 1.5\t16 mar 2008\nprogrammer \thugo\ntested by\ttobias\n\n\ncreates a date output from year, month and day of month\nyear must be in the form of 4 digits ie 2006 or 1977.\n*)\n\nSET_DT := DWORD_TO_DT(DATE_TO_DWORD(SET_DATE(YEAR, MONTH, day)) + INT_TO_DWORD(SECOND) + INT_TO_DWORD(MINUTE) * 60 + INT_TO_DWORD(HOUR) * 3600);\n\n\n(* revision history\nhm\t4. aug. 2006\t\trev 1.0\n\toriginal version\n\nhm\t\t19 sep. 2007\trev 1.1\n\tuse function leap_year to calculate leap year, more exceptions are handled\n\nhm\t\t1. okt 2007\t\trev 1.2\n\tadded step7 compatibility\n\tcall function set_date\n\nhm\t\t8. oct 2007\t\trev 1.3\n\tdeleted unused variables count and leap\n\nhm\t\t1. 11 2007\t\trev 1.4\n\tconverted hour type integer to dword in calculation to avoid overrun on möller ecp4\n\nhm\t\t16. mar 2008\trev 1.5\n\tadded type conversions to avoid warnings under codesys 3.0\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "SET_TOD.st", - "source": "FUNCTION SET_TOD : TOD\nVAR_INPUT\n\thour : INT;\n\tminute : INT;\n\tsecond : REAL;\nEND_VAR\n\n\n(*\nversion 1.5\t16. mar 2008\nprogrammer \thugo\ntested by\ttobias\n\ncreates tod from hour minute and second \n\n*)\n\nSET_TOD := DWORD_TO_TOD(REAL_TO_DWORD(SECOND * 1000.0) + INT_TO_DWORD(MINUTE) * 60000 + INT_TO_DWORD(HOUR) * 3600000);\n\n(* revision history\n\nhm\t\t4.aug.2006\t\trev 1.0\n\toriginal version\n\nhm\t\t11. sep 2007\trev 1.1\n\tchanged coding to avoid a compiler warning under twincat.\n\nhm\t\t1. nov 2007\trev 1.2\n\tchanged coding to avoid possible overrun situation on möller ecp4\n\nhm\t\t2. Nov\t2007\trev 1.3\n\tchanged dword to DINT in calcualtion to avoid warnings with some compilers\n\nhm\t\t14. mar 2008\trev 1.4\n\tchanged code to avoid rounding problem at last digit of millisecond\n\nhm\t\t16. mar. 2008\trev 1.5\n\tadded type conversions to avoid warning under codesys 3.0\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "SGN.st", - "source": "FUNCTION SGN : INT\nVAR_INPUT\n\tX : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t11. nov. 2008\nprogrammer \thugo\ntested by\ttobias\n\nsgn returns 0 when X = 0 , -1 when X < 1 and +1 when X > 1\n\n*)\n\nIF X > 0 THEN\n\tSGN := 1;\nELSIF X < 0 THEN\n\tSGN := -1;\nELSE\n\tSGN := 0;\nEND_IF;\n\n\n\n(* revision histroy\nhm\t16. oct 2007\trev 1.0\n\toriginal version\n\nhm\t11. nov 2007\trev 1.1\n\tchanged type of function from real to int\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "SH.st", - "source": "FUNCTION_BLOCK SH\nVAR_INPUT\n\tin : REAL;\n\tCLK : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tout : REAL;\n\ttrig : BOOL;\nEND_VAR\nVAR\n\tedge : BOOL;\nEND_VAR\n\n(*\nversion 1.1\t16 jan 2007\nprogrammer \thugo\ntested by\t\ttobias\n\nthis sample and hold module samples an input at the rising edge of clk an stores it in out.\nthe out stays stable until the next rising clk edge appears.\na trigger output as active for one cycle when the output was updated.\n\n*)\n\nIF clk AND NOT edge THEN\n\tout := in;\n\ttrig := TRUE;\nELSE;\n\ttrig := FALSE;\nEND_IF;\nedge := clk;\n\n(* revision history\n\nhm 16.1.2007\trev 1.1\n\tadded trig output\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "SHL1.st", - "source": "FUNCTION SHL1 : DWORD\nVAR_INPUT\n\tIN : DWORD;\n\tN : INT;\nEND_VAR\nVAR CONSTANT\n\ttemp : DWORD := 16#FFFF_FFFF;\nEND_VAR\n\n(*\nversion 1.1\t27 dec 2007\nprogrammer \thugo\ntested by\t\ttobias\n\nSHL1 shifts N bits to the left filling the new bits with 1\n\n*)\n\nSHL1 := SHR(temp,32-N) OR SHL(IN,N);\n\n\n(* revision history\nhm\t14.9.2007\t\trev 1.0\n\toriginal version\n\nhm\t27. dec 2007\trev 1.1\n\tchanged code for better performance\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "SHR1.st", - "source": "FUNCTION SHR1 : DWORD\nVAR_INPUT\n\tIN : DWORD;\n\tN : INT;\nEND_VAR\nVAR CONSTANT\n\ttemp : DWORD := 16#FFFF_FFFF;\nEND_VAR\n\n(*\nversion 1.1\t27 dec 2007\nprogrammer \thugo\ntested by\t\ttobias\n\nSHR1 shifts N bits to the right filling the new bits with 1\n\n*)\n\nSHR1 := SHL(temp,32-N) OR SHR(IN,N);\n\n(* revision history\nhm\t14.9.2007\t\trev 1.0\n\toriginal version\n\nhm\t27. dec 2007\trev 1.1\n\tchanged code for better performance\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "SHR_4E.st", - "source": "FUNCTION_BLOCK SHR_4E\nVAR_INPUT\n\tSET : BOOL;\n\tD0: BOOL;\n\tCLK: BOOL;\n\tRST: BOOL;\nEND_VAR\nVAR_OUTPUT\n\tQ0: BOOL;\n\tQ1: BOOL;\n\tQ2: BOOL;\n\tQ3: BOOL;\nEND_VAR\nVAR\n\ttrig : R_TRIG;\nEND_VAR\n\n(*\nversion 1.1\t25. oct. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\n4 bit shift register with reset\n\n*)\n\n(* trig.Q signals a rising edge on clk *)\ntrig(clk := clk);\n\nIF set OR rst THEN\n\tQ0 := NOT rst;\n\tQ1 := Q0;\n\tQ2 := Q0;\n\tQ3 := Q0;\nELSIF trig.Q THEN\n\tQ3 := Q2;\n\tQ2 := Q1;\n\tQ1 := Q0;\n\tQ0 := D0;\nEND_IF;\n\n\n\n(* revision history\nhm\t4. aug. 2006\trev 1.0\n\toriginal version\n\nhm\t25. oct. 2008\trev 1.1\n\toptimized code\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "SHR_4UDE.st", - "source": "FUNCTION_BLOCK SHR_4UDE\nVAR_INPUT\n\tSET : BOOL;\n\tD0: BOOL;\n\tD3: BOOL;\n\tCLK: BOOL;\n\tDN : BOOL;\n\tRST: BOOL;\n\nEND_VAR\nVAR_OUTPUT\n\tQ0: BOOL;\n\tQ1: BOOL;\n\tQ2: BOOL;\n\tQ3: BOOL;\nEND_VAR\nVAR\n\ttrig : R_TRIG;\nEND_VAR\n\n(*\nversion 1.2\t14. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\n4 bit shift register with reset up / down direction input\n\n*)\n\n(* trig.Q signals a rising edge on clk *)\ntrig(clk := clk);\n\nIF set OR rst THEN\n\tQ0 := NOT RST;\n\tQ1 := Q0;\n\tQ2 := Q0;\n\tQ3 := Q0;\nELSIF trig.Q THEN\n\tIF dn THEN\n\t\tQ0 := Q1;\n\t\tQ1 := Q2;\n\t\tQ2 := Q3;\n\t\tQ3 := D3;\n\tELSE\n\t\tQ3 := Q2;\n\t\tQ2 := Q1;\n\t\tQ1 := Q0;\n\t\tQ0 := D0;\n\tEND_IF;\nEND_IF;\n\n\n\n(* revision history\nhm\t4. aug. 2006\trev 1.0\n\toriginal version\n\nhm\t25. oct. 2008\trev 1.1\n\toptimized code\n\nhm\t14. mar. 2009\trev 1.2\n\tremoved double assignments\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "SHR_8PLE.st", - "source": "FUNCTION_BLOCK SHR_8PLE\nVAR_INPUT\n\tDin : BOOL;\n\tDload : BYTE;\n\tCLK: BOOL;\n\tUP: BOOL :=1;\n\tload : BOOL;\n\tRST: BOOL;\nEND_VAR\nVAR_OUTPUT\n\tDOut: BOOL;\nEND_VAR\nVAR\n\tedge : BOOL :=1;\n\tregister : BYTE;\nEND_VAR\n\n(*\nversion 1.0\t4 aug 2006\nprogrammer \thugo\ntested by\toscat\n\n8 bit shift register with reset and parallel load\nthe register can shift up or down\nit also has a serial input.\nthe Din input is on Bit0 for up shift and on bit 7 for down shift\nthe Dout output is on Bit7 for up shift and on bit 0 for down shift\nparalle clock is performed clock synchron while a shift is performed first and then the register is reloaded\n\n\n*)\n\n(* flankenerkennung clk wird high und edge war high reset ist nicht aktiv und set ist nicht aktiv *)\nIF CLK AND edge AND NOT rst THEN\n\tedge := FALSE;\t(* flanke wurde erkannt und weitere flankenerkennung wird verhindert bis edge wieder true ist *)\n\t(* hier ist der code für das flankenevent *)\n\tIF UP THEN\t\t\t\t\t\t(*shift up *)\n\t\tregister := SHL(register,1);\n\t\tregister.0 := Din;\n\t\tDout := register.7;\n\tELSE\t\t\t\t\t\t\t\t(* shift down *);\n\t\tregister := SHR(register,1);\n\t\tregister.7 := Din;\n\t\tDout := register.0;\n\tEND_IF;\n\tIF load THEN\t\t\t\t\t\t\t(* the byte on Din will be loaded if load = true *)\n\t\tregister := Dload;\n\t\tIF up THEN Dout := register.7; ELSE Dout := register.0; END_IF;\n\tEND_IF;\nEND_IF;\nIF NOT clk THEN edge := TRUE; END_IF;\t(* sobald clk wieder low wird warten auf nächste flanke *)\nIF rst THEN\t\t\t\t\t\t\t\t\t(* wenn reset aktiv dann ausgang rücksetzen *)\n\tregister := 0;\n\tDout := FALSE;\nEND_IF;\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "SHR_8UDE.st", - "source": "FUNCTION_BLOCK SHR_8UDE\nVAR_INPUT\n\tSET : BOOL;\n\tD0: BOOL;\n\tD7: BOOL;\n\tCLK: BOOL;\n\tDN : BOOL;\n\tRST: BOOL;\nEND_VAR\nVAR_OUTPUT\n\tQ0: BOOL;\n\tQ1: BOOL;\n\tQ2: BOOL;\n\tQ3: BOOL;\n\tQ4: BOOL;\n\tQ5: BOOL;\n\tQ6: BOOL;\n\tQ7: BOOL;\nEND_VAR\nVAR\n\ttrig : R_TRIG;\nEND_VAR\n\n(*\nversion 1.2\t14. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\n8 bit shift register with reset\n\n\n*)\n\n(* trig.Q signals a rising edge on clk *)\ntrig(clk := clk);\n\nIF set OR rst THEN\n\tQ0 := NOT RST;\n\tQ1 := Q0;\n\tQ2 := Q0;\n\tQ3 := Q0;\n\tQ4 := Q0;\n\tQ5 := Q0;\n\tQ6 := Q0;\n\tQ7 := Q0;\nELSIF trig.Q THEN\n\tIF dn THEN\n\t\tQ0 := Q1;\n\t\tQ1 := Q2;\n\t\tQ2 := Q3;\n\t\tQ3 := Q4;\n\t\tQ4 := Q5;\n\t\tQ5 := Q6;\n\t\tQ6 := Q7;\n\t\tQ7 := D7;\n\tELSE\n\t\tQ7 := Q6;\n\t\tQ6 := Q5;\n\t\tQ5 := Q4;\n\t\tQ4 := Q3;\n\t\tQ3 := Q2;\n\t\tQ2 := Q1;\n\t\tQ1 := Q0;\n\t\tQ0 := D0;\n\tEND_IF;\nEND_IF;\n\n\n\n(* revision history\nhm\t4. aug. 2006\trev 1.0\n\toriginal version\n\nhm\t25. oct. 2008\trev 1.1\n\toptimized code\n\nhm\t14. mar. 2009\trev 1.2\n\tremoved double assignments\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "SH_1.st", - "source": "FUNCTION_BLOCK SH_1\nVAR_INPUT\n\tin : REAL;\n\tPT : TIME;\nEND_VAR\nVAR_OUTPUT\n\tout : REAL;\n\tTrig : BOOL;\nEND_VAR\nVAR\n\tlast : TIME;\n\ttx: TIME;\nEND_VAR\n\n(*\nversion 1.2\t17 sep 2007\nprogrammer \thugo\ntested by\t\ttobias\n\nthis sample and hold module samples an input every PT seconds.\nafter a ample is taken the output Trig will be active for one cycle.\n\n*)\n\n(* read system time *)\ntx := DWORD_TO_TIME(T_PLC_MS());\n\nIF tx - last >= PT THEN\n\tlast := tx;\n\tout := in;\n\ttrig := TRUE;\nELSE\n\ttrig := FALSE;\nEND_IF;\n\n(* revision history\n\nHM\t6.1.2007\trev 1.1\n\tadded trig output\n\nHM\t17.9.2007\trev 1.2\n\treplaced time() with T_PLC_MS() for compatibility reasons\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "SH_2.st", - "source": "FUNCTION_BLOCK SH_2\nVAR_INPUT\n\tin : REAL;\n\tPT : TIME;\n\tN : INT := 16;\n\tdisc : INT;\nEND_VAR\nVAR_OUTPUT\n\tout : REAL;\n\ttrig : BOOL;\n\tavg : REAL;\n\thigh: REAL;\n\tlow: REAL;\nEND_VAR\nVAR\n\tM : INT;\n\tbuf : ARRAY[0..15] OF REAL;\n\tbuf2 : ARRAY[0..15] OF REAL;\n\tlast : TIME;\n\ti : INT;\n\tstart: INT;\n\ttemp: REAL;\n\tstop: INT;\n\ttx: TIME;\n\td2: INT;\nEND_VAR\n\n(*\nversion 1.6\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis sample and hold module samples an input every PT seconds.\nthis sample and hold also does avg and other calculations with the input data.\nan average is calculated over N samples while for this calculation disc samples are discarded,\ndisc = 0 all samples are averaged,\nif disc = 1 the lowest value is ignored,\nif disc = 2 the lowest and highest values are ignored, \nand so on.....\n\n*)\n\n(* read system time *)\ntx := DWORD_TO_TIME(T_PLC_MS());\nd2 := SHR(disc,1);\n\nIF tx - last >= PT THEN\n\tlast := tx;\n\ttrig := TRUE;\n\n\t(* limit M to 0..16 *)\n\tM := LIMIT(1,N,16);\n\n\t(* edge detected lets take the sample *)\n\tFOR i := M - 1 TO 1 BY -1 DO buf2[i] := buf2[i-1]; END_FOR;\n\tbuf2[0] := in;\n\tout := in;\n\tbuf := buf2;\n\n\t(* sort the ARRAY lowest value AT 0 *)\n\tFOR start := 0 TO M - 2 DO\n\t\tFOR i := start+1 TO M - 1 DO\n\t\t\tIF buf[start] > buf[i] THEN\n\t\t\t\ttemp := buf[start];\n\t\t\t\tbuf[start] := buf[i];\n\t\t\t\tbuf[i] := temp;\n\t\t\tEND_IF;\n\t\tEND_FOR;\n\tEND_FOR;\n\n\t(* any calculation with the samples is here *)\n\tstop := M - 1 - d2;\n\tstart := d2;\n\tIF NOT even(disc) THEN start := start + 1; END_IF;\n\tavg := 0;\n\tFOR i := start TO stop DO avg := avg + buf[i]; END_FOR;\n\tavg := avg / INT_TO_REAL(stop - start +1);\n\tlow := buf[start];\n\thigh := buf[stop];\nELSE\n\tTrig := FALSE;\nEND_IF;\n\n(* revision history\nhm 20. jan. 2007\trev 1.1\n\tadded input N to specify the amout of samples for average and high low calculations\n\tadded trig output\n\nhm 10. sep. 2007 \trev 1.2\n\tan error would be generated if N was set to 0, now n is forced to1 if set to 0.\n\tindex was out of array.\n\nhm\t17. sep. 2007\trev 1.3\n\treplaced time() with t_plc_ms() for compatibility reasons\n\nhm\t6. jan. 2008\trev 1.4\n\timproved performance\n\nhm\t14. jun. 2008\trev 1.5\n\tset default for input N = 16\n\nhm\t10. mar. 2009\trev 1.6\n\tadded type conversion for compatibility reasons\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "SH_T.st", - "source": "FUNCTION_BLOCK SH_T\nVAR_INPUT\n\tIN : REAL;\n\tE : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tOUT : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t18. oct. 2008\nprogrammer \thugo\ntested by\toscat\n\nthis sample and hold module samples an input while en is high.\nduring the high time of en the output follows in.\nthe out stays stable until the en goes high again.\n*)\n\nIF E THEN out := in; END_IF;\n\n\n\n(* revision history\nhm\t1. sep. 2006\trev 1.0\n\toriginal version\n\nhm\t18. oct. 2008\trev 1.1\n\tchanged input en to e for compatibility reasons\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "SIGMOID.st", - "source": "FUNCTION SIGMOID : REAL\nVAR_INPUT\n\tX : REAL;\nEND_VAR\n\n\n(*\nversion 1.2\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the sigmoid function\n\n*)\n\nIF X > 20.0 THEN\n\tSIGMOID := 1.0;\nELSIF x < -85.0 THEN\n\tSIGMOID := 0.0;\nELSE\n\tSIGMOID := 1.0 / (1.0 + EXP(-X));\nEND_IF;\n\n\n(* revision history\nhm\t10.12.2007\t\trev 1.0\n\toriginal version\n\nhm\t11. mar. 2008\t\trev 1.1\n\textended range of valid inputs to +inv / -inv\n\nhm 10. mar. 2009\t\trev 1.2\n\treal constants updated to new systax using dot\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "SIGNAL.st", - "source": "FUNCTION_BLOCK SIGNAL\nVAR_INPUT\n\tIN : BOOL;\n\tSIG : BYTE;\n\tTS : TIME;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\nEND_VAR\nVAR\n\ttx: DWORD;\n\tstep: BYTE;\nEND_VAR\nVAR CONSTANT\n\tone : BYTE := 1;\nEND_VAR\n\n(*\nversion 1.0\t13 dec 2007\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function generates an output signal according to a bit pattern SIG.\nthe patter is shifted to the output in time steps of TS.\nts defaults to 128 ms if not specified.\n*)\n\nIF in THEN\n\t(* an alarm is present read system time first *)\n\ttx := T_PLC_MS();\n\t(* calculate the step counter which is the lowest 3 bits of (time / ts) *)\n\tIF ts > t#0s THEN\n\t\tstep := DWORD_TO_BYTE(tx / TIME_TO_DWORD(ts) AND 16#0000_0007);\n\tELSE\n\t\tstep := DWORD_TO_BYTE(SHR(tx,7) AND 16#0000_0007);\n\tEND_IF;\n\t(* convert the value 0-7 in step into one bit only (bit 0-7) *)\n\tstep := SHL(one,step);\n\t(* generate the output signal *)\n\tQ := (step AND sig) > 0;\nELSE\n\tQ := FALSE;\nEND_IF;\n\n(* revision history\nhm\t13.12.2007\t\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "SIGNAL_4.st", - "source": "FUNCTION_BLOCK SIGNAL_4\nVAR_INPUT\n\tIN1 : BOOL;\n\tIN2 : BOOL;\n\tIN3 : BOOL;\n\tIN4 : BOOL;\n\tTS : TIME;\nEND_VAR\nVAR_INPUT CONSTANT\n\tS1 : BYTE := 2#1111_1111;\n\tS2 : BYTE := 2#1111_0000;\n\tS3 : BYTE := 2#1010_1010;\n\tS4 : BYTE := 2#1010_0000;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\nEND_VAR\nVAR\n\tsig : SIGNAL;\nEND_VAR\n\n(*\nversion 1.0\t13 dec 2007\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function generates one out of 4 signals specified by bit patterns S1 .. S4.\nthe selected pattern will be shifted with the step time TS.\nIn1 has higher priority then In2 which has higher priority then IN3 and in4 has the lowest priority.\nts defaults to 128 ms if not specified.\n*)\n\n(* an alarm is present read system time first *)\n(* check if an alarm is present if yes set sig to the alarm pattern otherwise exit the routine *)\nIF in1 THEN\n\tsig(in := TRUE, sig := s1, TS := TS);\nELSIF in2 THEN\n\tsig(in := TRUE, sig := s2, TS := TS);\nELSIF in3 THEN\n\tsig(in := TRUE, sig := s3, TS := TS);\nELSIF in4 THEN\n\tsig(in := TRUE, sig := s4, TS := TS);\nELSE\n\tsig(in := FALSE);\nEND_IF;\n\n(* set the output *)\nQ := sig.Q;\n\n\n(* revision history\nhm\t13.12.2007\t\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "SIGN_I.st", - "source": "FUNCTION SIGN_I : BOOL\nVAR_INPUT\n\tIN : DINT;\nEND_VAR\n\n\n(*\nversion 1.3\t27. oct. 2008\nprogrammer \thugo\ntested by\ttobias\n\nthis function return true if the integer input is negative\n\n*)\n\nSIGN_I := in.31;\n\n(* revision history\nhm 3.3.2007\trev 1.1\n\tchanged method of function for better compatibility to other systems\n\nhm\t1.12.2007\trev 1.2\n\tchanged code to improve performance\n\nhm\t27. oct. 2008\trev 1.3\n\tchanged type of input to dint\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "SIGN_R.st", - "source": "FUNCTION SIGN_R : BOOL\nVAR_INPUT\n\tin : REAL;\nEND_VAR\n\n\n(*\nversion 1.4\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function return true if the real input is negative\n\n*)\n\nSIGN_R := in < 0.0;\n\n\n(* revision history\nhm 19.1.2007\trev 1.1\n\tchanged method of function for better compatibility to other systems\n\nhm\t1.12.2007\trev 1.2\n\tchanged code to improve performance\n\nhm\t14. jun. 2008\trev 1.3\n\timproved performace\n\nhm 10. mar. 2009\trev 1.4\n\treal constants updated to new systax using dot\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "SINC.st", - "source": "FUNCTION SINC : REAL\nVAR_INPUT\n\tX : REAL;\nEND_VAR\n\n\n(*\nversion 1.2\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the sinc function.\n\n*)\n\nIF X = 0.0 THEN\n\tSINC := 1.0;\nELSE\n\tSINC := SIN(x) / x;\nEND_IF;\n\n\n(* revision histroy\nhm\t11. mar. 2008\trev 1.0\n\toriginal version\n\nhm\t1.12.2007\trev 1.1\n\tchanged code to improove performance\n\nhm 10. mar. 2009\trev 1.2\n\treal constants updated to new systax using dot\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "SINH.st", - "source": "FUNCTION SINH : REAL\nVAR_INPUT\n\tX : REAL;\nEND_VAR\n\n\n(*\nversion 1.3\t11. mar 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the sin hyperbolicus\n\n*)\n\nIF ABS(x) < 2E-3 THEN\n\tSINH := X;\nELSE\n\tSINH := (EXP(x) - EXP(-x)) * 0.5;\nEND_IF;\n\n\n(* revision history\nhm\t12.1.2007\trev 1.0\n\toriginal version\n\nhm\t1.12.2007\trev 1.1\n\tchanged code to improve performance\n\nhm\t5. jan 2008\trev 1.2\n\tfurther performance improvement\n\nhm\t11. mar 2008\trev 1.3\n\timproved accuracy around 0\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "SPEED.st", - "source": "FUNCTION_BLOCK SPEED\nVAR_INPUT\n\tms : REAL;\n\tkmh : REAL;\n\tkn : REAL;\n\tmh : REAL;\nEND_VAR\nVAR_OUTPUT\n\tYms : REAL;\n\tYkmh : REAL;\n\tYkn : REAL;\n\tYmh : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t11. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nthis function converts different speed units\nany unused input can simply be left open.\ndifferent inputs connected at the same time will be added up.\n\n*)\n\nYms := ms +\n\t\tkmh * 0.27777777777778 +\n\t\tkn * 0.5144444 +\n\t\tmh * 0.44704;\nYkmh := Yms * 3.6;\nYkn := Yms * 1.94384466037535;\nYmh := Yms * 2.23693629205440;\n\n(*\nGeschwindigkeit Meter durch Sekunde m/s 1 m/s = 3,6 km/h\nkm durch (pro) Stunde, nicht „Stundenkilometer“ verwenden\nKnoten kn 1 kn = 1 sm/h = 0,5144 m/s\n\n*)\n\n(* revision history\nhm\t27. mar. 2009\trev 1.0\n\toriginal version\n\nhm\t11. mar. 2009\trev 1.1\n\timproved code\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "SPHERE_V.st", - "source": "FUNCTION SPHERE_V : REAL\nVAR_INPUT\n\trx : REAL;\nEND_VAR\n\n\n(*\nversion 1.2\t22. feb 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nsphere_V calculates the Volume of a Sphere\n\n\n*)\n\nsphere_V := 4.188790205 * Rx * RX * RX;\n\n(* revision histroy\nhm\t16. oct 2007\trev 1.0\n\toriginal version\n\nhm\t4. dec 2007\t\trev 1.1\n\tchanged code for better performance\n\nhm\t22. feb 2008\t\trev 1.2\n\tchanged code for better performance\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "SQRTN.st", - "source": "FUNCTION SQRTN : REAL\nVAR_INPUT\n\tX : REAL;\n\tN : INT;\nEND_VAR\n\n\n(*\nversion 1.3\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the nth root function of X according to the formula sqrtn = x^(1/n).\n\n*)\n\nIF N > 0 THEN\n\tSQRTN := EXP(LN(x) / INT_TO_REAL(n));\nELSE\n\tSQRTN := 0.0;\nEND_IF;\n\n\n(* revision history\nhm\t\t12 jan 2007\trev 1.0\n\toriginal version\n\nhm\t\t2. dec 2007\trev 1.1\n\tchanged code for better performance\n\nhm\t\t11. mar 2008\trev 1.2\n\tadded result 0 for compatibility reasons\n\nhm 10. mar. 2009\trev 1.3\n\tadded type conversions for compatibility reasons\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "STACK_16.st", - "source": "FUNCTION_BLOCK STACK_16\nVAR_INPUT\n\tDin : DWORD;\n\tE : BOOL := TRUE;\n\tRD : BOOL;\n\tWD : BOOL;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tDout : DWORD;\n\tEMPTY : BOOL := TRUE;\n\tFULL : BOOL;\nEND_VAR\nVAR\n\tstack : ARRAY[0..n] OF DWORD;\n\tpt : INT;\nEND_VAR\nVAR CONSTANT\n\tn : INT := 15;\t(* changing this value will chage the number of stored elements in the fifo *)\nEND_VAR\n\n\n(*\nversion 2.0\t25. jul 2009\nprogrammer \thugo\ntested by\t\toscat\n\n16 Dword STACK memory\n\n*)\n\nIF RST THEN\n\t(* asynchronous reset for the fifo *)\n\tpt := 0;\n\tEMPTY := TRUE;\n\tFULL := FALSE;\n\tDout := 0;\nELSIF E THEN\n\tIF NOT EMPTY AND RD THEN\n\t\t(* read one element *)\n\t\tpt := pt - 1;\n\t\tDout := stack[pt];\n\t\tEMPTY := pt = 0;\n\t\tFULL := FALSE;\n\tEND_IF;\n\tIF NOT FULL AND WD THEN\n\t\t(* write one element *)\n\t\tstack[pt] := Din;\n\t\tpt := pt + 1;\n\t\tFULL := pt > n;\n\t\tEMPTY := FALSE;\n\tEND_IF;\nEND_IF;\n\n\n(* revision history\nhm\t4. aug. 2006\trev 1.0\n\toriginal version\n\nhm\t19. feb 2008\trev 1.1\n\tperformance improvements\n\nhm\t17. oct. 2008\trev 1.2\n\tdeleted unnecessary init with 0\n\nhm\t27. oct. 2008\trev 1.3\n\toptimized performance\n\nhm\t25. jul 2009\trev 2.0\n\tchanged inputs to allow simultsaneous read and write\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "STACK_32.st", - "source": "FUNCTION_BLOCK STACK_32\nVAR_INPUT\n\tDin : DWORD;\n\tE : BOOL := TRUE;\n\tRD : BOOL;\n\tWD : BOOL;\n\tRST : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tDout : DWORD;\n\tEMPTY : BOOL := TRUE;\n\tFULL : BOOL;\nEND_VAR\nVAR\n\tstack : ARRAY[0..n] OF DWORD;\n\tpt : INT;\nEND_VAR\nVAR CONSTANT\n\tn : INT := 31;\t(* changing this value will chage the number of stored elements in the fifo *)\nEND_VAR\n\n\n(*\nversion 2.0\t25. jul 2009\nprogrammer \thugo\ntested by\t\toscat\n\n32 Dword STACK memory\n*)\n\nIF RST THEN\n\t(* asynchronous reset for the fifo *)\n\tpt := 0;\n\tEMPTY := TRUE;\n\tFULL := FALSE;\n\tDout := 0;\nELSIF E THEN\n\tIF NOT EMPTY AND RD THEN\n\t\t(* read one element *)\n\t\tpt := pt - 1;\n\t\tDout := stack[pt];\n\t\tEMPTY := pt = 0;\n\t\tFULL := FALSE;\n\tEND_IF;\n\tIF NOT FULL AND WD THEN\n\t\t(* write one element *)\n\t\tstack[pt] := Din;\n\t\tpt := pt + 1;\n\t\tFULL := pt > n;\n\t\tEMPTY := FALSE;\n\tEND_IF;\nEND_IF;\n\n\n(* revision history\nhm\t4. aug. 2006\trev 1.0\n\toriginal version\n\nhm\t19. feb 2008\trev 1.1\n\tperformance improvements\n\nhm\t17. oct. 2008\trev 1.2\n\tdeleted unnecessary init with 0\n\nks\t27. oct. 2008\trev 1.3\n\toptimized performance\n\nhm\t25. jul 2009\trev 2.0\n\tchanged inputs to allow simultsaneous read and write\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "STAIR.st", - "source": "FUNCTION STAIR : REAL\nVAR_INPUT\n\tX : REAL;\n\tD : REAL;\nEND_VAR\n\n\n(*\nversion 1.4\t10. mar. 2009\nprogrammer \toscat\ntested by\t\ttobias\n\nthe function stair converts an anlog input signal to a staircase like output.\nD is the step width for the output signal.\nif D = 0 then the output follows the input without a chage.\n*)\n\nIF D > 0.0 THEN\n\tSTAIR := DINT_TO_REAL(REAL_TO_DINT(X / D)) * D;\nELSE\n\tSTAIR := X;\nEND_IF;\n\n\n\n(* revision history\nhm\t28 jan 2007\t\trev 1.0\n\toriginal version\n\nhm\t27 dec 2007\t\trev 1.1\n\tchanged code for better performance\n\nhm\t6. jan 2008\t\trev 1.2\n\tfurther performance improvement\n\nhm\t26. oct. 2008\t\trev 1.3\n\toptimized code\n\nhm\t10. mar. 2009\trev 1.4\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "STAIR2.st", - "source": "FUNCTION_BLOCK STAIR2\nVAR_INPUT\n\tX : REAL;\n\tD : REAL;\nEND_VAR\nVAR_OUTPUT\n\tY: REAL;\nEND_VAR\n\n\n(*\nversion 1.4\t10. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nthe function stair2 converts an anlog input signal to a staircase like output.\nD is the step width for the output signal. the output will use D as a hysteresis for a stairchange.\nif D = 0 then the output follows the input without a chage.\n*)\n\nIF D > 0.0 THEN\n\tIF X >= Y + D OR X <= Y - D THEN Y := FLOOR(X/D) * D; END_IF;\nELSE\n\tY := X;\nEND_IF;\n\n\n\n(* revision history\nhm\t28 jan 2007\t\trev 1.0\n\toriginal version\n\nhm\t27. dec 2007\trev 1.1\n\tchanged code for better performance\n\nhm\t30. jun. 2008\trev 1.2\n\tadded type conversions to avoid warnings under codesys 3.0\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\nks\t26. oct. 2008\trev 1.3\n\timproved code\n\nhm\t10. mar. 2009\trev 1.4\n\treal constants updated to new systax using dot\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "STATUS_TO_ESR.st", - "source": "FUNCTION STATUS_TO_ESR : esr_data\nVAR_INPUT\n\tstatus : BYTE;\n\tadress : STRING(10);\n\tDT_in : DT;\n\tTS : TIME;\nEND_VAR\n\n\n(*\nversion 1.0\t6 oct 2006\nprogrammer \thugo\ntested by\t\ttobias\n\nstatus_to_esr creates esr data from a status byte.\n\n*)\n\nIF status < 100 THEN\n\tstatus_to_ESR.typ := 1;\nELSIF status < 200 THEN\n\tstatus_to_ESR.typ := 2;\nELSE\n\tstatus_to_ESR.typ := 3;\nEND_IF;\nstatus_to_ESR.adress:= adress;\nstatus_to_ESR.DS := DT_in;\nstatus_to_ESR.TS := TS;\nstatus_to_ESR.data[0] := status;\n\nEND_FUNCTION\n" - }, - { - "fileName": "STORE_8.st", - "source": "FUNCTION_BLOCK STORE_8\nVAR_INPUT\n\tSet : BOOL;\n\tD0,D1, D2, D3, D4, D5, D6, D7 : BOOL;\n\tClr : BOOL;\n\tRst : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tQ0, Q1, Q2, Q3, Q4, Q5, Q6, Q7 : BOOL;\nEND_VAR\nVAR\n\tedge: BOOL;\nEND_VAR\n\n(*\nversion 1.2\t14. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nStore_4 stores up to 4 boolean inputs until a reset is clearing the outputs.\nthe respective output is set with a true at the respective input and stays true until a reset is generated.\na set input is used to set all outputs true at the same time, independent of their inputs.\na clear input is used to reset only the lowest priority of the outputs one at a time.\nthe lowest priority is q3.\n\n*)\n\nIF rst OR set THEN\n\tq0 := NOT rst;\n\tq1 := q0;\n\tq2 := q0;\n\tq3 := q0;\n\tq4 := q0;\n\tq5 := q0;\n\tq6 := q0;\n\tq7 := q0;\nELSE\n\tIF D0 THEN Q0 := TRUE; END_IF;\n\tIF D1 THEN Q1 := TRUE; END_IF;\n\tIF D2 THEN Q2 := TRUE; END_IF;\n\tIF D3 THEN Q3 := TRUE; END_IF;\n\tIF D4 THEN Q4 := TRUE; END_IF;\n\tIF D5 THEN Q5 := TRUE; END_IF;\n\tIF D6 THEN Q6 := TRUE; END_IF;\n\tIF D7 THEN Q7 := TRUE; END_IF;\n\n\tIF clr AND NOT edge THEN\n\t\tIF q0 THEN q0 := FALSE;\n\t\tELSIF q1 THEN q1 := FALSE;\n\t\tELSIF q2 THEN q2 := FALSE;\n\t\tELSIF q3 THEN q3 := FALSE;\n\t\tELSIF q4 THEN q4 := FALSE;\n\t\tELSIF q5 THEN q5 := FALSE;\n\t\tELSIF q6 THEN q6 := FALSE;\n\t\tELSE q7 := FALSE;\n\t\tEND_IF;\n\tEND_IF;\n\tedge := clr;\nEND_IF;\n\n\n(* revision history\nhm\t25.12.2007\trev 1.0\n\toriginal version\n\nhm\t30. oct. 2008\trev 1.1\n\toptimized performance\n\nhm\t14. mar. 2009\trev 1.2\n\tremoved double assignments\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "SUN_MIDDAY.st", - "source": "FUNCTION SUN_MIDDAY : TOD\nVAR_INPUT\n\tLON : REAL;\n\tUTC : DATE;\nEND_VAR\nVAR\n\tT : REAL;\n\tOFFSET : REAL;\nEND_VAR\n\n(*\nversion 1.0\t26. jan. 2011\nprogrammer \thugo\ntested by\toscat\n\nthis FUNCTION calculates the time when the sun stand exactly south of a given location.\n\n*)\n\nT := INT_TO_REAL(DAY_OF_YEAR(utc));\nOFFSET := -0.1752 * SIN(0.033430 * T + 0.5474) - 0.1340 * SIN(0.018234 * T - 0.1939);\nSUN_MIDDAY := HOUR_TO_TOD(12.0 - OFFSET - lon * 0.0666666666666);\n\n\n(* revision history\n\nhm\t26. jan. 2011\trev 1.0\n\tinitial release\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "SUN_POS.st", - "source": "FUNCTION_BLOCK SUN_POS\nVAR_INPUT\n\tlatitude : REAL;\t\t\t\t(* latitude of geographical position *)\n\tlongitude : REAL;\t\t\t\t(* longitude of geographical position *)\n\tutc : DT;\t\t\t\t\t\t(*\tworld time\t\t\t\t*)\nEND_VAR\nVAR_OUTPUT\n\tB: REAL;\n\tH : REAL;\n\tHR: REAL;\nEND_VAR\nVAR_TEMP\n\tg: REAL;\n\ta: REAL;\n\td: REAL;\n\tt1: REAL;\n\tn: REAL;\n\te: REAL;\n\tc: REAL;\n\ttau: REAL;\n\tsin_d: REAL;\n\trlat: REAL;\n\tsin_lat: REAL;\n\tcos_lat: REAL;\n\tcos_tau: REAL;\n\tcos_d: REAL;\nEND_VAR\n\n(*\nversion 2.1\t7. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nthis FUNCTION block calculates the sun position for a given date and time.\nthe times are calculated in utc and have to be corrected for the given time zone.\nB is the angle from north and HR is the highth in degrees.\n\n*)\n\n\n(* n is the julian date and the number of days since 1.1.2000-12:00 midday *)\n(* be careful for step7 date startes 1.1.1990 instead of 1.1.1970 *)\n(* for step7 this line must change *)\nn := DWORD_TO_REAL(DT_TO_DWORD(UTC) - 946728000) * 0.000011574074074074;\ng :=MODR(6.240040768 + 0.01720197 * n, math.PI2);\nd := MODR(4.89495042 + 0.017202792 * n, math.PI2) + 0.033423055 * SIN(g) + 0.000349066 * SIN(2.0*g);\ne := 0.409087723 - 0.000000006981317008 * n;\ncos_d := COS(d);\nsin_d := SIN(d);\na := ATAN(COS(e) * sin_d / cos_d);\nIF cos_d < 0.0 THEN a := a + math.PI; END_IF;\nc := ASIN(SIN(e) * sin_d);\n\n(* also here we must be very careful utc is from 1.1.1970 for step7 the formula must change *)\ntau := RAD(MODR(6.697376 + (n - 0.25) * 0.0657098245037645 + DWORD_TO_REAL(TOD_TO_DWORD(DT_TO_TOD(utc))) * 0.0000002785383333, 24.0) * 15.0 + longitude) - a;\nrlat := RAD(latitude);\nsin_lat := SIN(rlat);\ncos_lat := COS(rlat);\ncos_tau := COS(tau);\nt1 := cos_tau * sin_lat - TAN(c) * cos_lat;\nB := ATAN(SIN(tau) / t1);\nIF t1< 0.0 THEN B := B + math.PI2; ELSE B := B + math.PI; END_IF;\nB := DEG(MODR(B, math.PI2));\nh := DEG(ASIN(COS(C) * cos_tau * cos_lat +SIN(c) * sin_lat));\nIF h > 180.0 THEN h := h - 360.0; END_IF;\n(* consider refraction *)\nHR := h + REFRACTION(h);\n\n\n(* revision history\nhm\t1. feb 2007\trev 1.0\n\toriginal version\n\nhm\t6. jan 2008\trev 1.1\n\tperformance improvements\n\nhm\t18. jan 2008\trev 1.2\n\tfurther performance improvements\n\tonly calculate once every 10 seconds\n\nhm\t16. mar. 2008\trev 1.3\n\tadded type conversion to avoid warnings under codesys 3.0\n\nhm\t30. jun. 2008\trev 1.4\n\tadded type conversions to avoid warnings under codesys 3.0\n\nhm\t18. oct. 2008\trev 1.5\n\tusing math constants\n\nhm\t17. dec. 2008\trev 1.6\n\tangles below horizon are displayed in negative degrees\n\nhm\t27. feb. 2009\trev 2.0\n\tnew code with better accuracy\n\nhm\t7. mar. 2009\trev 2.1\n\trefraction is added after angle normalization\n\tdeleted 10 second lockout\n\tadded output for astronomical heigth h\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "SUN_TIME.st", - "source": "FUNCTION_BLOCK SUN_TIME\nVAR_INPUT\n\tLATITUDE : REAL;\t\t\t\t(* latitude of geographical position *)\n\tLONGITUDE : REAL;\t\t\t\t(* longitude of geographical position *)\n\tUTC : DATE;\t\t\t\t\t\t(*\tworld time\t*)\n\tH : REAL := -0.83333333333;\t(* heighth above horizon for sunrise *)\nEND_VAR\nVAR_OUTPUT\n\tMIDDAY : TOD;\t\t\t(*\tastrological midday in hours when sun stands at south direction\t*)\n\tSUN_RISE : TOD;\t\t\t\t(*\tsun rise for current day in local time *)\n\tSUN_SET : TOD;\t\t\t\t(*\tsun set for current day in local time *)\n\tSUN_DECLINATION : REAL;\t\t(*\tsun declination above horizon at midday in degrees\t*)\nEND_VAR\nVAR\n\tdk: REAL;\t\t\t\t\t\t(* sun declination at midday *)\n\tdelta: TIME;\t\t\t\t\t(* delta from midday for sunrise and sunset *)\n\tb: REAL;\nEND_VAR\n\n(*\nversion 1.7\t25. jan. 2011\nprogrammer \thugo\ntested by\ttobias\n\nthis FUNCTION block calculates the sun rise, sun set, sun offset at midday sun declination for a given date \nfor performance reasons the algorithm has been simplified and is accurate within a few minutes only \nthe times are calculated in utc and have to be corrected for the given time zone\nthis correction is not done within sun_time because it would be a problem on days where dst is enabled or disabled\n\n*)\n\nB := latitude * 0.0174532925199433;\nMIDDAY := SUN_MIDDAY(longitude, utc);\nDK := 0.40954 * SIN(0.0172 * (INT_TO_REAL(DAY_OF_YEAR(utc)) - 79.35));\nsun_declination := DEG(DK);\nIF sun_declination > 180.0 THEN sun_declination := sun_declination - 360.0; END_IF;\nsun_declination := 90.0 - LATITUDE + sun_declination;\ndelta := HOUR_TO_TIME(ACOS((SIN(RAD(H)) - SIN(B) * SIN(DK)) / (COS(B) * COS(DK))) * 3.819718632);\nsun_rise := MIDDAY - delta;\nsun_set := MIDDAY + delta;\n\n(* revision history\n\nrev 1.1\thm\t20.1.2007\n\tdeleted unused variables sun_riseR and sun_setR\n\nrev 1.2 hm 17.4.2007\n\tcorrected error while sun:midday would not be corrected for longitude.\n\nrev 1.3\thm\t6. jan 2008\n\tperformance improvements\n\nrev\t1.4 hm\t17. jan 2008\n\tcalculation is now only performed once a day\n\nhm\t10. mar. 2009\trev 1.5\n\timproved performance\n\tcalculation will be performed on every call to allow movong installations\n\nhm\t26. jul 2009\trev 1.6\n\tfixed a problem with wrong midday calculation\n\nhm\t25. jan. 2011\trev 1.7\n\tusing function sun_midday\n\tcorrected angle of sun_declination\n\tadded input H\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "SWAP_BYTE.st", - "source": "FUNCTION SWAP_BYTE : WORD\nVAR_INPUT\n\tIN : WORD;\nEND_VAR\n\n\n(*\nversion 1.0\t4 feb 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nThis function swaps the high and low byte of the word in.\n\n*)\n\nSWAP_BYTE := ROL(in,8);\n\n\n(* revision history\nhm\t\t4. feb 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "SWAP_BYTE2.st", - "source": "FUNCTION SWAP_BYTE2 : DWORD\nVAR_INPUT\n\tIN : DWORD;\nEND_VAR\n\n\n(*\nversion 1.0\t4 feb 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nThis function reverses the byte order in the dword.\n\n*)\n\nSwap_Byte2 := (ROR(in,8) AND 16#FF00FF00) OR (ROL(in,8) AND 16#00FF00FF);\n\n(* revision history\nhm\t\t4. feb 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "TANC.st", - "source": "FUNCTION TANC : REAL\nVAR_INPUT\n\tX : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t10. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nthis function calculates the tanc function.\n\n*)\n\nIF X = 0.0 THEN\n\tTANC := 1.0;\nELSE\n\tTANC := TAN(x) / x;\nEND_IF;\n\n\n(* revision histroy\nhm\t23. oct. 2008\trev 1.0\n\toriginal version\n\nhm 10. mar. 2009\trev 1.1\n\treal constants updated to new systax using dot\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "TANH.st", - "source": "FUNCTION TANH : REAL\nVAR_INPUT\n\tX : REAL;\nEND_VAR\n\n\n(*\nversion 1.3\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the tangens hyperbolicus\n\n*)\n\nIF X > 20.0 THEN\n\tTANH := 1.0;\nELSIF X < -20.0 THEN\n\tTANH := -1.0;\nELSE\n\tTANH := 1.0 - 2.0 / (EXP(2.0 * x) + 1.0);\nEND_IF;\n\n\n(* revision hisdtory\nhm\t\t12.1.2007\t\trev 1.0\n\toriginal version\n\nhm\t\t1.12.2007\t\trev 1.1\n\tchanged code to improve performance\n\nhm\t\t10. mar 2008\trev 1.2\n\tcorrected an error in formula\n\textended range of valid inputs to +/- INV\n\nhm 10. mar. 2009\trev 1.3\n\treal constants updated to new systax using dot\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "TC_MS.st", - "source": "FUNCTION_BLOCK TC_MS\n\nVAR_OUTPUT\n\tTC : DWORD;\nEND_VAR\nVAR\n\tinit: BOOL;\n\ttx: DWORD;\n\tlast: DWORD;\nEND_VAR\n\n(*\n\tversion 1.0\t13 mar 2008\n\tprogrammer \thugo\n\ttested by\t\ttobias\n\nTC_MS delivers the time it was last called on the output TC in Milliseconds.\n\n*)\n\n(* read system timer *)\ntx := T_PLC_MS();\n\nIF NOT init THEN\n\tinit := TRUE;\n\tTC := 0;\nELSE\n\ttc := tx - last;\nEND_IF;\nlast := tx;\n\n(* revision history\nhm\t\t13. mar. 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "TC_S.st", - "source": "FUNCTION_BLOCK TC_S\n\nVAR_OUTPUT\n\tTC : REAL;\nEND_VAR\nVAR\n\tinit: BOOL;\n\ttx: DWORD;\n\tlast: DWORD;\nEND_VAR\n\n(*\n\tversion 1.2\t11. mar. 2009\n\tprogrammer \thugo\n\ttested by\t\ttobias\n\nTC_S delivers the time it was last called on the output TC in seconds.\n\n*)\n\n(* read system timer *)\ntx := T_PLC_US();\n\nIF NOT init THEN\n\tinit := TRUE;\n\tTC := 0.0;\nELSE\n\ttc := DWORD_TO_REAL(tx - last)*1.0E-6;\nEND_IF;\nlast := tx;\n\n(* revision history\nhm\t13. mar. 2008\trev 1.0\n\toriginal version\n\nhm\t16. mar 2008\trev 1.1\n\tadded type conversion to avoid warnings under codesys 3.0\n\nhm\t11. mar. 2009\trev 1.2\n\tchanged real constants to use dot syntax\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "TC_US.st", - "source": "FUNCTION_BLOCK TC_US\n\nVAR_OUTPUT\n\tTC : DWORD;\nEND_VAR\nVAR\n\tinit: BOOL;\n\ttx: DWORD;\n\tlast: DWORD;\nEND_VAR\n\n(*\n\tversion 1.0\t13 mar 2008\n\tprogrammer \thugo\n\ttested by\t\ttobias\n\nTC_US delivers the time it was last called on the output TC in Microseconds.\n\n*)\n\n(* read system timer *)\ntx := T_PLC_US();\n\nIF NOT init THEN\n\tinit := TRUE;\n\tTC := 0;\nELSE\n\ttc := tx - last;\nEND_IF;\nlast := tx;\n\n(* revision history\nhm\t\t13. mar. 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "TEMPERATURE.st", - "source": "FUNCTION_BLOCK TEMPERATURE\nVAR_INPUT\n\tK : REAL;\n\tC : REAL := -273.15;\n\tF : REAL := -459.67;\n\tRe : REAL := -218.52;\n\tRa : REAL;\nEND_VAR\nVAR_OUTPUT\n\tYK : REAL;\n\tYC : REAL;\n\tYF : REAL;\n\tYRe : REAL;\n\tYRa : REAL;\nEND_VAR\n\n\n(*\nversion 1.0\t21 feb 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function converts different temperature units\nany unused input can simply be left open.\ndifferent inputs connected at the same time will be added up.\n\n*)\n\nYK := K + (C + 273.15) + (F + 459.67) * 0.555555555555 + (Re * 1.25 + 273.15) + (Ra * 0.555555555555);\nYC := YK -273.15;\nYF := YK * 1.8 - 459.67;\nYRe := (YK - 273.15) * 0.8;\nYRa := YK * 1.8;\n\n\n(* revision history\nhm\t21. feb. 2008\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "TEMP_NI.st", - "source": "FUNCTION TEMP_NI : REAL\nVAR_INPUT\n\tRes : REAL;\n\tR0 : REAL;\nEND_VAR\n\n\n(*\nversion 1.5\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function returns the temperature for a nickel sensor in a range from -60..+180 °C *)\n\nTEMP_NI := (SQRT(0.30085225 - 2.66E-3 * (R0 - Res)) - 0.5485) * 751.8796992;\n\n\n(* revision history\n\nhm 24.1.2007\t\trev 1.1\n\tdeleted unused variable A, B, C\n\nhm 10.9.2007\t\trev 1.2\n\tchanged accuracy to 0.02 degrees to improove performace\n\nhm 17. 12 2007\trev 1.3\n\timproovements for better performance and higher accuracy\n\nhm\t6. jan 2008\trev 1.4\n\tfurther performance improvement\n\nhm\t10. mar. 2009\trev 1.5\n\tremoved nested comments\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "TEMP_NTC.st", - "source": "FUNCTION TEMP_NTC : REAL\nVAR_INPUT\n\tRES : REAL;\n\tRN : REAL;\n\tB : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t11. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function returs the temperature for a NTC sensor for a range from 0..85 °C.\nRN is the resistance at 25 °C and B is a constant for the given sensor.\n\n*)\n\nIF res > 0.0 THEN\n\tTEMP_NTC := B * 298.15 / (B + LN(RES / RN) * 298.15) -273.15;\nEND_IF;\n\n\n(* revision history\n\nhm 30. dec. 2008\trev 1.0\n\toriginal version\n\nhm\t11. mar. 2009\trev 1.1\n\tchanged real constants to use dot syntax\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "TEMP_PT.st", - "source": "FUNCTION TEMP_PT : REAL\nVAR_INPUT\n\tRes : REAL;\n\tR0 : REAL;\nEND_VAR\nVAR CONSTANT\n\tA : REAL := 3.9083E-3 ;\n\tB : REAL := -5.775E-7;\n\taccuracy : REAL := 0.01;\nEND_VAR\nVAR\n\tstep: REAL := 50.0;\n\tX: REAL;\n\tY: REAL;\n\tt1: REAL;\n\tpt : POINTER TO DWORD;\nEND_VAR\n\n(*\nversion 1.7\t11. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nthis function returs the temperature for a platinum sensor for a range from -200..+850 °C *)\n\nX := A * R0;\nY := B * R0;\nIF Res >= R0 THEN\n\tt1 := X * X - 4.0 * Y * (R0 - Res);\n\tIF t1 < 0.0 THEN\n\t\tTEMP_PT := 10000.0;\n\tELSE\n\t\tTEMP_PT := (-X + SQRT(t1)) / (2.0 * Y);\n\tEND_IF;\nELSE\n\tpt := ADR(step);\n\t(* since the formula cannot be solved this is a successive approximation *)\n\tTEMP_PT := -100.0;\n\tWHILE step > accuracy DO\n\t\t(* test if result greater or less *)\n\t\tIF RES_PT(TEMP_PT, R0) < res THEN TEMP_PT := TEMP_PT + step; ELSE TEMP_PT := TEMP_PT - step; END_IF;\n\t\tpt^ := pt^ - 8388608; (* this is a super fast divide by 2 method for non floating point CPUs *)\n\t\t(* the alternative code: step := step * 0.5; *)\n\tEND_WHILE;\nEND_IF;\n\n(* revision history\n\nrev 1.1 hm 24.1.2007\t\n\tdeleted unused variable C\n\nrev 1.2 hm 10.9.2007\n\treduced accuracy to 0.02 to shorten execution time\n\nrev 1.3\thm\t2. dec 2007\n\tchanged code for better performance\n\nrev\t1.4\thm\t23. dec 2007\n\tavoid a negative square root if input values are wrong\n\nrev 1.5 hm\t5. jan 2008\n\treplaced / 2 with * 0.5 for better performance\n\nhm\t31. oct. 2008\trev 1.6\n\timproved performance\n\nhm\t11. mar. 2009\trev 1.7\n\tchanged real constants to use dot syntax\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "TEMP_SI.st", - "source": "FUNCTION TEMP_SI : REAL\nVAR_INPUT\n\tRes : REAL;\n\tRS : REAL;\n\tTS : REAL;\nEND_VAR\n\n\n(*\nversion 1.5\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function returs the temperature for a silicon sensor for a range from -60..+180 °C\nfor example KTY10 RS at TS normally 25 °C\n*)\n\nTEMP_SI := (-7.64E-3 + SQRT(Res / RS * 6.64E-5 - 0.803E-5)) * 30120.48193 + TS;\n\n\n\n(* revision history\n\nhm 24.1.2007\t\trev 1.1\n\tthe function would only work for TS = 25, now it works for other values of ts.\n\nhm 10.9.2007\t\trev 1.2\n\tchanged the function to use successive approcimation to avoid an error generated by a sqrt from a negative result.\n\tchanged accuracy to 0.02 degrees to shorten execution time\n\nhm 17. 12 2007\trev 1.3\n\timproovements for better performance\n\nhm\t6. jan 2008\trev 1.4\n\tfurther performance improvement\n\nhm\t10. mar. 2009\trev 1.5\n\tremoved nested comments\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "TICKER.st", - "source": "FUNCTION_BLOCK TICKER\n\nVAR_INPUT\n\tN : INT;\n\tPT : TIME;\nEND_VAR\n\nVAR_IN_OUT\n\tText : STRING(STRING_LENGTH);\nEND_VAR\n\nVAR_OUTPUT\n\tDisplay : STRING(STRING_LENGTH);\nEND_VAR\nVAR\n\tdelay : TP;\n\tstep : INT;\nEND_VAR\n\n(*\nversion 1.2\t29. mar. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nTicker sends a substring of text with length N every TD Milliseconds to generate a ticker. \n\n*)\n\n\n(* generate next ticker when delay is low *)\nIF N < LEN(text) THEN\n\tIF NOT delay.Q THEN\n\t\t(* increase step for next tick *)\n\t\tstep := step + 1;\n\t\tIF step > LEN(text) THEN step := 1; END_IF;\n\t\t(* extract dispay from text *)\n\t\tdisplay := MID(text, N, step);\n\t\t(* set delay timer for next tick *)\n\t\tdelay(in := TRUE, PT := PT);\n\tELSE;\n\t\t(* execute delay timer *)\n\t\tdelay(in := FALSE);\n\tEND_IF;\nELSE\n\tdisplay := text;\nEND_IF;\n(* revision history\nhm\t4. dec. 2007\trev 1.0\n\toriginal version\n\nhm\t15. dec. 2007\trev 1.1\n\tstep now starts at 1 instaed of 0\n\nhm\t29. mar. 2008\trev 1.2\n\tchanged STRING to STRING(STRING_LENGTH)\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "TIMECHECK.st", - "source": "FUNCTION TIMECHECK : BOOL\nVAR_INPUT\n\tTD : TOD;\n\tSTART : TOD;\n\tSTOP : TOD;\nEND_VAR\n\n\n(*\nversion 1.0\t19. jul. 2009\nprogrammer \toscat\ntested by\t\toscat\n\nthis function retruns true if the daytime TD is between start and stop and returns true if so.\nif you want to generate an event to span over midnight, start timemust be later than the stop time.\n\n*)\n\nIF stop < start THEN\n\tTIMECHECK := start <= TD OR TD < stop;\nELSE\n\tTIMECHECK := start <= TD AND TD < stop;\nEND_IF;\n\n\n\n(* revision history\nhm 19. jul. 2009\trev 1.0\n\toriginal release\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "TIMER_EVENT.st", - "source": "TYPE TIMER_EVENT :\nSTRUCT\n\tTYP : BYTE;\n\tCHANNEL : BYTE;\n\tDAY : BYTE;\n\tSTART : TOD;\n\tDURATION : TIME;\n\tLAND : BYTE;\n\tLOR : BYTE;\n\tLAST : DT;\nEND_STRUCT\nEND_TYPE\n" - }, - { - "fileName": "TOGGLE.st", - "source": "FUNCTION_BLOCK TOGGLE\nVAR_INPUT\n\tCLK : BOOL;\n\trst : BOOL;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\nEND_VAR\nVAR\n\tedge : BOOL;\nEND_VAR\n\n(*\nversion 1.1\t30. oct. 2008\nprogrammer \thugo\ntested by\toscat\n\ntoggle flip flop the output changes state with every rising edge of clk.\n\n*)\n\nIF rst THEN\n\tq := 0;\nELSIF clk AND NOT edge THEN\n\tQ := NOT Q;\nEND_IF;\nedge := clk;\n\n(* revision history\n\nhm\t13.9.2007\t\trev 1.0\n\toriginal version\n\nhm\t30. oct. 2008\trev 1.1\n\tdeleted unnecessary init\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "TONOF.st", - "source": "FUNCTION_BLOCK TONOF\nVAR_INPUT\n\tIN : BOOL;\n\t T_ON,T_OFF : TIME;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\nEND_VAR\nVAR\n X : TON;\n old: BOOL;\n mode: BOOL;\nEND_VAR\n\n(*\nversion 1.2\t21. jul 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nTONOF generated a TON and TOF Delay for the Input N TON (T1) and TOF (T2) can be configured separately\n*)\n\nIF IN XOR old THEN\n X(IN := FALSE, PT := SEL(IN,T_OFF,T_ON));\n mode := IN;\n old := IN;\nEND_IF;\nX(IN := TRUE);\nIF X.Q THEN Q := mode;END_IF;\n\n(* revision history\nhm\t10. dec 2007\trev 1.0\n\toriginal version\n\nhm\t17. sep. 2007\trev 1.1\n\timproved performance\n\nhm\t21. jul. 2009\trev 1.2\n\tfixed a timing probelm\n\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "TO_LOWER.st", - "source": "FUNCTION TO_LOWER : BYTE\nVAR_INPUT\n\tIN : BYTE;\nEND_VAR\n\n\n(*\nversion 1.2\t25. oct 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nto_lower converts a character from uppercase to lowercase\n\n*)\n\nIF in > 64 AND in < 91 THEN\n TO_LOWER := in OR 16#20;\nELSIF (in > 191 AND in < 223) AND in <> 215 AND setup.EXTENDED_ASCII THEN\n TO_LOWER := in OR 16#20;\nELSE\n TO_LOWER := in;\nEND_IF;\n\n\n(* revision history\nhm\t6. mar. 2008\trev 1.0\n\toriginal version\n\nhm\t19. oct. 2008\trev 1.1\n\tchanged setup constants\n\nks\t25. oct. 2008\trev 1.2\n\toptimized code\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "TO_UML.st", - "source": "FUNCTION TO_UML : STRING(2)\nVAR_INPUT\n\tIN : BYTE;\nEND_VAR\n\n\n(*\nversion 1.1\t17. dec. 2008\nprogrammer \t\thugo\ntested by\t\ttobias\n\nto_uml converts a character above 127 to a two digit character below 127.\nthe character Ä is converted to Ae\n\n*)\n\nCASE in OF\n\t196:\t(* Ä *)\n\t\tTO_UML := 'Ae';\n\t214:\t(* Ö *)\n\t\tTO_UML := 'Oe';\n\t220:\t(* Ü *)\n\t\tTO_UML := 'Ue';\n\t223:\t(* ß *)\n\t\tTO_UML := 'ss';\n\t228:\t(* ä *)\n\t\tTO_UML := 'ae';\n\t246:\t(* ö *)\n\t\tTO_UML := 'oe';\n\t252:\t(* ü *)\n\t\tTO_UML := 'ue';\nELSE\n\tTO_UML := CHR_TO_STRING(IN);\nEND_CASE;\n\n\n\n(* revision history\nhm\t29. mar. 2008\trev 1.0\n\toriginal version\n\nhm\t17. dec. 2008\trev 1.1\n\tchanges name of function chr to chr_to_string\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "TO_UPPER.st", - "source": "FUNCTION TO_UPPER : BYTE\nVAR_INPUT\n\tIN : BYTE;\nEND_VAR\n\n\n(*\nversion 1.3\t16. jan. 2009\nprogrammer \thugo\ntested by\t\toscat\n\nto_upper converts a character from lowercase to uppercase\n\n*)\n\nIF in > 96 AND in < 123 THEN\n TO_UPPER := in AND 16#DF;\nELSIF in > 223 AND in <> 247 AND in <> 255 AND setup.EXTENDED_ASCII THEN\n TO_UPPER := in AND 16#DF;\nELSE\n TO_UPPER := in;\nEND_IF;\n\n\n\n\n(* revision history\nhm\t6. mar. 2008\trev 1.0\n\toriginal version\n\nhm\t19. oct. 2008\trev 1.1\n\tchanged setup constants\n\nks\t25. oct. 2008\trev 1.2\n\toptimized code\n\nhm 16. jan 2009\trev 1.3\n\tcorrected an error in module\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "TP_X.st", - "source": "FUNCTION_BLOCK TP_X\nVAR_INPUT\n\tIN : BOOL;\n\tPT : TIME;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\n\tET : TIME;\nEND_VAR\nVAR\n\tedge : BOOL;\n\tstart : TIME;\n\ttx: TIME;\nEND_VAR\n\n(*\nversion 1.3\t17. dec. 2008\nprogrammer \thugo\ntested by\toscat\n\nretriggerable edge triggered pulse similar to TP but with a retrigger function\nif the pt input is 0 then output is always low.\n*)\n\n(* read system_time *)\ntx := DWORD_TO_TIME(T_PLC_MS());\n\n(* rising edge trigger *)\nIF IN AND NOT edge THEN\n\tstart := tx;\n\tQ := PT > t#0ms;\nELSIF Q THEN\n\tET := tx - start;\n\tIF ET >= PT THEN\n\t\tQ := FALSE;\n\t\tET := t#0ms;\n\tEND_IF;\nEND_IF;\nedge := IN;\n\n(* revision history\nhm\t4. aug 2006\t\trev 1.0\n\toriginal version\n\nhm\t17. sep 2007\trev 1.1\n\treplaced time() with T_PLC_MS() for compatibility reasons\n\nhm\t19. oct. 2008\trev 1.2\n\trenamed to TP_R to TP_X for compatibility reasons\n\nhm\t17. dec. 2008\trev 1.3\n\tcode optimized\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "TREND.st", - "source": "FUNCTION_BLOCK TREND\nVAR_INPUT\n\tX : REAL;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\n\tTU : BOOL;\n\tTD : BOOL;\n\tD : REAL;\nEND_VAR\nVAR\n\tlast_X: REAL;\nEND_VAR\n\n(*\nversion 1.0\t21. aug. 2009\nprogrammer \thugo\ntested by\t\toscat\n\ntrend analyses the trend of a input signal.\nThe Output Q is True if the input X is >= last_X and is false if the input X is <= last_X\nin addition to the trend the output TU will be high for one cycle to signal a rising of the input value X\nand TD will signal a decreasing value on the input X.\nin case of a change the output D will show the delta of the input to the last input value.\n\n*)\n\nTU := X > last_X;\nTD := X < last_X;\nQ := TU OR TD;\nD := X - LAST_X;\n\nlast_X := X;\n\n\n\n(* revision history\nhm\t21. aug. 2009\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "TREND_DW.st", - "source": "FUNCTION_BLOCK TREND_DW\nVAR_INPUT\n\tX : DWORD;\nEND_VAR\nVAR_OUTPUT\n\tQ : BOOL;\n\tTU : BOOL;\n\tTD : BOOL;\n\tD : DWORD;\nEND_VAR\nVAR\n\tlast_X: DWORD;\nEND_VAR\n\n(*\nversion 1.2\t14. mar. 2009\nprogrammer \thugo\ntested by\t\toscat\n\ntrend_DW analyses the trend of a input signal.\nThe Output Q is True if the input X is >= last_X and is false if the input X is <= last_X\nin addition to the trend the output TU will be high for one cycle to signal a rising of the input value X\nand TD will signal a decreasing value on the input X.\nin case of a change the output D will show the delta of the input to the last input value.\n\n\n*)\n\nIF X > last_X THEN\n\tTU := TRUE;\n\tTD := FALSE;\n\tD := X - last_X;\n\tQ := TRUE;\nELSIF X < last_X THEN\n\tTD := TRUE;\n\tTU := FALSE;\n\tD := last_X - X;\n\tQ := FALSE;\nELSE\n\tTU := FALSE;\n\tTD := FALSE;\n\tD := 0;\nEND_IF;\nlast_X := X;\n\n\n\n(* revision history\nhm\t21. nov. 2008\trev 1.0\n\toriginal version\n\nhm\t20. feb. 2009\trev 1.1\n\tadded outputs TU, TD and D\n\nhm\t14. mar. 2009\trev 1.2\n\tremoved double assignments\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "TRIANGLE_A.st", - "source": "FUNCTION TRIANGLE_A : REAL\nVAR_INPUT\n\tS1 : REAL;\n\tA : REAL;\n\tS2 : REAL;\n\tS3 : REAL;\nEND_VAR\n\n\n(*\nversion 1.2\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\ntriangle_A calculates the Area of a triangle.\nif any input is 0 it will be neglected and the are will be calculated from eiter:\ntwo sides and an angle (s1 and S2 and the angle A1) or 3 sides.\n\n\n*)\n\nIF A = 0.0 THEN\n\tTRIANGLE_A := SQRT((s1+s2+S3) * (s1+s2-S3) * (S2+S3-S1) * (S3+S1-S2)) * 0.25;\nELSE\n\tTRIANGLE_A := S1 * S2 * SIN(RAD(A)) * 0.5;\nEND_IF;\n\n(* revision histroy\nhm\t16. oct 2007\trev 1.0\n\toriginal version\n\nhm\t22. feb 2008\trev 1.1\n\timproved performance\n\nhm\t10. mar. 2009\trev 1.2\n\tchanged syntax of real constants to 0.0\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "TRIM.st", - "source": "FUNCTION TRIM : STRING(STRING_LENGTH)\nVAR_INPUT\n\tstr : STRING(STRING_LENGTH);\nEND_VAR\nVAR\n\tpos: INT;\nEND_VAR\n\n(*\nversion 1.2\t29. mar. 2008\nprogrammer \thugo\ntested by\ttobias\n\nthe function deletes all blanks within a string.\n\n*)\n\nTRIM := str;\nREPEAT\n\tpos := FIND(trim,' ');\n\tIF pos > 0 THEN TRIM := REPLACE(TRIM,'',1,pos); END_IF;\nUNTIL pos = 0\tEND_REPEAT;\n\n\n(* revision histroy\nhm\t6.10.2006\t\trev 1.0\n\toriginal release\n\nhm\t20. mar. 2008\trev 1.1\n\tavoid to call replace with pos = 0 because some systems will produce an error\n\nhm\t29. mar. 2008\trev 1.2\n\tchanged STRING to STRING(STRING_LENGTH)\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "TRIM1.st", - "source": "FUNCTION TRIM1 : STRING(STRING_LENGTH)\nVAR_INPUT\n\tstr : STRING(STRING_LENGTH);\nEND_VAR\nVAR\n\tpos: INT;\nEND_VAR\n\n(*\nversion 1.2\t29. mar. 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nthe function replaces all multiple blanks within a string by only one blank.\nleading and ending blanks will be deleted\n\n*)\n\nTRIM1 := str;\nREPEAT\n\tpos := FIND(trim1,' ');\n\tIF pos > 0 THEN TRIM1 := REPLACE(TRIM1,' ',2,pos); END_IF;\nUNTIL pos = 0\tEND_REPEAT;\n(* beginning and ending blanks need to be stripped off *)\nIF LEFT(trim1,1) = ' ' THEN trim1 := DELETE(trim1,1,1); END_IF;\nIF RIGHT(trim1,1) = ' ' THEN trim1 := DELETE(trim1,1,LEN(trim1)); END_IF;\n\n\n(* revision histroy\nhm\t4. feb. 2008 rev 1.0\n\toriginal release\n\nhm\t20. mar. 2008\trev 1.1\n\tavoid to call replace with pos = 0 because some systems will produce an error\n\nhm\t29. mar. 2008\trev 1.2\n\tchanged STRING to STRING(STRING_LENGTH)\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "TRIME.st", - "source": "FUNCTION TRIME : STRING(string_length)\nVAR_INPUT\n\tstr : STRING(STRING_LENGTH);\nEND_VAR\n\n\n(*\nversion 1.0\t28. mar. 2008\nprogrammer \thugo\ntested by\ttobias\n\nthis function deletes all leading and ending blanks of a string.\n\n*)\n\nTRIME := str;\n(* beginning blanks need to be stripped off *)\nWHILE LEFT(TRIME,1) = ' ' DO\n\tTRIME := DELETE(TRIME,1,1);\nEND_WHILE;\n\n(* ending blanks need to be stripped off *)\nWHILE RIGHT(TRIME,1) = ' ' DO\n\tTRIME := DELETE(TRIME,1,LEN(TRIME));\nEND_WHILE;\n\n\n(* revision histroy\nhm\t28. mar. 2008\trev 1.0\n\toriginal release\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "TUNE.st", - "source": "FUNCTION_BLOCK TUNE\nVAR_INPUT\n\tSET : BOOL;\n\tSU, SD : BOOL;\n\tRST : BOOL;\nEND_VAR\nVAR_INPUT CONSTANT\n\tSS : REAL := 0.1;\n\tLimit_L : REAL;\n\tLIMIT_H : REAL := 100.0;\n\tRST_val : REAL;\n\tSET_val : REAL := 100.0;\n\tT1 : TIME := T#500ms;\n\tT2 : TIME := T#2s;\n\tS1 : REAL := 2.0;\n\tS2 : REAL := 10.0;\nEND_VAR\nVAR_OUTPUT\n\tY : REAL;\nEND_VAR\nVAR\n\ttx : DWORD;\n\tstart, start2 : DWORD;\n\tstate : INT;\n\tin : BOOL;\n\tstep : REAL;\n\tSPEED : REAL;\n\tY_start : REAL;\n\tY_start2: REAL;\nEND_VAR\n\n(*\nversion 1.2\t11. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\ntune generates an output signal which is set by input switches.\nup to 4 switsches can be used to tune the signal up or down.\n\n*)\n\n(* read system time *)\ntx := T_PLC_MS();\n\nIF rst THEN\n\tY := RST_val;\n\tstate := 0;\nELSIF set THEN\n\tY := SET_val;\n\tstate := 0;\nELSIF state > 0 THEN\n\t(* key has been pushed state machine operating *)\n\t(* first read the correct input *)\n\tIF state = 1 THEN\n\t\t(* step up *)\n\t\tin := su;\n\tELSE\n\t\t(* step down *)\n\t\tin := sd;\n\tEND_IF;\n\t(* check for single step operation *)\n\tIF NOT in AND tx - start <= TIME_TO_DWORD(T1) THEN\n\t\tY := Y_start + step;\n\t\tstate := 0;\n\t(* check if fast ramp needs to be generated *)\n\tELSIF in AND tx - start >= TIME_TO_DWORD(T2) THEN\n\t\tY := Y_start2 + DWORD_TO_REAL(tx - start2) * s2 / speed;\n\t(* check if slow ramp needs to be generated *)\n\tELSIF in AND tx - start >= TIME_TO_DWORD(T1) THEN\n\t\tY := Y_start + DWORD_TO_REAL(tx - start - TIME_TO_DWORD(T1)) * S1 / speed;\n\t\tstart2 := tx;\n\t\tY_start2 := Y;\n\tELSIF NOT in THEN\n\t\tstate := 0;\n\tEND_IF;\nELSIF su THEN\n\t(* slow step up *)\n\tstate := 1;\n\tstart := tx;\n\tstep := ss;\n\tspeed := 1000.0;\n\tY_start := Y;\nELSIF sd THEN\n\t(* slow step down *)\n\tstate := 2;\n\tstart := tx;\n\tstep := -ss;\n\tspeed := -1000.0;\n\tY_start := Y;\nEND_IF;\n\n(* make sure output does not exceed limits *)\nY := LIMIT(LIMIT_L, Y, LIMIT_H);\n\n(* revision history\nhm\t3.11.2007\t\trev 1.0\n\toriginal version\n\nhm\t16. mar. 2008\trev 1.1\n\tadded type conversions to avoid warnings under codesys 3.0\n\nhm\t11. mar. 2009\trev 1.2\n\treal constants updated to new systax using dot\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "TUNE2.st", - "source": "FUNCTION_BLOCK TUNE2\nVAR_INPUT\n\tSET : BOOL;\n\tSU, SD : BOOL;\n\tFU, FD : BOOL;\n\tRST : BOOL;\nEND_VAR\nVAR_INPUT CONSTANT\n\tSS : REAL := 0.1;\n\tFS : REAL := 5.0;\n\tLimit_L : REAL;\n\tLIMIT_H : REAL := 100.0;\n\tRST_val : REAL;\n\tSET_val : REAL := 100.0;\n\tTR : TIME := T#500ms;\n\tS1 : REAL := 2.0;\n\tS2 : REAL := 10.0;\nEND_VAR\nVAR_OUTPUT\n\tY : REAL;\nEND_VAR\nVAR\n\ttx : DWORD;\n\tstart : DWORD;\n\tstate : INT;\n\tin : BOOL;\n\tstep : REAL;\n\tSPEED : REAL;\n\tY_start : REAL;\nEND_VAR\n\n(*\nversion 1.2\t11. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\ntune2 generates an output signal which is set by input switches.\nup to 4 switsches can be used to tune the signal up or down.\n\n*)\n\n(* read system time *)\ntx := T_PLC_MS();\n\nIF rst THEN\n\tY := RST_val;\n\tstate := 0;\nELSIF set THEN\n\tY := SET_val;\n\tstate := 0;\nELSIF state > 0 THEN\n\t(* key has been pushed state machine operating *)\n\t(* first read the correct input *)\n\tCASE state OF\n\t\t1 :\t(* slow up *)\n\t\t\tin := su;\n\t\t2 :\t(* slow down *)\n\t\t\tin := sd;\n\t\t3 :\t(* fast up *)\n\t\t\tin := fu;\n\t\t4 :\t(* fast down *)\n\t\t\tin := fd;\n\tEND_CASE;\n\t(* check for single step operation *)\n\tIF NOT in AND tx - start <= TIME_TO_DWORD(TR) THEN\n\t\tY := Y_start + step;\n\t\tstate := 0;\n\t(* check if ramp needs to be generated *)\n\tELSIF in AND tx - start >= TIME_TO_DWORD(TR) THEN\n\t\tY := Y_start + DWORD_TO_REAL(tx - start - TIME_TO_DWORD(TR)) * speed;\n\tELSIF NOT in THEN\n\t\tstate := 0;\n\tEND_IF;\nELSIF su THEN\n\t(* slow step up *)\n\tstate := 1;\n\tstart := tx;\n\tstep := ss;\n\tspeed := s1 * 1.0E-3;\n\tY_start := Y;\nELSIF sd THEN\n\t(* slow step down *)\n\tstate := 2;\n\tstart := tx;\n\tstep := -ss;\n\tspeed := -s1 * 1.0E-3;\n\tY_start := Y;\nELSIF fu THEN\n\t(* fast step up *)\n\tstate := 3;\n\tstart := tx;\n\tstep := fs;\n\tspeed := s2 * 1.0E-3;\n\ty_start := Y;\nELSIF fd THEN\n\t(* fast step down *)\n\tstate := 4;\n\tstart := tx;\n\tstep := -fs;\n\tspeed := -s2 * 1.0E-3;\n\ty_start := Y;\nEND_IF;\n\n(* make sure output does not exceed limits *)\nY := LIMIT(LIMIT_L, Y, LIMIT_H);\n\n(* revision history\nhm\t3.11.2007\t\trev 1.0\n\toriginal version\n\nhm\t16. 3. 2008\trev 1.1\n\tadded type conversions to avoid warnings in codesys 3.0\n\timproved performance\n\nhm\t11. mar. 2009\trev 1.2\n\treal constants updated to new systax using dot\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "T_PLC_MS.st", - "source": "FUNCTION T_PLC_MS : DWORD\nVAR CONSTANT\n\tdebug : BOOL := 0;\n\tN : INT := 0;\n\toffset : DWORD := 0;\nEND_VAR\nVAR\n\ttx : TIME;\nEND_VAR\n\n(*\nversion 1.2\t16. nov 2008\nprogrammer \thugo\ntested by\toscat\n\nT_PLC_MS reads the internal PLC timer and return the time, it has the advantage to be able to set a debug mode \nand speed up the counter to test the plc timer overrun which occurs every 50 days respectively 25 days at siemens S7\nthis routine also allows to correct the behavior of s7 where the internal plc counter will not count all 32 bits.\n\n*)\n\ntx := TIME();\nT_PLC_MS := TIME_TO_DWORD(Tx);\n(* hier muss die korrektur für step7 stattfinden\nplctime muss den vollen wertebereich von time ausnutzen:\nwenn bei step7 time -24tage bis plus 24 tage ist dann muss der timer auch beim überlauf auf -24tage springen \nund auf keinen fall auf 0 !!!!\nfür siemens muss ein weiterer fb im main eingebunden werden der sicherstellt das alle 32 bits durchgezählt werden.\nes kann nur ein fb sein den er muss sich das oberste (32te) bit merken.\noder etwa spring s7 bei überlauf auf -24 tage????? dann wäre keine korrektur nötig.\n*)\nIF debug THEN\n\tT_PLC_MS := (SHL(T_PLC_MS,N) OR SHL(DWORD#1,N)-1) + OFFSET;\nEND_IF;\n\n(* revision history\nhm\t14.9.2007\trev 1.0\n\toriginal version\n\nhm\t12. nov 2007\trev 1.1\n\tadded temporaray variable tx because some compilers could not handle time() as an argument\n\nhm\t16. nov. 2008\trev 1.2\n\tinitialized constants with 0 for compatibility reasons\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "T_PLC_US.st", - "source": "FUNCTION T_PLC_US : DWORD\nVAR CONSTANT\n\tdebug : BOOL := 0;\n\tN : INT := 0;\n\toffset : DWORD := 0;\nEND_VAR\nVAR\n\ttx : TIME;\nEND_VAR\n\n(*\nversion 1.2\t16 nov 2008\nprogrammer \thugo\ntested by\ttobias\n\nT_PLC_US reads the internal PLC timer and return the time, it has the advantage to be able to set a debug mode \nand speed up the counter to test the plc timer overrun which occurs every 50 days respectively 25 days at siemens S7\nthis routine also allows to correct the behavior of s7 where the internal plc counter will not count all 32 bits.\n\n*)\n\ntx := TIME();\nT_PLC_US := TIME_TO_DWORD(Tx)*1000;\n(* hier muss die korrektur für step7 stattfinden\nplctime muss den vollen wertebereich von time ausnutzen:\nwenn bei step7 time -24tage bis plus 24 tage ist dann muss der timer auch beim überlauf auf -24tage springen \nund auf keinen fall auf 0 !!!!\nfür siemens muss ein weiterer fb im main eingebunden werden der sicherstellt das alle 32 bits durchgezählt werden.\nes kann nur ein fb sein den er muss sich das oberste (32te) bit merken.\noder etwa spring s7 bei überlauf auf -24 tage????? dann wäre keine korrektur nötig.\n*)\nIF debug THEN\n\tT_PLC_US := (SHL(T_PLC_US,N) OR SHL(DWORD#1,N)-1) + OFFSET;\nEND_IF;\n\n(* revision history\nhm\t14.9.2007\trev 1.0\n\toriginal version\n\nhm\t12. nov 2007\trev 1.1\n\tadded temporaray variable tx because some compilers could not handle time() as an argument\n\nhm\t16. nov. 2008\trev 1.2\n\tinitialized constants with 0 for compatibility reasons\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "UPPERCASE.st", - "source": "FUNCTION UPPERCASE : STRING(STRING_LENGTH)\nVAR_INPUT\n\tstr : STRING(STRING_LENGTH);\nEND_VAR\nVAR\n\tpt : POINTER TO BYTE;\n\tpos: INT;\n\tl: INT;\nEND_VAR\n\n(*\nversion 1.3\t29. mar. 2008\nprogrammer \thugo\ntested by\ttobias\n\nuppercase returns str while all letters a..z and ä,ö,ü are converted to uppercase\n\n*)\n\npt := ADR(UPPERCASE);\nUPPERCASE := str;\nl := LEN(str);\nFOR pos := 1 TO l DO\n\tpt^ := TO_UPPER(pt^);\n\tpt := pt + 1;\nEND_FOR;\n\n(* revision histroy\nhm\t6. oct. 2006\trev 1.0\n\toriginal release\n\nhm\t4. feb. 2008\trev 1.1\n\timproved performance\n\tadded Ä,Ö,Ü\n\nhm\t6. mar. 2008\trev 1.2\n\tadded support for exteded Ascii\n\nhm\t29. mar. 2008\trev 1.3\n\tchanged STRING to STRING(STRING_LENGTH)\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "UTC_TO_LTIME.st", - "source": "FUNCTION UTC_TO_LTIME : DT\nVAR_INPUT\n\tUTC : DT;\n\tDST_ENABLE : BOOL;\n\tTIME_ZONE_OFFSET : INT;\nEND_VAR\nVAR\n\ttmp: INT;\nEND_VAR\n\n(*\n\nversion 1.9\t27. feb. 2009\nprogrammer \toscat\ntested by\t\toscat\n\nltime is a real time clock that uses the system rtc as utc time and calculates and given time zone.\nthe utc time is supplied on the input UTC.\naccording to the input variable time_zone_offset when the input dst_enable is true,\nthe dst on and off times are calculated by a formula for any given year and the time is advanced and reset by one hour\nat 02:00 and 03:00 for the last sunday of march and last sunday of october.\nthe code is high performance and the rtc counts every second.\nif more then one time zone is needed by the systen the clock can be started many times by placing more then one function block.\n\n \n*)\n\ntmp := TIME_ZONE_OFFSET * 60 + BOOL_TO_INT(DST_ENABLE AND DST(UTC)) * 3600;\nIF tmp < 0 THEN\n\ttmp := ABS(tmp);\n\tUTC_TO_LTIME := DWORD_TO_DT(DT_TO_DWORD(UTC) - INT_TO_DWORD(tmp));\nELSE\n\tUTC_TO_LTIME := DWORD_TO_DT(DT_TO_DWORD(UTC) + INT_TO_DWORD(tmp));\nEND_IF;\n\n\n(* revision history\n\nhm 2.10.2006\trev 1.1\n\tcorrected an error where dst would be delayed by 0.1second\n\nhm 17.1.2007\trev 1.2\n\tadded utc input instead of internal sysrtcgettime because this would only work on wago.\n\tdst_enable would not be checked before dst would be enabled.\n\nhm 18.3.2007\trev 1.3\n\tchanged code, dst would not work during first cycle.\n\nhm 24.10.2007\trev 1.4\n\tchanged code because the execution every 100ms can cause major problems if the supplied time was not correct at start.\n\tuse of new dst function\n\nhm 12. nov 2007\trev 1.5\n\t\tchanged Type of time_zone_offset from time to int to allow for time zones with negative offset\n\nhm\t8 dec 2007\t\trev 1.6\n\tcorrected a problem with time_zone_offset\n\nhm\t14. oct. 2008\trev 1.7\n\trenamed module from LTIME to UTC_TO_LTIME\n\tchanged function weekday to day_of_week\n\toptimized code for better performance\n\nhm\t20. oct. 2008\trev 1.8\n\tchanges type of input TIME_ZONE_OFFSET from real to int, now is in +/-minutes\n\tdeleted outputs DST_ON and WDAY\n\tconverted to function\n\nhm\t27. feb. 2009\trev 1.9\n\tadded type conversions to avoid warnings under codesys 3.0\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "V3_ABS.st", - "source": "FUNCTION V3_ABS : REAL\nVAR_INPUT\n\tA : Vector_3;\nEND_VAR\n\n\n(*\nversion 1.0\t11 dec 2007\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the length of a vectors in a 3 dimensional space\n\n*)\n\nV3_ABS := SQRT(A.X * A.X + A.Y * A.Y + A.Z * A.Z);\n\n\n(* revision history\nhm\t\t11 dec 2007\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "V3_ADD.st", - "source": "FUNCTION V3_ADD : vector_3\nVAR_INPUT\n\tA : Vector_3;\n\tB : Vector_3;\nEND_VAR\n\n\n(*\nversion 1.0\t11 dec 2007\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function adds two vectors in a 3 dimensional space\n\n*)\n\nV3_ADD.X := A.X + B.X;\nV3_ADD.Y := A.Y + B.Y;\nV3_ADD.Z := A.Z + B.Z;\n\n\n\n(* revision history\nhm\t\t11 dec 2007\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "V3_ANG.st", - "source": "FUNCTION V3_ANG : REAL\nVAR_INPUT\n\tA : Vector_3;\n\tB : Vector_3;\nEND_VAR\nVAR\n\td : REAL;\nEND_VAR\n\n(*\nversion 1.1\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the angle between two vectors in a 3 dimensional space\n\n*)\n\nd := V3_ABS(A) * V3_ABS(B);\nIF d > 0 THEN\n\tV3_ANG := ACOS(LIMIT(-1.0, V3_DPRO(A, B) / d,1.0));\nEND_IF;\n\n(* revision history\nhm\t11. dec. 2007\trev 1.0\n\toriginal version\n\nhm\t10. mar. 2009\trev 1.1\n\tchanged syntax of real constants to 0.0\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "V3_DPRO.st", - "source": "FUNCTION V3_DPRO : REAL\nVAR_INPUT\n\tA : Vector_3;\n\tB : Vector_3;\nEND_VAR\n\n\n(*\nversion 1.0\t11 dec 2007\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the dot product of two vectors in 3 dimensional space\n\n*)\n\nV3_DPRO := A.X * B.X + A.Y * B.Y + A.Z * B.Z;\n\n\n(* revision history\nhm\t\t11 dec 2007\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "V3_NORM.st", - "source": "FUNCTION V3_NORM : vector_3\nVAR_INPUT\n\tA : Vector_3;\nEND_VAR\nVAR\n\tla: REAL;\nEND_VAR\n\n(*\nversion 1.1\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function generates a vectors with absolute length 1 from a vector A in a 3 dimensional space\n\n*)\n\nla := V3_ABS(A);\nIF la > 0.0 THEN\n\tV3_NORM := V3_SMUL(A, 1.0 / la);\nEND_IF;\n\n(* revision history\nhm\t11 dec 2007\trev 1.0\n\toriginal version\n\nhm\t10. mar. 2009\trev 1.1\n\tchanged syntax of real constants to 0.0\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "V3_NUL.st", - "source": "FUNCTION V3_NUL : BOOL\nVAR_INPUT\n\tA : Vector_3;\nEND_VAR\n\n\n(*\nversion 1.1\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function checks if a vectors in a null Vector\n\n*)\n\nV3_NUL := A.X = 0.0 AND A.Y = 0.0 AND A.Z = 0.0;\n\n\n\n(* revision history\nhm\t12 dec 2007\trev 1.0\n\toriginal version\n\nhm\t10. mar. 2009\trev 1.1\n\tchanged syntax of real constants to 0.0\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "V3_PAR.st", - "source": "FUNCTION V3_PAR : BOOL\nVAR_INPUT\n\tA : Vector_3;\n\tB : Vector_3;\nEND_VAR\n\n\n(*\nversion 1.1\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function checks if two vectors in a 3 dimensional space are parallel.\nwhich means the two vectors have the same direction\n\n*)\n\nV3_PAR := V3_ABS(V3_XPRO(A, B)) = 0.0;\n\n\n\n(* revision history\nhm\t11 dec 2007\trev 1.0\n\toriginal version\n\nhm\t10. mar. 2009\trev 1.1\n\tchanged syntax of real constants to 0.0\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "V3_REV.st", - "source": "FUNCTION V3_REV : vector_3\nVAR_INPUT\n\tA : Vector_3;\nEND_VAR\n\n\n(*\nversion 1.0\t11 dec 2007\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function reverses a vector in a 3 dimensional space\n\n*)\n\nV3_REV.X := -A.X;\nV3_REV.Y := -A.Y;\nV3_REV.Z := -A.Z;\n\n\n\n(* revision history\nhm\t\t11 dec 2007\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "V3_SMUL.st", - "source": "FUNCTION V3_SMUL : vector_3\nVAR_INPUT\n\tA : Vector_3;\n\tM : REAL;\nEND_VAR\n\n\n(*\nversion 1.0\t11 dec 2007\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function multiplies a vectors in a 3 dimensional space with a skalar M\n\n*)\n\nV3_SMUL.X := A.X * M;\nV3_SMUL.Y := A.Y * M;\nV3_SMUL.Z := A.Z * M;\n\n\n\n(* revision history\nhm\t\t11 dec 2007\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "V3_SUB.st", - "source": "FUNCTION V3_SUB : vector_3\nVAR_INPUT\n\tA : Vector_3;\n\tB : Vector_3;\nEND_VAR\n\n\n(*\nversion 1.0\t11 dec 2007\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function subtracts two vectors in a 3 dimensional space\nV3_SUB = A - B\n\n*)\n\nV3_SUB.X := A.X - B.X;\nV3_SUB.Y := A.Y - B.Y;\nV3_SUB.Z := A.Z - B.Z;\n\n\n\n(* revision history\nhm\t\t11 dec 2007\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "V3_XANG.st", - "source": "FUNCTION V3_XANG : REAL\nVAR_INPUT\n\tA : Vector_3;\nEND_VAR\nVAR\n\tla: REAL;\nEND_VAR\n\n(*\nversion 1.1\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the angle between the X-axis and a vectors in a 3 dimensional space\n\n*)\n\nla := V3_ABS(a);\nIF la > 0.0 THEN\n\tV3_XANG := ACOS(A.X / la);\nEND_IF;\n\n(* revision history\nhm\t11 dec 2007\trev 1.0\n\toriginal version\n\nhm\t10. mar. 2009\trev 1.1\n\tchanged syntax of real constants to 0.0\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "V3_XPRO.st", - "source": "FUNCTION V3_XPRO : vector_3\nVAR_INPUT\n\tA : Vector_3;\n\tB : Vector_3;\nEND_VAR\n\n\n(*\nversion 1.0\t11 dec 2007\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function adds two vectors in a 3 dimensional space\n\n*)\n\nV3_XPRO.X := A.Y * B.Z - A.Z * B.Y;\nV3_XPRO.Y := A.Z * B.X - A.X * B.Z;\nV3_XPRO.Z := A.X * B.Y - A.Y * B.X;\n\n\n\n(* revision history\nhm\t\t11 dec 2007\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "V3_YANG.st", - "source": "FUNCTION V3_YANG : REAL\nVAR_INPUT\n\tA : Vector_3;\nEND_VAR\nVAR\n\tla: REAL;\nEND_VAR\n\n(*\nversion 1.1\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the angle between the Y-axis and a vectors in a 3 dimensional space\n\n*)\n\nla := V3_ABS(a);\nIF la > 0.0 THEN\n\tV3_YANG := ACOS(A.Y / la);\nEND_IF;\n\n(* revision history\nhm\t11 dec 2007\trev 1.0\n\toriginal version\n\nhm\t10. mar. 2009\trev 1.1\n\tchanged syntax of real constants to 0.0\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "V3_ZANG.st", - "source": "FUNCTION V3_ZANG : REAL\nVAR_INPUT\n\tA : Vector_3;\nEND_VAR\nVAR\n\tla: REAL;\nEND_VAR\n\n(*\nversion 1.1\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function calculates the angle between the Z-axis and a vectors in a 3 dimensional space\n\n*)\n\nla := V3_ABS(a);\nIF la > 0.0 THEN\n\tV3_ZANG := ACOS(A.Z / la);\nEND_IF;\n\n(* revision history\nhm\t11 dec 2007\trev 1.0\n\toriginal version\n\nhm\t10. mar. 2009\trev 1.1\n\tchanged syntax of real constants to 0.0\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "VECTOR_3.st", - "source": "TYPE VECTOR_3 :\nSTRUCT\n\tX : REAL;\n\tY : REAL;\n\tZ : REAL;\nEND_STRUCT\nEND_TYPE\n" - }, - { - "fileName": "WEEKDAY_TO_STRING.st", - "source": "FUNCTION WEEKDAY_TO_STRING : STRING(10)\nVAR_INPUT\n\tWDAY : INT;\n\tLANG : INT;\n\tLX : INT;\nEND_VAR\nVAR\n\tly : INT;\nEND_VAR\n\n(*\nversion 1.1\t19. oct. 2008\nprogrammer \thugo\ntested by\toscat\n\nWEEKDAY_TO_STRING converts an Integer 1..7 into a String with the Names of the corresponding weekday.\nthe decoding is according to the language setup in global vars\n\n*)\n\nIF LANG = 0 THEN ly := LANGUAGE.DEFAULT; ELSE ly := MIN(LANG, LANGUAGE.LMAX); END_IF;\nIF wday < 1 OR wday > 7 THEN\n\tRETURN;\nELSIF LX = 0 THEN\n\tWEEKDAY_TO_STRING := language.WEEKDAYS[ly, WDAY];\nELSIF Lx = 2 THEN\n\tWEEKDAY_TO_STRING := language.WEEKDAYS2[ly, WDAY];\nEND_IF;\n\n\n(* revisison history\n\nhm\t21. sep. 2008\trev 1.0\n\toriginal version\n\nhm\t19. oct. 2008\trev 1.1\n\tchanged language setup constants\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "WINDOW.st", - "source": "FUNCTION WINDOW : BOOL\nVAR_INPUT\n\tlow : REAL;\n\tin : REAL;\n\thigh : REAL;\nEND_VAR\n\n\n(*\n\tversion 1.1\t22 jan 2007\n\tprogrammer \thugo\n\ttested BY\ttobias\n\nthis checks a signal if the signal is between the upper and lower limit\n*)\n\nWINDOW := in < high AND in > low;\n\n\n(* revision history\nhm\t22.1.2007\trev 1.1\n\tchanged the order of inputs to low, in, high\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "WINDOW2.st", - "source": "FUNCTION WINDOW2 : BOOL\nVAR_INPUT\n\tLOW : REAL;\n\tIN : REAL;\n\tHIGH : REAL;\nEND_VAR\n\n\n(*\n\tversion 1.0\t31 oct 2007\n\tprogrammer \thugo\n\ttested BY\ttobias\n\nthis checks a signal if the signal is between the upper and lower limit including the two limits\n*)\n\nWINDOW2 := IN >= LOW AND IN <= HIGH;\n\n\n(* revision history\nhm\t31.10.2007\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "WORD_OF_BYTE.st", - "source": "FUNCTION WORD_OF_BYTE : WORD\nVAR_INPUT\n\tB1 : BYTE;\n\tB0 : BYTE;\nEND_VAR\n\n\n(*\nversion 1.4\t18. jul. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function creates a word from 2 individual bytes\n\n*)\n\nWORD_OF_BYTE := SHL(BYTE_TO_WORD(B1),8) OR BYTE_TO_WORD(B0);\n\n(* revision history\nhm\t24. jan 2007\trev 1.0\n\toriginal version\n\nhm\t2. jan 2008\trev 1.1\n\timproved performance\n\nhm\t19. feb 2008\trev 1.2\n\treplaced and with or for better compatibility\n\nhm\t23. apr. 2008\trev 1.3\n\treverse order of inputs to be more logical\n\nhm\t18. jul. 2009\trev 1.4\n\tadded type conversions for compatibility reasons\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "WORD_OF_DWORD.st", - "source": "FUNCTION WORD_OF_DWORD : WORD\nVAR_INPUT\n\tin : DWORD;\n\tN : BYTE;\nEND_VAR\n\n\n(*\nversion 1.2\t30. oct. 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function extracts a single word from the nth position from right (right is lowest byte)\nthe lower word (starting with Bit0 from in) is selected with N=0.\n*)\n\nWORD_OF_DWORD := DWORD_TO_WORD(SHR(in,SHL(n,4)));\n\n(* revision history\nhm\t17. jan 2007\trev 1.0\n\toriginal version\n\nhm\t2. jan 2008\t\trev 1.1\n\timproved performance\n\nhm\t30. oct. 2008\trev 1.2\n\timproved performance\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "WORD_TO_RANGE.st", - "source": "FUNCTION WORD_TO_RANGE : REAL\nVAR_INPUT\n\tX : WORD;\n\tlow : REAL;\n\thigh : REAL;\nEND_VAR\n\n\n(*\nversion 1.1\t10. mar. 2009\nprogrammer \thugo\ntested by\t\ttobias\n\nWord_to_Range converts a Byte into a real between low and high.\n\n*)\n\nWORD_TO_RANGE := (high - low) * WORD_TO_REAL(X) * 0.00001525902189669640 + low;\n\n\n(* revision history\nhm\t9. jan 2008\trev 1.0\n\toriginal version\n\nhm\t10. mar. 2009\trev 1.1\n\timproved code\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "WORK_WEEK.st", - "source": "FUNCTION WORK_WEEK : INT\nVAR_INPUT\n\tidate : DATE;\nEND_VAR\nVAR\n\td1 : DATE;\n\tw1 : INT;\n\tds: DWORD;\n\tyr: INT;\n\tw31: INT;\n\tw01: INT;\n\twm: INT;\nEND_VAR\n\n(*\nversion 1.5\t25. oct. 2008\nprogrammer \thugo\ntested by\toscat\n\ncalculates the work week for a given date according to iso8601\n\n*)\n\n(* berechne den 1.1 des jahres von idate. *)\nyr := YEAR_OF_DATE(idate);\nd1 := YEAR_BEGIN(yr);\n(* wochentag von d1 *)\nw1 := DAY_OF_WEEK(d1);\n(* offset des montags der eletzten KW des vorjahres *)\n(* wenn der erste tag des jahres größer als donnerstag ist dann beginnt die letzte kw am montag davor *)\n(* wenn der erste tag des jahres ein donnerstag oder kleiner ist beginnt die erste kw 2 montage davor *)\nIF w1 < 5 THEN\n\tds := DATE_TO_DWORD(d1) - INT_TO_DWORD(w1+6) * 86400;\nELSE\n\tds := DATE_TO_DWORD(d1) - INT_TO_DWORD(w1-1) * 86400;\nEND_IF;\n\n(* kalenderwoche des eingangsdatums *)\nWORK_WEEK := DWORD_TO_INT((DATE_TO_DWORD(idate) - ds) / 604800);\n\n(* korrektur wenn work_week = 0 *)\nIF work_week = 0 THEN\n\t(* work_week needs to be 53 when 1.jan of the year before is thursday or dec 31. is thursday. *)\n\t(* first and last weekday of a year is equal and one more day for a leap_year. *)\n\tIF w1 > 1 THEN w31 := w1 - 1; ELSE W31 := 7; END_IF;\n\tIF LEAP_YEAR(yr - 1) AND w31 > 1 THEN w01 := W31 - 1; ELSE w1 := 7; END_IF;\n\t(* if first or last day of a year is a thursday, the year has 53 weeks *)\n\tWORK_WEEK := 52 + BOOL_TO_INT(w31 = 4 OR w01 = 4);\nELSE\n\t(* end of year calculation *)\n\t(* calculated the first and last weekday *)\n\tIF leap_year(yr) THEN\n\t\tIF w1 < 7 THEN w31 := w1 + 1; ELSE w31 := 1; END_IF;\n\tELSE\n\t\tw31 := w1;\n\tEND_IF;\n\t(* if first or last day is thursday then the year has 53 weeks otherwise only 52 *)\n\twm := 52 + BOOL_TO_INT(w31 = 4 OR w1 = 4);\n\tIF WORK_WEEK > wm THEN WORK_WEEK := 1; END_IF;\nEND_IF;\n\n\n\n(* revision history\n\nhm \t17.1.2007\t\trev 1.1\n\tdeleted unused variable yday\n\nhm\t19. dec 2007\trev 1.2\n\tchanged code for better performance\n\tchanged code to comply with ISO8601\n\nhm\t16. mar 2008\trev 1.3\n\tadded type conversions to avoid warnings under codesys 3.0\n\nhm\t7. oct. 2008\trev 1.4\n\tchanged function year to year_of_date\n\tchanged function weekday to day_of_week\n\nhm\t25. oct. 2008\trev 1.5\n\toptimized code for performance\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "YEAR_BEGIN.st", - "source": "FUNCTION YEAR_BEGIN : DATE\nVAR_INPUT\n\ty : INT;\nEND_VAR\n\n\n(*\nversion 1.2\t7. Apr. 2008\nprogrammer \thugo\ntested by\ttobias\n\nreturs the date of january 1st for the given year \nthe function works for dates from 1970 - 2099 \n\n*)\n\nYEAR_BEGIN := DWORD_TO_DATE(SHR(INT_TO_DWORD(y) * 1461 - 2878169,2) * 86400);\n\n\n\n(* revision history\nhm\t19. dec 2007\trev 1.0\n\toriginal version\n\nhm\t4. jan 2008\t\trev 1.1\n\tformula for step7 was incorrect during leap years\n\nhm\t7. apr. 2008\trev 1.2\n\tdeleted unused step7 code\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "YEAR_END.st", - "source": "FUNCTION YEAR_END : DATE\nVAR_INPUT\n\ty : INT;\nEND_VAR\n\n\n(*\nversion 1.1\t24. jan. 2011\nprogrammer \thugo\ntested by\toscat\n\nreturs the date of december 31st for the given year \nthe function works for dates from 1970 - 2099 \n\n*)\n\nYEAR_END := DWORD_TO_DATE(SHR(INT_TO_DWORD(y) * 1461 - 2876712, 2) * 86400);\n\n\n\n(* revision history\nhm\t15. jun. 2008\trev 1.0\n\toriginal version\n\nhm\t24. jan 2011\trev 1.1\n\timproved performance\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "YEAR_OF_DATE.st", - "source": "FUNCTION YEAR_OF_DATE : INT\nVAR_INPUT\n\tIDATE : DATE;\nEND_VAR\n\n\n(*\nversion 1.4\t7. oct. 2008\nprogrammer \thugo\ntested by\t\toscat\n\nreturs the year of a date \nthe function works for dates from 1970 - 2099 \n\n*)\n\nYEAR_OF_DATE := DWORD_TO_INT((DATE_TO_DWORD(idate) + 43200) / 31557600 + 1970);\n\n\n(* revision history\nhm\t4. aug 2006\t\trev 1.0\n\toriginal version\n\nhm\t1. okt 2007\t\trev 1.1\n\tcorrected error in algorithm\n\tadjustment for S7 compatibility\n\nhm\t23.12.2007\t\trev 1.2\n\tchanged code for better performance\n\nhm\t7. apr. 2008\trev 1.3\n\tdeleted unused step7 code\n\nhm\t7. oct. 2008\trev 1.4\n\trenamed function (year) to year_of_date\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "_ARRAY_ABS.st", - "source": "FUNCTION _ARRAY_ABS : BOOL\nVAR_INPUT\n\tpt : POINTER TO ARRAY[0..32000] OF REAL;\n\tsize : UINT;\nEND_VAR\nVAR\n\ti: UINT;\n\tstop: UINT;\nEND_VAR\n\n(*\nversion 1.0\t2. apr. 2008\nprogrammer \thugo\ntested by\ttobias\n\nthis function will calculate the absolute value of each element of the array and stroe the result instead of the element.\nArray[i] := ABS(ARRAY[i]).\nthe function needs to be called:\tarray_avg(adr(\"array\"),sizeof(\"array\"));\nbecause this function works with pointers its very time efficient and it needs no extra memory.\n\n*)\n\nstop := SHR(size,2)-1;\nFOR i := 0 TO stop DO\n\tPT^[i] := ABS(PT^[i]);\nEND_FOR;\n_ARRAY_ABS := TRUE;\n\n\n(* revision history\nhm\t2. apr 2008\t\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "_ARRAY_ADD.st", - "source": "FUNCTION _ARRAY_ADD : BOOL\nVAR_INPUT\n\tpt : POINTER TO ARRAY[0..32000] OF REAL;\n\tsize : UINT;\n\tX : REAL;\nEND_VAR\nVAR\n\ti: UINT;\n\tstop: UINT;\nEND_VAR\n\n(*\nversion 1.0\t2. apr. 2008\nprogrammer \thugo\ntested by\ttobias\n\nthis function will add an offset X to each element of the array and stroe the result instead of the element.\nArray[i] := ARRAY[i] + X.\nthe function needs to be called:\tarray_avg(adr(\"array\"),sizeof(\"array\"));\nbecause this function works with pointers its very time efficient and it needs no extra memory.\n\n*)\n\nstop := SHR(size,2)-1;\nFOR i := 0 TO stop DO\n\tPT^[i] := PT^[i] + X;\nEND_FOR;\n_ARRAY_ADD := TRUE;\n\n\n(* revision history\nhm\t2. apr 2008\t\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "_ARRAY_INIT.st", - "source": "FUNCTION _ARRAY_INIT : BOOL\nVAR_INPUT\n\tpt : POINTER TO ARRAY[0..32000] OF REAL;\n\tsize : UINT;\n\tinit : REAL;\nEND_VAR\nVAR\n\ti: UINT;\n\tstop: UINT;\nEND_VAR\n\n\n(*\nversion 1.3\t16 mar 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function will initialize a given array with a value init.\nthe function needs to be called:\t_array_init(adr(\"array\"),sizeof(\"array\"));\nthis function will manipulate a given array.\nthe function manipulates the original array, it rerturnes true when finished.\nbecause this function works with pointers its very time efficient and it needs no extra memory.\n\n*)\n\nstop := SHR(size,2)-1;\nFOR i := 0 TO stop DO\n\tpt^[i] := init;\nEND_FOR;\n\n_array_init := TRUE;\n\n(* revision History\n\nhm 6.1.2007\t\trev 1.1\n\tchange type of function to bool\n\tadded array_init := true to set output true.\n\nhm\t14.11.2007\trev 1.2\n\tchanged stop calculation to be more efficient\n\nhm\t16.3. 2008\t\trev 1.3\n\tchanged type of input size to uint\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "_ARRAY_MEDIAN.st", - "source": "FUNCTION _ARRAY_MEDIAN : REAL\nVAR_INPUT\n\tpt : POINTER TO ARRAY[0..32000] OF REAL;\n\tsize : UINT;\nEND_VAR\nVAR\n\ti: UINT;\n\tstop: UINT;\nEND_VAR\n\n(*\nversion 1.5\t16 mar 2008\nprogrammer \thugo\ntested by\t\ttobias\n\nthis function will calculate the median of a given array.\nin order to do so the ariginal array is sorted and stays sorted after the function finishes\nthe function needs to be called:\t_array_median(adr(\"array\"),sizeof(\"array\"));\nthis function will manipulate a given array.\nthe function will return the median of the original array.\nfor example [12,0,4,7,1] the median is 4 and the array after the function is called is [0,1,4,7,12]\nbecause this function works with pointers its very time efficient and it needs no extra memory.\n\n*)\n\n_ARRAY_SORT(pt,size);\nstop := SHR(size,2)-1;\nIF EVEN(UINT_TO_INT(stop)) THEN\n\t_ARRAY_MEDIAN := pt^[SHR(stop,1)];\nELSE\n\ti := SHR(stop,1);\n\t_ARRAY_MEDIAN := (pt^[i] + pt^[i+1]) * 0.5;\nEND_IF;\n\n(* old code\nstop := (size - SIZEOF(pt)) / SIZEOF(pt);\nFOR i := 0 TO stop - 1 DO\n\tFOR m := i + 1 TO stop DO\n\t\tIF pt^[i] > pt^[m] THEN\n\t\t\ttemp := pt^[i];\n\t\t\tpt^[i] := pt^[m];\n\t\t\tpt^[m] := temp;\n\t\tEND_IF;\n\tEND_FOR;\nEND_FOR;\nIF even(stop) THEN\n\t_array_median := pt^[stop/2];\nELSE\n\ti := stop/2;\n\t_array_median := (pt^[i] + pt^[i+1])/2;\nEND_IF;\n*)\n(* revision history\nhm \t3.3.2007\t\trev 1.1\n\tcorrected an error, changed the statement line 14\ti := TRUNC(stop/2); to i := stop/2;\n\nhm\t\t22. sep 2007\trev 1.2\n\tchanged algorithm to use _array_soft for performance reasons\n\nhm\t\t8. oct 2007\t\trev 1.3\n\tdeleted unused variables m and temp\n\nhm\t\t14. nov 2007\trev 1.4\n\tcorrected a problem with size calculation\n\nhm\t\t16.3. 2008\t\trev 1.5\n\tchanged type of input size to uint\n\tperformance improvements\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "_ARRAY_MUL.st", - "source": "FUNCTION _ARRAY_MUL : BOOL\nVAR_INPUT\n\tpt : POINTER TO ARRAY[0..32000] OF REAL;\n\tsize : UINT;\n\tX : REAL;\nEND_VAR\nVAR\n\ti: UINT;\n\tstop: UINT;\nEND_VAR\n\n(*\nversion 1.0\t2. apr. 2008\nprogrammer \thugo\ntested by\ttobias\n\nthis function will multiply each element of the array and stroe the result instead of the element.\nArray[i] := ARRAY[i] * X.\nthe function needs to be called:\tarray_avg(adr(\"array\"),sizeof(\"array\"));\nbecause this function works with pointers its very time efficient and it needs no extra memory.\n\n*)\n\nstop := SHR(size,2)-1;\nFOR i := 0 TO stop DO\n\tPT^[i] := PT^[i] * X;\nEND_FOR;\n_ARRAY_MUL := TRUE;\n\n\n(* revision history\nhm\t2. apr 2008\t\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "_ARRAY_SHUFFLE.st", - "source": "FUNCTION _ARRAY_SHUFFLE : BOOL\nVAR_INPUT\n\tpt : POINTER TO ARRAY[0..32000] OF REAL;\n\tsize : UINT;\nEND_VAR\nVAR\n\ttemp : REAL;\n\tpos : INT;\n\ti: INT;\n\tstop: INT;\nEND_VAR\n\n\n(*\nversion 1.2\t30. mar. 2008\nprogrammer \tkurt\ntested by\t\thugo\n\nthis function will randomly shuffle the elements of an array\n*)\n\nstop := UINT_TO_INT(SHR(size,2)-1);\nFOR i := 0 TO stop DO\n pos := RDM2(i+pos,0,stop);\n (* swap elements *)\n temp := pt^[i];\n pt^[i] := pt^[pos];\n pt^[pos] := temp;\nEND_FOR;\n\n_ARRAY_SHUFFLE := TRUE;\n\n\n(* revision History\nhm \t4. mar 2008\trev 1.0\n\toriginal version\n\nhm\t16. mar. 2008\trev 1.1\n\tchanged type of input size to uint\n\nhm\t30. mar. 2008\trev 1.2\n\tchanged last in rdm2 fromm pos to i + pos to allow for more randomness\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "_ARRAY_SORT.st", - "source": "FUNCTION _ARRAY_SORT : BOOL\nVAR_INPUT\n\tPT : POINTER TO ARRAY[1..32000] OF REAL;\n\tSIZE : UINT;\nEND_VAR\nVAR\n\tstack_count: UINT;\t\t\t\t(* Laufvariable Stack*)\n\tstack: ARRAY[1..32] OF UINT;\t(* Stackgröße~ 1,6*Log(n)/log(2) *)\n\t\t\t\t\t\t\t\t\t\t(* Stackgröße 32 => ~1 Mio Elemente *)\n\tlinks: UINT;\t\t\t\t\t\t(* Anfangselement des Arrays *)\n\trechts: UINT;\t\t\t\t\t\t(* Endelement des Arrays *)\n\tpivot: REAL;\t\t\t\t\t\t(* temporärer Schwellwert für Tauschbedingung *)\n\ti: UINT;\t\t\t\t\t\t\t(* Laufvariable1 *)\n\tj: UINT;\t\t\t\t\t\t\t(* Laufvariable2 *)\n\tende_innen: BOOL;\t\t\t\t(* Ende innere Schleife *)\n\tende_aussen: BOOL;\t\t\t\t(* Ende äußere Schleife *)\n\ttmp: REAL;\t\t\t\t\t\t(* Hilfsvariable zum Tauschen von Werten *)\nEND_VAR\n\n\n\n(*\nversion 2.0\t19. jan. 2011\nprogrammer \tAlexander Trikitis\ntested by\toscat\n\nthis function will sort a given array.\nthe function needs to be called:\t_array_sort(adr(\"array\"),sizeof(\"array\"));\nthis function will manipulate a given array.\nthe function will not return anything except true, it will instead manipulate the original array.\nbecause this function works with pointers its very time efficient and it needs no extra memory.\n\n*)\n\n(* Startwerte zur Arraygröße *)\nlinks := 1;\t\t\t\t\t(* Anfangselement des Arrays *)\nrechts := SHR(size,2);\t\t(* Endelement des Arrays *)\nstack_count := 1;\t\t\t(* Laufvariable Stack *)\n\nWHILE NOT ende_aussen DO\t\t\t\t\t\t(* äußere Schleife *)\n\tIF links < rechts THEN\n\t\tpivot := PT^[SHR(rechts+links,1)];\t\t\t(* Wert des mittleren Elements als Pivot-Wert *)\n\t\ti := links -1;\n\t\tj := rechts +1;\n\n\t\t(* innere Schleife, teile Feld *)\n\t\tende_innen := FALSE;\n\t\tREPEAT\n\n\t\t\t(* steigende Reihenfolge *)\n\t\t\tREPEAT\ti := i+1;\tUNTIL (PT^[i] >= pivot) OR NOT (i < rechts)\tEND_REPEAT;\n\t\t\tREPEAT\tj := j-1;\tUNTIL (PT^[j] <= pivot) OR NOT (j > links)\tEND_REPEAT;\n\n\n\t\t\t(*sinkende Reihenfolge *)\n(*\t\t\tREPEAT\ti := i+1;\tUNTIL (PT^[i] <= pivot) OR NOT (i < rechts)\tEND_REPEAT\t*)\n(*\t\t\tREPEAT\tj := j-1;\tUNTIL (PT^[j] >= pivot) OR NOT (j > links)\tEND_REPEAT\t*)\n\n\t\t\tIF i >= j THEN\n\t\t\t\tende_innen := TRUE;\n\t\t\tELSE\n\t\t\t\t tmp := PT^[j];\n\t\t\t\tPT^[j] := PT^[i];\n\t\t\t\tPT^[i] := tmp;\n\t\t\tEND_IF;\n\n\t\tUNTIL ende_innen END_REPEAT;\n\n\t\t(* Push stack *)\n\t\tstack[stack_count] := rechts;\t\t(* rechten Teil später sortieren *)\n\t\tIF Stack_count < 32 THEN\n\t\t\tstack_count := stack_count +1;\n\t\tELSE\n\t\t\tende_aussen := TRUE;\n\t\t\t_ARRAY_SORT := FALSE;\t\t\t\t\t(* Fehler: Stack zu klein *)\n\t\tEND_IF;\n\n\t\t(* linken Teil sortiern *)\n\t\trechts := MAX(links, i-1);\n\n\tELSE\n\n\t\tIF stack_count = 1 THEN\n\t\t\tende_aussen := TRUE;\n\t\tELSE\n\n\t\t\tlinks := rechts+1;\n\n\t\t\t(* pop stack *)\n\t\t\tstack_count := stack_count -1;\t\t(* jetzt rechten Teil sortierne *)\n\t\t\trechts:= stack[stack_count];\n\t\tEND_IF;\n\n\tEND_IF;\n\nEND_WHILE;\n\n_ARRAY_SORT := TRUE;\t\t\t\t(* Sortierung beendet *)\n\n\n(* algorithm used before rev 2.0\n\nsize := SHR(size,2);\nsize2 := UINT_TO_INT(SHR(size,1));\nFOR i := SIZE2 TO 1 BY -1 DO\n\tj:=i;\n WHILE j <= SIZE2 DO\n \tstop := j * 2 + 1;\n IF stop > UINT_TO_INT(SIZE) THEN stop := stop - 1;\n ELSIF pt^[stop-1] > pt^[stop] THEN stop := stop - 1;\n\t\tEND_IF;\n IF pt^[j] < pt^[stop] THEN\n \ttemp := pt^[j];\n pt^[j] := pt^[stop];\n pt^[stop] := temp;\n END_IF;\n j := stop;\n END_WHILE;\nEND_FOR;\n\n*)\n\n(* heapsort\nFOR heapsize := UINT_TO_INT(size) TO 1 BY -1 DO\n\tpopmax := pt^[1];\n\tpt^[1] := pt^[heapsize];\n \ti := 1;\n\ths2 := SHR(heapsize,1);\n\tWHILE i <= hs2 DO\n \tstop := i * 2 + 1; \n \tIF stop > heapsize THEN stop := stop - 1;\n \tELSIF pt^[stop-1] > pt^[stop] THEN stop := stop - 1;\n\t \tEND_IF;\n \tIF pt^[i] < pt^[stop] THEN\n \t\ttemp := pt^[i];\n \t\tpt^[i] := pt^[stop];\n \t\tpt^[stop] := temp;\n \tEND_IF;\n \ti := stop;\n \tEND_WHILE;\n\tpt^[heapsize] := popmax;\nEND_FOR;\n\n_ARRAY_SORT2 := TRUE;\n*)\n\n(* old algorithm bubble sort used before rev 1.2\nstop := (size - SIZEOF(pt)) / SIZEOF(pt);\nFOR i := 0 TO stop - 1 DO\n\tFOR m := i + 1 TO stop DO\n\t\tIF pt^[i] > pt^[m] THEN\n\t\t\ttemp := pt^[i];\n\t\t\tpt^[i] := pt^[m];\n\t\t\tpt^[m] := temp;\n\t\tEND_IF;\n\tEND_FOR;\nEND_FOR;\n_array_sort := TRUE;\n\n*)\n\n\n(* revision history\n\nhm \t6.1.2007 \trev 1.1\n\tchanged return value to true\n\nhm\t22. sep 2007\trev 1.2\n\tchanged sorting algorithm to heap sort for performance reasons\n\nhm \t14. nov 2007\trev 1.3\n\tchanged calculation of stop to be more efficient\n\nhm\t15 dec 2007\trev 1.4\n\tadded function return true\n\nhm\t5. jan 2008\t\trev 1.5\n\timproved performance\n\nhm\t16. mar. 2008\trev 1.6\n\tchanged type of input size to uint\n\nhm\t28. mar. 2008\trev 1.7\n\tchanged input f to pt\n\nhm\t19. jan. 2011\trev 2.0\n\tnew faster algorithm using qucksort (Alexander Drikitis)\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "_BUFFER_CLEAR.st", - "source": "FUNCTION _BUFFER_CLEAR : BOOL\nVAR_INPUT\n\tPT : POINTER TO BYTE;\n\tSIZE : UINT;\nEND_VAR\nVAR\n\tptw : POINTER TO DWORD;\n\ttemp: DWORD;\n\tend, end32 : DWORD;\nEND_VAR\n\n\n(*\nversion 1.2\t31. oct. 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function will initialize a given array of byte with 0.\nthe function needs to be called:\t_buffer_clear(adr(\"array\"),sizeof(\"array\"));\nthis function will manipulate a given array.\nthe function manipulates the original array, it rerturnes true when finished.\nbecause this function works with pointers its very time efficient and it needs no extra memory.\n\n*)\n\n(* this routine uses 32 bit access to gain speed *)\n(* first access bytes till pointer is aligned for 32 bit access *)\ntemp := pt;\nend := temp + UINT_TO_DWORD(size);\nend32 := end - 3;\nWHILE (pt < end) AND ((temp AND 16#00000003) > 0) DO\n\tpt^ := 0;\n\tpt := pt + 1;\n\ttemp := temp + 1;\nEND_WHILE;\n(* pointer is aligned, now copy 32 bits at a time *)\nptw := pt;\nWHILE ptw < end32 DO (* *)\n\tptw^ := 0;\n\tptw := ptw + 4;\nEND_WHILE;\n(* copy the remaining bytes in byte mode *)\npt := ptw;\nWHILE pt < end DO\n\tpt^ := 0;\n\tpt := pt + 1;\nEND_WHILE;\n\n_BUFFER_CLEAR := TRUE;\n\n(* revision History\nhm \t5. mar. 2008\trev 1.0\n\toriginal version\n\nhm\t16. mar. 2008\trev 1.1\n\tadded type conversion to avoid warnings under codesys 30\n\tchaged type of input size to uint\n\tdeleted unused variable i\n\nhm\t31. oct. 2008\trev 1.2\n\tcorrected an error while routine would write outside of arrays\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "_BUFFER_INIT.st", - "source": "FUNCTION _BUFFER_INIT : BOOL\nVAR_INPUT\n\tPT : POINTER TO BYTE;\n\tSIZE : UINT;\n\tINIT : BYTE;\nEND_VAR\nVAR\n\tptw : POINTER TO DWORD;\n\ttemp : DWORD;\n\tend, end32 : DWORD;\nEND_VAR\n\n\n(*\nversion 1.2\t31. oct. 2008\nprogrammer \thugo\ntested by\toscat\n\nthis function will initialize a given array of byte with init.\nthe function needs to be called:\t_buffer_init(adr(\"array\"),sizeof(\"array\"),init);\nthis function will manipulate a given array.\nthe function manipulates the original array, it rerturnes true when finished.\nbecause this function works with pointers its very time efficient and it needs no extra memory.\n\n*)\n\n(* this routine uses 32 bit access to gain speed *)\n(* first access bytes till pointer is aligned for 32 bit access *)\ntemp := pt;\nend := temp + UINT_TO_DWORD(size);\nend32 := end - 3;\nWHILE (pt < end) AND ((temp AND 16#00000003) > 0) DO\n\tpt^ := init;\n\tpt := pt + 1;\n\ttemp := temp + 1;\nEND_WHILE;\n(* pointer is aligned, now copy 32 bits at a time *)\nptw := pt;\ntemp := SHL(BYTE_TO_DWORD(init),24) OR SHL(BYTE_TO_DWORD(init),16) OR SHL(BYTE_TO_DWORD(init),8) OR BYTE_TO_DWORD(init);\nWHILE ptw < end32 DO\n\tptw^ := temp;\n\tptw := ptw + 4;\nEND_WHILE;\n(* copy the remaining bytes in byte mode *)\npt := ptw;\nWHILE pt < end DO\n\tpt^ := init;\n\tpt := pt + 1;\nEND_WHILE;\n\n_BUFFER_INIT := TRUE;\n\n(* revision History\nhm \t5. mar. 2008\trev 1.0\n\toriginal version\n\nhm\t16. mar. 2008\trev 1.1\n\tadded type conversion to avoid warnings under codesys 3.0\n\tchaged type of input size to uint.\n\nhm\t31. oct. 2008\trev 1.2\n\tcorrected an error while routine would write outside of arrays\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "_BUFFER_INSERT.st", - "source": "FUNCTION _BUFFER_INSERT : INT\nVAR_INPUT\n\tSTR : STRING(STRING_LENGTH);\n\tPOS : INT;\n\tPT : POINTER TO ARRAY[0..32767] OF BYTE;\n\tSIZE : UINT;\nEND_VAR\nVAR\n\tend : INT;\n\tlx: INT;\n\ti: INT;\nEND_VAR\n\n\n(*\nversion 1.5\t2. jan. 2012\nprogrammer \thugo\ntested by\toscat\n\nthis function will insert a string at a given position in a buffer.\nthe function needs to be called:\t_buffer_init(adr(\"array\"),sizeof(\"array\"),init);\nthis function will manipulate a given array.\nthe function manipulates the original array, it returnes the next position after the input string when finished.\nbecause this function works with pointers its very time efficient and it needs no extra memory.\n\n*)\n\nlx := LEN(str);\nend := pos + lx;\n(* first move the upper part of the buffer to make space for the string *)\nFOR i := UINT_TO_INT(size) - 1 TO end BY -1 DO\n\tpt^[i] := pt^[i-lx];\nEND_FOR;\n(* copy the string *)\n_BUFFER_INSERT := _STRING_TO_BUFFER(str, pos, PT, size);\n\n\n(* revision History\nhm \t9. mar. 2008\trev 1.0\n\toriginal version\n\nhm\t16. mar. 2008\trev 1.1\n\tchanged type of input size to uint\n\nhm\t13. may. 2008\trev 1.2\n\tchanged type of pointer to array[1..32767]\n\tchanged size of string to STRING_LENGTH\n\nhm\t23. mar. 2009\trev 1.3\n\tavoid writing to input pos\n\nhm\t12. nov. 2009\trev 1.4\n\tcode optimized\n\nhm 2. jan 2012\trev 1.5\n\tfunction now returns the next position after the input string\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "_BUFFER_UPPERCASE.st", - "source": "FUNCTION _BUFFER_UPPERCASE : BOOL\nVAR_INPUT\n\tPT : POINTER TO ARRAY[0..32000] OF BYTE;\n\tSIZE : INT;\nEND_VAR\nVAR\n\tpos: INT;\nEND_VAR\n\n\n(*\nversion 1.0\t20. jan. 2011\nprogrammer \thugo\ntested by\toscat\n\nthis function will convert an array of byte into uppercase\nthe function needs to be called:\t_buffer_clear(adr(\"array\"),sizeof(\"array\"));\nthis function will manipulate a given array.\nthe function manipulates the original array, it rerturnes true when finished.\nbecause this function works with pointers its very time efficient and it needs no extra memory.\n\n*)\n\npos := 0;\nWHILE pos < size DO\n\tPT^[pos] := TO_UPPER(pt^[pos]);\n\tpos := pos + 1;\nEND_WHILE;\n\n_BUFFER_UPPERCASE := TRUE;\n\n(* revision History\nhm \t20. jan. 2011\trev 1.0\n\toriginal version\n\n*)\n\nEND_FUNCTION\n" - }, - { - "fileName": "_RMP_B.st", - "source": "FUNCTION_BLOCK _RMP_B\nVAR_INPUT\n\tDIR : BOOL; (* true = up *)\n\tE : BOOL := TRUE;\n\tTR : TIME;\nEND_VAR\nVAR_IN_OUT\n\tRMP : BYTE;\nEND_VAR\nVAR\n\ttx, tl, tn : TIME;\n\tinit : BOOL;\n\tlast_dir : BOOL;\n\tstart : BYTE;\nEND_VAR\n\n\n(*\nversion 1.2\t\t19. feb. 2011\nprogrammer \thugo\ntested by\t\toscat\n\n_RMP_B generates a ramp on an external var of type byte\ntr is the total ramp time, E is an enable and dir the direction of the ramp\n\n*)\n\n(* read system timer *)\ntx := DWORD_TO_TIME(T_PLC_MS());\n\nIF E AND init AND (dir = last_dir) AND (RMP <> SEL(DIR, 0, 255)) AND TR = tn THEN\n\tRMP := FRMP_B(start, DIR, tx - tl, TR);\nELSE\n\tinit := TRUE;\n\ttl := tx;\n\ttn := tr;\n\tstart := RMP;\nEND_IF;\nlast_dir := dir;\n\n\n\n(* revison history\nhm\t22. oct. 2008\trev 1.0\n\toriginal version\n\nhm\t20. nov. 2008\trev 1.1\n\tset default for E to be TRUE\n\tadded init\n\nhm\t19. nov. 2011\trev 1.2\n\tnew code\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "_RMP_NEXT.st", - "source": "FUNCTION_BLOCK _RMP_NEXT\nVAR_INPUT\n\tE : BOOL := TRUE;\n\tIN : BYTE;\n\tTR : TIME;\n\tTF : TIME;\n\tTL : TIME;\nEND_VAR\nVAR_OUTPUT\n\tDIR : BOOL; (* upwards = TRUE *)\n\tUP : BOOL;\n\tDN : BOOL;\nEND_VAR\nVAR_IN_OUT\n\tOUT : BYTE;\nEND_VAR\nVAR\n\trmx : _RMP_B;\n\tdirx : TREND_DW;\n\tt_lock :TP;\n\txen: BOOL;\n\txdir: BOOL;\nEND_VAR\n\n\n(*\nversion 1.4\t\t18. jul. 2009\nprogrammer \thugo\ntested by\t\toscat\n\n\n_RMP_NEXT will generate a ramp output following the input IN.\non a rising ramp the output will stop as soon as it has surpassed the input in, and on a falling ramp it will stop when out is smaller than in.\na lockout time T_L will be added between up and down direction.\n\n*)\n\ndirx(X := in);\n\nt_lock(in := FALSE, pt := TL);\n\nIF dirx.TU AND (OUT < IN) THEN\n\tIF NOT xdir AND xen THEN t_lock(in := TRUE); END_IF;\n\txen := TRUE;\n\txdir := TRUE;\nELSIF dirx.TD AND (OUT > IN) THEN\n\tIF xdir AND xen THEN t_lock(in := TRUE); END_IF;\n\txen := TRUE;\n\txdir := FALSE;\nELSIF xen THEN\n\tIF (xdir AND (out >= in)) OR (NOT xdir AND (out <= in)) THEN\n\t\txen := FALSE;\n\t\tIF tl > t#0s THEN t_lock(IN := TRUE); END_IF;\n\tEND_IF;\nEND_IF;\n\nIF NOT t_lock.Q AND xen THEN\n\t\tUP := XDIR;\n\t\tDIR := XDIR;\n\t\tDN := NOT XDIR;\nELSE\n\tUP := FALSE;\n\tDN := FALSE;\nEND_IF;\n\nrmx(rmp := OUT, E := E AND (UP OR DN) , dir := DIR, tr := SEL(dir, TF, TR));\n\n\n(* revison history\nhm\t23. nov. 2008\trev 1.0\n\toriginal version\n\nhm\t24. jan. 2009\trev 1.1\n\tdeleted unused vars tmp1, tmp2\n\nhm\t20. feb. 2009\trev 1.2\n\timproved algorithm\n\tadded TL\n\nhm\t9. mar. 2009\trev 1.3\n\tinput E was ignored\n\tremoved double assignments\n\nhm\t18. jul. 2009\trev 1.4\n\timproved performance\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "_RMP_W.st", - "source": "FUNCTION_BLOCK _RMP_W\nVAR_INPUT\n\tDIR : BOOL;\n\tE : BOOL := TRUE;\n\tTR : TIME;\nEND_VAR\nVAR_IN_OUT\n\tRMP : WORD;\nEND_VAR\nVAR\n\ttx, tl : DWORD;\n\tstep : DINT;\n\tinit: BOOL;\n\tlast_dir : BOOL;\nEND_VAR\n\n\n(*\nversion 1.1\t20. nov. 2008\nprogrammer \thugo\ntested by\toscat\n\n\n_RMP_B generates a ramp on an external var of type byte\ntr is the total ramp time, E is an enable and dir the direction of the ramp\n\n*)\n\ntx := T_PLC_MS();\nIF E AND init THEN\n\t(* we need to set tl = tx when direction changes *)\n\tIF dir XOR last_dir THEN\n\t tl := tx;\n\t last_dir := dir;\n\tEND_IF;\n\t(* check_elapsed time and calculate only if necessary *)\n\tIF tr > t#0s THEN\n\t\tstep := DWORD_TO_DINT(SHL(tx-tl, 16) / TIME_TO_DWORD(TR));\n\tELSE\n\t\tstep := 65535;\n\tEND_IF;\n\tIF step > 0 THEN\n\t\t(* perform the step on the ramp *)\n\t\ttl := tx;\n\t\t(* calculate the step response *)\n\t\tIF NOT dir THEN step := - step; END_IF;\n\t\trmp := DINT_TO_WORD(LIMIT(0, WORD_TO_DINT(rmp) + step, 65535));\n\tEND_IF;\nELSE\n\ttl := tx;\n\tinit := TRUE;\nEND_IF;\n\n\n(* revison history\nhm\t22. oct. 2008\trev 1.0\n\toriginal version\n\nhm\t20. nov. 2008\trev 1.1\n\tset default for E to be TRUE\n\tadded init\n\n*)\n\nEND_FUNCTION_BLOCK\n" - }, - { - "fileName": "_STRING_TO_BUFFER.st", - "source": "FUNCTION _STRING_TO_BUFFER : INT\nVAR_INPUT\n\tSTR : STRING(STRING_LENGTH);\n\tPOS : INT;\n\tPT : POINTER TO ARRAY[0..32767] OF BYTE;\n\tSIZE : UINT;\nEND_VAR\nVAR\n\tps : POINTER TO BYTE;\n\ti: INT;\n\tend: INT;\nEND_VAR\n\n\n(*\nversion 1.4\t2. jan. 2012\nprogrammer \thugo\ntested by\t\toscat\n\nthis function will copy a string into an array of byte starting at position pos.\nthe function needs to be called:\t_String_To_buffer(str, pos, adr(\"array\"),sizeof(\"array\"));\nthis function will manipulate the array directly in memory and returns the position after the input string when finished.\nbecause this function works with pointers its very time efficient and it needs no extra memory.\n\n*)\n\nps := ADR(str);\nend := MIN(pos + LEN(str), UINT_TO_INT(size));\nIF end > 0 THEN end := end -1; END_IF;\nFOR i := pos TO end DO\n\tpt^[i] := ps^;\n\tps := ps + 1;\nEND_FOR;\n\n_STRING_TO_BUFFER := i;\n\n(* revision History\n\nhm \t5. mar. 2008\trev 1.0\n\toriginal version\n\nhm\t16. mar. 2008\trev 1.1\n\tchanged type of input size to uint\n\nhm\t13. may. 2008\trev 1.2\n\tchanged type of pointer to array[1..32767]\n\tchanged size of string to STRING_LENGTH\n\nhm\t12. nov. 2009\trev 1.3\n\tlimit end to size - 1\n\nhm\t2. jan 2012\trev 1.4\n\treturn the position after the input string when finished\n*)\n\nEND_FUNCTION\n" - } - ], - "globalConstants": { - "STRING_LENGTH": 254, - "LIST_LENGTH": 254 - } -} diff --git a/libs/sources/additional-function-blocks/derivative.st b/libs/sources/additional-function-blocks/derivative.st new file mode 100644 index 0000000..cd9698a --- /dev/null +++ b/libs/sources/additional-function-blocks/derivative.st @@ -0,0 +1,33 @@ +(* Additional Function Blocks: DERIVATIVE *) +(* Source carried verbatim from MatIEC's lib/derivative_st.txt. *) +(* Original header preserved for traceability: *) +(* "Following taken directly from the IEC 61131.3 draft standard" *) +(* "FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)" *) + +FUNCTION_BLOCK DERIVATIVE + VAR_INPUT + RUN : BOOL ; (* 0 = reset *) + XIN : REAL ; (* Input to be differentiated *) + CYCLE : TIME ; (* Sampling period *) + END_VAR + VAR_OUTPUT + XOUT : REAL ; (* Differentiated output *) + END_VAR + VAR + X1 : REAL ; + X2 : REAL ; + X3 : REAL ; + END_VAR + + IF RUN THEN + XOUT := (3.0 * (XIN - X3) + X1 - X2) / (10.0 * TIME_TO_REAL(CYCLE)) ; + X3 := X2 ; + X2 := X1 ; + X1 := XIN ; + ELSE + XOUT := 0.0 ; + X1 := XIN ; + X2 := XIN ; + X3 := XIN ; + END_IF ; +END_FUNCTION_BLOCK diff --git a/libs/sources/additional-function-blocks/hysteresis.st b/libs/sources/additional-function-blocks/hysteresis.st new file mode 100644 index 0000000..1780450 --- /dev/null +++ b/libs/sources/additional-function-blocks/hysteresis.st @@ -0,0 +1,26 @@ +(* Additional Function Blocks: HYSTERESIS *) +(* Source carried verbatim from MatIEC's lib/hysteresis_st.txt. *) +(* Original header preserved for traceability: *) +(* "Following taken directly from the IEC 61131.3 draft standard" *) +(* "FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)" *) +(* *) +(* Boolean hysteresis on the difference of two REAL inputs (XIN1 - XIN2). *) + +FUNCTION_BLOCK HYSTERESIS + VAR_INPUT + XIN1 : REAL ; + XIN2 : REAL ; + EPS : REAL ; + END_VAR + VAR_OUTPUT + Q : BOOL := FALSE ; + END_VAR + + IF Q THEN + IF XIN1 < (XIN2 - EPS) THEN + Q := FALSE ; + END_IF ; + ELSIF XIN1 > (XIN2 + EPS) THEN + Q := TRUE ; + END_IF ; +END_FUNCTION_BLOCK diff --git a/libs/sources/additional-function-blocks/integral.st b/libs/sources/additional-function-blocks/integral.st new file mode 100644 index 0000000..a3689f5 --- /dev/null +++ b/libs/sources/additional-function-blocks/integral.st @@ -0,0 +1,26 @@ +(* Additional Function Blocks: INTEGRAL *) +(* Source carried verbatim from MatIEC's lib/integral_st.txt. *) +(* Original header preserved for traceability: *) +(* "Following taken directly from the IEC 61131.3 draft standard" *) +(* "FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)" *) + +FUNCTION_BLOCK INTEGRAL + VAR_INPUT + RUN : BOOL ; (* 1 = integrate, 0 = hold *) + R1 : BOOL ; (* Overriding reset *) + XIN : REAL ; (* Input variable *) + X0 : REAL ; (* Initial value *) + CYCLE : TIME ; (* Sampling period *) + END_VAR + VAR_OUTPUT + Q : BOOL ; (* NOT R1 *) + XOUT : REAL ; (* Integrated output *) + END_VAR + + Q := NOT R1 ; + IF R1 THEN + XOUT := X0 ; + ELSIF RUN THEN + XOUT := XOUT + XIN * TIME_TO_REAL(CYCLE) ; + END_IF ; +END_FUNCTION_BLOCK diff --git a/libs/sources/additional-function-blocks/library.json b/libs/sources/additional-function-blocks/library.json new file mode 100644 index 0000000..c0006b0 --- /dev/null +++ b/libs/sources/additional-function-blocks/library.json @@ -0,0 +1,28 @@ +{ + "name": "additional-function-blocks", + "displayName": "Additional Function Blocks", + "version": "1.0.0", + "namespace": "strucpp", + "description": "IEC 61131-3 Annex E Additional Function Blocks (RTC, INTEGRAL, DERIVATIVE, PID, RAMP, HYSTERESIS) — auto-generated from ST sources", + "isBuiltin": true, + "blocks": { + "RTC": { + "documentation": "The real time clock has many uses including time stamping, setting dates and times of day in batch reports, in alarm messages and so on." + }, + "INTEGRAL": { + "documentation": "The integral function block integrates the value of input XIN over time." + }, + "DERIVATIVE": { + "documentation": "The derivative function block produces an output XOUT proportional to the rate of change of the input XIN." + }, + "PID": { + "documentation": "The PID (proportional, Integral, Derivative) function block provides the classical three term controller for closed loop control." + }, + "RAMP": { + "documentation": "The RAMP function block is modelled on example given in the standard." + }, + "HYSTERESIS": { + "documentation": "The hysteresis function block provides a hysteresis boolean output driven by the difference of two floating point (REAL) inputs XIN1 and XIN2." + } + } +} diff --git a/libs/sources/additional-function-blocks/pid.st b/libs/sources/additional-function-blocks/pid.st new file mode 100644 index 0000000..6d3cdbd --- /dev/null +++ b/libs/sources/additional-function-blocks/pid.st @@ -0,0 +1,35 @@ +(* Additional Function Blocks: PID *) +(* Source carried verbatim from MatIEC's lib/pid_st.txt. *) +(* Original header preserved for traceability: *) +(* "Following taken directly from the IEC 61131.3 draft standard" *) +(* "FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)" *) +(* *) +(* Depends on INTEGRAL and DERIVATIVE FBs declared elsewhere in this lib. *) + +FUNCTION_BLOCK PID + VAR_INPUT + AUTO : BOOL ; (* 0 - manual , 1 - automatic *) + PV : REAL ; (* Process variable *) + SP : REAL ; (* Set point *) + X0 : REAL ; (* Manual output adjustment - typically from transfer station *) + KP : REAL ; (* Proportionality constant *) + TR : REAL ; (* Reset time *) + TD : REAL ; (* Derivative time constant *) + CYCLE : TIME ; (* Sampling period *) + END_VAR + VAR_OUTPUT + XOUT : REAL ; + END_VAR + VAR + ERROR : REAL ; (* PV - SP *) + ITERM : INTEGRAL ; (* FB for integral term *) + DTERM : DERIVATIVE ; (* FB for derivative term *) + END_VAR + + ERROR := PV - SP ; + (*** Adjust ITERM so that XOUT := X0 when AUTO = 0 ***) + ITERM (RUN := AUTO, R1 := NOT AUTO, XIN := ERROR, + X0 := TR * (X0 - ERROR), CYCLE := CYCLE) ; + DTERM (RUN := AUTO, XIN := ERROR, CYCLE := CYCLE) ; + XOUT := KP * (ERROR + ITERM.XOUT / TR + DTERM.XOUT * TD) ; +END_FUNCTION_BLOCK diff --git a/libs/sources/additional-function-blocks/ramp.st b/libs/sources/additional-function-blocks/ramp.st new file mode 100644 index 0000000..c130440 --- /dev/null +++ b/libs/sources/additional-function-blocks/ramp.st @@ -0,0 +1,38 @@ +(* Additional Function Blocks: RAMP *) +(* Source carried verbatim from MatIEC's lib/ramp_st.txt. *) +(* Original header preserved for traceability: *) +(* "Following taken directly from the IEC 61131.3 draft standard" *) +(* "FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)" *) + +FUNCTION_BLOCK RAMP + VAR_INPUT + RUN : BOOL ; (* 0 - track X0, 1 - ramp to/track X1 *) + X0 : REAL ; + X1 : REAL ; + TR : TIME ; (* Ramp duration *) + CYCLE : TIME ; (* Sampling period *) + END_VAR + VAR_OUTPUT + BUSY : BOOL ; (* BUSY = 1 during ramping period *) + XOUT : REAL := 0.0 ; + END_VAR + VAR + XI : REAL ; (* Initial value *) + T : TIME := T#0s ; (* Elapsed time of ramp *) + END_VAR + + BUSY := RUN ; + IF RUN THEN + IF T >= TR THEN + BUSY := FALSE ; + XOUT := X1 ; + ELSE + XOUT := XI + (X1 - XI) * TIME_TO_REAL(T) / TIME_TO_REAL(TR) ; + T := T + CYCLE ; + END_IF ; + ELSE + XOUT := X0 ; + XI := X0 ; + T := T#0s ; + END_IF ; +END_FUNCTION_BLOCK diff --git a/libs/sources/additional-function-blocks/rtc.st b/libs/sources/additional-function-blocks/rtc.st new file mode 100644 index 0000000..4fbca65 --- /dev/null +++ b/libs/sources/additional-function-blocks/rtc.st @@ -0,0 +1,53 @@ +(* Additional Function Blocks: RTC *) +(* Source ported verbatim from MatIEC's lib/rtc.txt with one substitution: *) +(* the MatIEC pragma `{__SET_VAR(data__->,CURRENT_TIME,,__CURRENT_TIME)}` *) +(* read MatIEC's `__CURRENT_TIME` global, which serves the same purpose as *) +(* STruC++'s TIME() — monotonic scan-cycle time, hardware agnostic. We *) +(* substitute TO_DT(TIME()) so the same int64 tick value lands in a DT- *) +(* typed local. STruC++ requires an explicit conversion where MatIEC's *) +(* pragma did a raw bit-copy; behaviour is otherwise identical. *) +(* *) +(* Original MatIEC documentation: *) +(* *) +(* RTC - Real-time clock *) +(* *) +(* Q is a copy of IN. *) +(* *) +(* When IN = FALSE, CDT is the current "tick" time exposed by the *) +(* runtime as a DT. *) +(* *) +(* When IN changes from FALSE to TRUE, PDT is stored. As long as IN is *) +(* TRUE, CDT is equal to PDT + the amount of time since PDT was loaded. *) + +FUNCTION_BLOCK RTC + VAR_INPUT + IN : BOOL ; (* 0 - current time, 1 - load time from PDT *) + PDT : DT ; (* Preset datetime *) + END_VAR + VAR_OUTPUT + Q : BOOL := FALSE ; (* Copy of IN *) + CDT : DT ; (* Datetime, current or relative to PDT *) + END_VAR + + VAR + PREV_IN : BOOL := FALSE ; + OFFSET : TIME ; + CURRENT_TIME : DT ; + END_VAR + + CURRENT_TIME := TO_DT(TIME()) ; + + IF IN THEN + IF NOT PREV_IN THEN + OFFSET := PDT - CURRENT_TIME ; + END_IF ; + + (* PDT + time since PDT was loaded *) + CDT := CURRENT_TIME + OFFSET ; + ELSE + CDT := CURRENT_TIME ; + END_IF ; + + Q := IN ; + PREV_IN := IN ; +END_FUNCTION_BLOCK diff --git a/libs/sources/iec-standard-fb/bistable.st b/libs/sources/iec-standard-fb/bistable.st new file mode 100644 index 0000000..f1ce17a --- /dev/null +++ b/libs/sources/iec-standard-fb/bistable.st @@ -0,0 +1,13 @@ +(* IEC 61131-3 Standard Function Blocks: Bistable Latches *) + +FUNCTION_BLOCK SR + VAR_INPUT S1, R : BOOL; END_VAR + VAR_OUTPUT Q1 : BOOL; END_VAR + Q1 := S1 OR ((NOT R) AND Q1); +END_FUNCTION_BLOCK + +FUNCTION_BLOCK RS + VAR_INPUT S, R1 : BOOL; END_VAR + VAR_OUTPUT Q1 : BOOL; END_VAR + Q1 := (NOT R1) AND (S OR Q1); +END_FUNCTION_BLOCK diff --git a/libs/sources/iec-standard-fb/counter.st b/libs/sources/iec-standard-fb/counter.st new file mode 100644 index 0000000..e1bd4f5 --- /dev/null +++ b/libs/sources/iec-standard-fb/counter.st @@ -0,0 +1,396 @@ +(* IEC 61131-3 Standard Function Blocks: Counters *) + +FUNCTION_BLOCK CTU + VAR_INPUT + CU : BOOL; + R : BOOL; + PV : INT; + END_VAR + VAR_OUTPUT + Q : BOOL; + CV : INT; + END_VAR + VAR + CU_T : R_TRIG; + END_VAR + CU_T(CLK := CU); + IF R THEN + CV := 0; + ELSIF CU_T.Q AND (CV < PV) THEN + CV := CV + 1; + END_IF; + Q := (CV >= PV); +END_FUNCTION_BLOCK + +FUNCTION_BLOCK CTD + VAR_INPUT + CD : BOOL; + LD : BOOL; + PV : INT; + END_VAR + VAR_OUTPUT + Q : BOOL; + CV : INT; + END_VAR + VAR + CD_T : F_TRIG; + END_VAR + CD_T(CLK := CD); + IF LD THEN + CV := PV; + ELSIF CD_T.Q AND (CV > 0) THEN + CV := CV - 1; + END_IF; + Q := (CV <= 0); +END_FUNCTION_BLOCK + +FUNCTION_BLOCK CTUD + VAR_INPUT + CU : BOOL; + CD : BOOL; + R : BOOL; + LD : BOOL; + PV : INT; + END_VAR + VAR_OUTPUT + QU : BOOL; + QD : BOOL; + CV : INT; + END_VAR + VAR + CU_T : R_TRIG; + CD_T : F_TRIG; + END_VAR + CU_T(CLK := CU); + CD_T(CLK := CD); + IF R THEN + CV := 0; + ELSIF LD THEN + CV := PV; + ELSE + IF CU_T.Q AND (CV < PV) THEN + CV := CV + 1; + END_IF; + IF CD_T.Q AND (CV > 0) THEN + CV := CV - 1; + END_IF; + END_IF; + QU := (CV >= PV); + QD := (CV <= 0); +END_FUNCTION_BLOCK + +FUNCTION_BLOCK CTU_DINT + VAR_INPUT + CU : BOOL; + R : BOOL; + PV : DINT; + END_VAR + VAR_OUTPUT + Q : BOOL; + CV : DINT; + END_VAR + VAR + CU_T : R_TRIG; + END_VAR + CU_T(CLK := CU); + IF R THEN + CV := 0; + ELSIF CU_T.Q AND (CV < PV) THEN + CV := CV + 1; + END_IF; + Q := (CV >= PV); +END_FUNCTION_BLOCK + +FUNCTION_BLOCK CTU_LINT + VAR_INPUT + CU : BOOL; + R : BOOL; + PV : LINT; + END_VAR + VAR_OUTPUT + Q : BOOL; + CV : LINT; + END_VAR + VAR + CU_T : R_TRIG; + END_VAR + CU_T(CLK := CU); + IF R THEN + CV := 0; + ELSIF CU_T.Q AND (CV < PV) THEN + CV := CV + 1; + END_IF; + Q := (CV >= PV); +END_FUNCTION_BLOCK + +FUNCTION_BLOCK CTU_UDINT + VAR_INPUT + CU : BOOL; + R : BOOL; + PV : UDINT; + END_VAR + VAR_OUTPUT + Q : BOOL; + CV : UDINT; + END_VAR + VAR + CU_T : R_TRIG; + END_VAR + CU_T(CLK := CU); + IF R THEN + CV := 0; + ELSIF CU_T.Q AND (CV < PV) THEN + CV := CV + 1; + END_IF; + Q := (CV >= PV); +END_FUNCTION_BLOCK + +FUNCTION_BLOCK CTU_ULINT + VAR_INPUT + CU : BOOL; + R : BOOL; + PV : ULINT; + END_VAR + VAR_OUTPUT + Q : BOOL; + CV : ULINT; + END_VAR + VAR + CU_T : R_TRIG; + END_VAR + CU_T(CLK := CU); + IF R THEN + CV := 0; + ELSIF CU_T.Q AND (CV < PV) THEN + CV := CV + 1; + END_IF; + Q := (CV >= PV); +END_FUNCTION_BLOCK + +FUNCTION_BLOCK CTD_DINT + VAR_INPUT + CD : BOOL; + LD : BOOL; + PV : DINT; + END_VAR + VAR_OUTPUT + Q : BOOL; + CV : DINT; + END_VAR + VAR + CD_T : F_TRIG; + END_VAR + CD_T(CLK := CD); + IF LD THEN + CV := PV; + ELSIF CD_T.Q AND (CV > 0) THEN + CV := CV - 1; + END_IF; + Q := (CV <= 0); +END_FUNCTION_BLOCK + +FUNCTION_BLOCK CTD_LINT + VAR_INPUT + CD : BOOL; + LD : BOOL; + PV : LINT; + END_VAR + VAR_OUTPUT + Q : BOOL; + CV : LINT; + END_VAR + VAR + CD_T : F_TRIG; + END_VAR + CD_T(CLK := CD); + IF LD THEN + CV := PV; + ELSIF CD_T.Q AND (CV > 0) THEN + CV := CV - 1; + END_IF; + Q := (CV <= 0); +END_FUNCTION_BLOCK + +FUNCTION_BLOCK CTD_UDINT + VAR_INPUT + CD : BOOL; + LD : BOOL; + PV : UDINT; + END_VAR + VAR_OUTPUT + Q : BOOL; + CV : UDINT; + END_VAR + VAR + CD_T : F_TRIG; + END_VAR + CD_T(CLK := CD); + IF LD THEN + CV := PV; + ELSIF CD_T.Q AND (CV > 0) THEN + CV := CV - 1; + END_IF; + Q := (CV <= 0); +END_FUNCTION_BLOCK + +FUNCTION_BLOCK CTD_ULINT + VAR_INPUT + CD : BOOL; + LD : BOOL; + PV : ULINT; + END_VAR + VAR_OUTPUT + Q : BOOL; + CV : ULINT; + END_VAR + VAR + CD_T : F_TRIG; + END_VAR + CD_T(CLK := CD); + IF LD THEN + CV := PV; + ELSIF CD_T.Q AND (CV > 0) THEN + CV := CV - 1; + END_IF; + Q := (CV <= 0); +END_FUNCTION_BLOCK + +FUNCTION_BLOCK CTUD_DINT + VAR_INPUT + CU : BOOL; + CD : BOOL; + R : BOOL; + LD : BOOL; + PV : DINT; + END_VAR + VAR_OUTPUT + QU : BOOL; + QD : BOOL; + CV : DINT; + END_VAR + VAR + CU_T : R_TRIG; + CD_T : F_TRIG; + END_VAR + CU_T(CLK := CU); + CD_T(CLK := CD); + IF R THEN + CV := 0; + ELSIF LD THEN + CV := PV; + ELSE + IF CU_T.Q AND (CV < PV) THEN + CV := CV + 1; + END_IF; + IF CD_T.Q AND (CV > 0) THEN + CV := CV - 1; + END_IF; + END_IF; + QU := (CV >= PV); + QD := (CV <= 0); +END_FUNCTION_BLOCK + +FUNCTION_BLOCK CTUD_LINT + VAR_INPUT + CU : BOOL; + CD : BOOL; + R : BOOL; + LD : BOOL; + PV : LINT; + END_VAR + VAR_OUTPUT + QU : BOOL; + QD : BOOL; + CV : LINT; + END_VAR + VAR + CU_T : R_TRIG; + CD_T : F_TRIG; + END_VAR + CU_T(CLK := CU); + CD_T(CLK := CD); + IF R THEN + CV := 0; + ELSIF LD THEN + CV := PV; + ELSE + IF CU_T.Q AND (CV < PV) THEN + CV := CV + 1; + END_IF; + IF CD_T.Q AND (CV > 0) THEN + CV := CV - 1; + END_IF; + END_IF; + QU := (CV >= PV); + QD := (CV <= 0); +END_FUNCTION_BLOCK + +FUNCTION_BLOCK CTUD_UDINT + VAR_INPUT + CU : BOOL; + CD : BOOL; + R : BOOL; + LD : BOOL; + PV : UDINT; + END_VAR + VAR_OUTPUT + QU : BOOL; + QD : BOOL; + CV : UDINT; + END_VAR + VAR + CU_T : R_TRIG; + CD_T : F_TRIG; + END_VAR + CU_T(CLK := CU); + CD_T(CLK := CD); + IF R THEN + CV := 0; + ELSIF LD THEN + CV := PV; + ELSE + IF CU_T.Q AND (CV < PV) THEN + CV := CV + 1; + END_IF; + IF CD_T.Q AND (CV > 0) THEN + CV := CV - 1; + END_IF; + END_IF; + QU := (CV >= PV); + QD := (CV <= 0); +END_FUNCTION_BLOCK + +FUNCTION_BLOCK CTUD_ULINT + VAR_INPUT + CU : BOOL; + CD : BOOL; + R : BOOL; + LD : BOOL; + PV : ULINT; + END_VAR + VAR_OUTPUT + QU : BOOL; + QD : BOOL; + CV : ULINT; + END_VAR + VAR + CU_T : R_TRIG; + CD_T : F_TRIG; + END_VAR + CU_T(CLK := CU); + CD_T(CLK := CD); + IF R THEN + CV := 0; + ELSIF LD THEN + CV := PV; + ELSE + IF CU_T.Q AND (CV < PV) THEN + CV := CV + 1; + END_IF; + IF CD_T.Q AND (CV > 0) THEN + CV := CV - 1; + END_IF; + END_IF; + QU := (CV >= PV); + QD := (CV <= 0); +END_FUNCTION_BLOCK diff --git a/libs/sources/iec-standard-fb/edge_detection.st b/libs/sources/iec-standard-fb/edge_detection.st new file mode 100644 index 0000000..a86d5ca --- /dev/null +++ b/libs/sources/iec-standard-fb/edge_detection.st @@ -0,0 +1,17 @@ +(* IEC 61131-3 Standard Function Blocks: Edge Detection *) + +FUNCTION_BLOCK R_TRIG + VAR_INPUT CLK : BOOL; END_VAR + VAR_OUTPUT Q : BOOL; END_VAR + VAR RETAIN M : BOOL; END_VAR + Q := CLK AND NOT M; + M := CLK; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK F_TRIG + VAR_INPUT CLK : BOOL; END_VAR + VAR_OUTPUT Q : BOOL; END_VAR + VAR RETAIN M : BOOL := TRUE; END_VAR + Q := NOT CLK AND NOT M; + M := NOT CLK; +END_FUNCTION_BLOCK diff --git a/libs/sources/iec-standard-fb/library.json b/libs/sources/iec-standard-fb/library.json new file mode 100644 index 0000000..0934771 --- /dev/null +++ b/libs/sources/iec-standard-fb/library.json @@ -0,0 +1,79 @@ +{ + "name": "iec-standard-fb", + "displayName": "Standard Function Blocks", + "version": "1.0.0", + "namespace": "strucpp", + "description": "IEC 61131-3 Standard Function Blocks (auto-generated from ST sources)", + "isBuiltin": true, + "blocks": { + "R_TRIG": { + "documentation": "The output produces a single pulse when a rising edge is detected." + }, + "F_TRIG": { + "documentation": "The output produces a single pulse when a falling edge is detected." + }, + "SR": { + "documentation": "The SR bistable is a latch where the Set dominates." + }, + "RS": { + "documentation": "The RS bistable is a latch where the Reset dominates." + }, + "SEMA": { + "documentation": "The semaphore provides a mechanism to allow software elements mutually exclusive access to certain resources." + }, + "CTU": { + "documentation": "The up-counter can be used to signal when a count has reached a maximum value." + }, + "CTU_DINT": { + "documentation": "The up-counter can be used to signal when a count has reached a maximum value." + }, + "CTU_LINT": { + "documentation": "The up-counter can be used to signal when a count has reached a maximum value." + }, + "CTU_UDINT": { + "documentation": "The up-counter can be used to signal when a count has reached a maximum value." + }, + "CTU_ULINT": { + "documentation": "The up-counter can be used to signal when a count has reached a maximum value." + }, + "CTD": { + "documentation": "The down-counter can be used to signal when a count has reached zero, on counting down from a preset value." + }, + "CTD_DINT": { + "documentation": "The down-counter can be used to signal when a count has reached zero, on counting down from a preset value." + }, + "CTD_LINT": { + "documentation": "The down-counter can be used to signal when a count has reached zero, on counting down from a preset value." + }, + "CTD_UDINT": { + "documentation": "The down-counter can be used to signal when a count has reached zero, on counting down from a preset value." + }, + "CTD_ULINT": { + "documentation": "The down-counter can be used to signal when a count has reached zero, on counting down from a preset value." + }, + "CTUD": { + "documentation": "The up-down counter has two inputs CU and CD. It can be used to both count up on one input and down on the other." + }, + "CTUD_DINT": { + "documentation": "The up-down counter has two inputs CU and CD. It can be used to both count up on one input and down on the other." + }, + "CTUD_LINT": { + "documentation": "The up-down counter has two inputs CU and CD. It can be used to both count up on one input and down on the other." + }, + "CTUD_UDINT": { + "documentation": "The up-down counter has two inputs CU and CD. It can be used to both count up on one input and down on the other." + }, + "CTUD_ULINT": { + "documentation": "The up-down counter has two inputs CU and CD. It can be used to both count up on one input and down on the other." + }, + "TON": { + "documentation": "The on-delay timer can be used to delay setting an output true, for fixed period after an input becomes true." + }, + "TOF": { + "documentation": "The off-delay timer can be used to delay setting an output false, for fixed period after input goes false." + }, + "TP": { + "documentation": "The pulse timer can be used to generate output pulses of a given time duration." + } + } +} diff --git a/libs/sources/iec-standard-fb/sema.st b/libs/sources/iec-standard-fb/sema.st new file mode 100644 index 0000000..a3e719a --- /dev/null +++ b/libs/sources/iec-standard-fb/sema.st @@ -0,0 +1,18 @@ +(* IEC 61131-3 Standard Function Blocks: Semaphore *) + +FUNCTION_BLOCK SEMA + VAR_INPUT + CLAIM : BOOL; + RELEASE : BOOL; + END_VAR + VAR_OUTPUT + BUSY : BOOL; + END_VAR + VAR + Q_INTERNAL : BOOL; + END_VAR + + Q_INTERNAL := CLAIM OR ( Q_INTERNAL AND (NOT RELEASE)); + BUSY := Q_INTERNAL; + +END_FUNCTION_BLOCK diff --git a/libs/sources/iec-standard-fb/timer.st b/libs/sources/iec-standard-fb/timer.st new file mode 100644 index 0000000..d8c3642 --- /dev/null +++ b/libs/sources/iec-standard-fb/timer.st @@ -0,0 +1,121 @@ +(* IEC 61131-3 Standard Function Blocks: Timers *) +(* Uses TIME() built-in function for current time (CODESYS-compatible) *) + +FUNCTION_BLOCK TON + VAR_INPUT + IN : BOOL; + PT : TIME; + END_VAR + VAR_OUTPUT + Q : BOOL; + ET : TIME; + END_VAR + VAR + STATE : SINT; + PREV_IN : BOOL; + CURRENT_TIME, START_TIME : TIME; + END_VAR + + CURRENT_TIME := TIME(); + + IF ((STATE = 0) AND NOT(PREV_IN) AND IN) THEN + STATE := 1; + Q := FALSE; + START_TIME := CURRENT_TIME; + ELSE + IF (NOT(IN)) THEN + ET := T#0s; + Q := FALSE; + STATE := 0; + ELSIF (STATE = 1) THEN + IF ((START_TIME + PT) <= CURRENT_TIME) THEN + STATE := 2; + Q := TRUE; + ET := PT; + ELSE + ET := CURRENT_TIME - START_TIME; + END_IF; + END_IF; + END_IF; + + PREV_IN := IN; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK TOF + VAR_INPUT + IN : BOOL; + PT : TIME; + END_VAR + VAR_OUTPUT + Q : BOOL; + ET : TIME; + END_VAR + VAR + STATE : SINT; + PREV_IN : BOOL; + CURRENT_TIME, START_TIME : TIME; + END_VAR + + CURRENT_TIME := TIME(); + + IF ((STATE = 0) AND PREV_IN AND NOT(IN)) THEN + STATE := 1; + START_TIME := CURRENT_TIME; + ELSE + IF (IN) THEN + ET := T#0s; + Q := TRUE; + STATE := 0; + ELSIF (STATE = 1) THEN + IF ((START_TIME + PT) <= CURRENT_TIME) THEN + STATE := 2; + Q := FALSE; + ET := PT; + ELSE + Q := TRUE; + ET := CURRENT_TIME - START_TIME; + END_IF; + END_IF; + END_IF; + + PREV_IN := IN; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK TP + VAR_INPUT + IN : BOOL; + PT : TIME; + END_VAR + VAR_OUTPUT + Q : BOOL; + ET : TIME; + END_VAR + VAR + STATE : SINT; + PREV_IN : BOOL; + CURRENT_TIME, START_TIME : TIME; + END_VAR + + CURRENT_TIME := TIME(); + + IF ((STATE = 0) AND NOT(PREV_IN) AND IN) THEN + STATE := 1; + Q := TRUE; + START_TIME := CURRENT_TIME; + ELSIF (STATE = 1) THEN + IF ((START_TIME + PT) <= CURRENT_TIME) THEN + STATE := 2; + Q := FALSE; + ET := PT; + ELSE + ET := CURRENT_TIME - START_TIME; + END_IF; + END_IF; + + IF (NOT(IN) AND (STATE = 2)) THEN + STATE := 0; + ET := T#0s; + END_IF; + + PREV_IN := IN; +END_FUNCTION_BLOCK diff --git a/libs/sources/iec-std-functions/library.json b/libs/sources/iec-std-functions/library.json new file mode 100644 index 0000000..6d62749 --- /dev/null +++ b/libs/sources/iec-std-functions/library.json @@ -0,0 +1,8 @@ +{ + "name": "iec-std-functions", + "displayName": "Standard Functions", + "version": "1.0.0", + "namespace": "strucpp", + "description": "IEC 61131-3 standard functions (ADD/SUB/MUX/SHL/CONCAT/...) — synthesized from strucpp's StdFunctionRegistry. No ST sources: every function is a compiler+runtime intrinsic. The .stlib exists purely so editor tooling can list, categorize, and type-check standard functions through the same path it uses for ordinary libraries.", + "isBuiltin": true +} diff --git a/libs/sources/oscat-basic/library.json b/libs/sources/oscat-basic/library.json new file mode 100644 index 0000000..5c6a219 --- /dev/null +++ b/libs/sources/oscat-basic/library.json @@ -0,0 +1,13 @@ +{ + "name": "oscat-basic", + "displayName": "OSCAT Basic", + "version": "335.0.0", + "namespace": "oscat_basic", + "description": "OSCAT Basic 3.35 — open-source community automation library (auto-imported from oscat_basic_335.library)", + "isBuiltin": false, + "codesysSource": "oscat_basic_335.library", + "globalConstants": { + "STRING_LENGTH": 254, + "LIST_LENGTH": 254 + } +} diff --git a/tests/fixtures/codesys/oscat_basic_335_codesys3.library b/libs/sources/oscat-basic/oscat_basic_335.library similarity index 100% rename from tests/fixtures/codesys/oscat_basic_335_codesys3.library rename to libs/sources/oscat-basic/oscat_basic_335.library diff --git a/package.json b/package.json index 8c435e3..c0366e3 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,10 @@ "types": "dist/index.d.ts", "type": "module", "scripts": { - "build": "tsc", + "build": "node scripts/rebuild-libs.mjs", + "build:tsc-only": "tsc", "build:stdlib": "node scripts/generate-stdlib.mjs", + "build:additional-fb": "node scripts/generate-additional-fb.mjs", "build:libs": "node scripts/rebuild-libs.mjs", "build:bundle": "npm run build && node scripts/bundle.mjs", "build:pkg": "npm run build:bundle && pkg dist/strucpp-bundle.cjs --targets node18-linux-x64,node18-win-x64,node18-macos-x64 --out-path dist/bin --compress GZip", @@ -23,7 +25,8 @@ "format": "prettier --write src/", "format:check": "prettier --check src/", "typecheck": "tsc --noEmit", - "clean": "rm -rf dist/", + "clean": "rm -rf dist/ libs/*.stlib libs/iec-types.json vscode-extension/bundled-libs/*.stlib vscode-extension/bundled-libs/iec-types.json", + "prepack": "npm run build", "prepublishOnly": "npm run build", "prepare": "husky" }, diff --git a/scripts/build-iec-types-json.mjs b/scripts/build-iec-types-json.mjs new file mode 100644 index 0000000..38a2254 --- /dev/null +++ b/scripts/build-iec-types-json.mjs @@ -0,0 +1,70 @@ +#!/usr/bin/env node +/** + * Emit `libs/iec-types.json` — the canonical IEC base-type registry + * shipped to downstream consumers (OpenPLC Editor, future xml2st + * replacement, third-party tooling). + * + * The data is hand-authored in `src/semantic/iec-types-data.ts`; this + * script transcodes it to JSON and writes it next to the .stlib + * archives. Both source and artifact are committed — strucpp's own + * code reads the TS module directly (typed, fast) and external + * consumers read the JSON via `node_modules/strucpp/libs/iec-types.json`. + * + * A `schemaVersion` field guards against silent shape drift: bump it + * here whenever IECTypeMetadata gains/loses/renames a field, and any + * out-of-date editor will fail loudly on first read instead of + * silently mis-parsing. + */ + +import { writeFileSync } from "fs"; +import { resolve, dirname } from "path"; +import { fileURLToPath } from "url"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); +const projectRoot = resolve(__dirname, ".."); + +/** + * Bump on any breaking change to the per-type metadata shape (renamed + * fields, dropped fields, changed field semantics). Additive + * changes — new optional fields, new wireFormat values — do not need + * a bump as long as old consumers still parse the JSON correctly. + */ +const SCHEMA_VERSION = 1; + +export async function buildIecTypesJson() { + // Load from the freshly-compiled dist/ — `rebuild-libs.mjs` does a + // `tsc` pass before importing, so by the time this runs the dist + // mirror of `iec-types-data.ts` is current. + const data = await import( + resolve(projectRoot, "dist/semantic/iec-types-data.js") + ); + + const out = { + $schema: + "https://github.com/Autonomy-Logic/strucpp/blob/main/docs/iec-types.schema.json", + schemaVersion: SCHEMA_VERSION, + description: + "Canonical IEC 61131-3 elementary type registry emitted by " + + "strucpp. Source of truth — downstream tools (OpenPLC Editor, " + + "xml2st replacement, third-party generators) should read from " + + "here rather than maintaining their own type tables.", + elementaryTypes: data.IEC_BASE_TYPES, + }; + + const target = resolve(projectRoot, "libs/iec-types.json"); + writeFileSync(target, JSON.stringify(out, null, 2) + "\n", "utf-8"); + console.log( + `[build-iec-types-json] Wrote ${out.elementaryTypes.length} elementary types to ${target}`, + ); + return target; +} + +const isDirectRun = + process.argv[1] && resolve(process.argv[1]) === resolve(__filename); +if (isDirectRun) { + buildIecTypesJson().catch((err) => { + console.error(err); + process.exit(1); + }); +} diff --git a/scripts/generate-additional-fb.mjs b/scripts/generate-additional-fb.mjs new file mode 100644 index 0000000..42e9580 --- /dev/null +++ b/scripts/generate-additional-fb.mjs @@ -0,0 +1,120 @@ +#!/usr/bin/env node +/** + * Generate the Additional Function Blocks library `.stlib` archive. + * + * Sources of truth (all on disk): + * - libs/sources/additional-function-blocks/*.st — ST sources + * - libs/sources/additional-function-blocks/library.json — manifest + * metadata + * + per-block + * docs + * + * Produces: + * - libs/additional-function-blocks.stlib + * + * Block source order matters for type-resolution: PID's locals are typed + * INTEGRAL/DERIVATIVE, so those FBs must be visible when PID is type- + * checked. The script enforces a deterministic order rather than relying + * on filesystem traversal. + * + * Run: npm run build:additional-fb + */ + +import { readFileSync, readdirSync, writeFileSync, mkdirSync, existsSync } from "fs"; +import { resolve, dirname } from "path"; +import { fileURLToPath } from "url"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); +const projectRoot = resolve(__dirname, ".."); + +const { compileStlib } = await import( + resolve(projectRoot, "dist/library/library-compiler.js") +); +const { loadLibraryConfig, applyLibraryConfigDocumentation } = await import( + resolve(projectRoot, "dist/library/library-config.js") +); + +const sourcesDir = resolve(projectRoot, "libs", "sources", "additional-function-blocks"); +const libsDir = resolve(projectRoot, "libs"); +const outPath = resolve(libsDir, "additional-function-blocks.stlib"); + +if (!existsSync(sourcesDir)) { + console.error(`Error: sources directory not found: ${sourcesDir}`); + process.exit(1); +} + +const config = loadLibraryConfig(sourcesDir); +if (!config) { + console.error(`Error: ${sourcesDir}/library.json not found`); + process.exit(1); +} + +const ORDERED = [ + "integral.st", + "derivative.st", + "rtc.st", + "pid.st", + "ramp.st", + "hysteresis.st", +]; +const onDisk = new Set(readdirSync(sourcesDir).filter((f) => f.endsWith(".st"))); +const missing = ORDERED.filter((f) => !onDisk.has(f)); +if (missing.length > 0) { + console.error( + `Error: missing source files in ${sourcesDir}:\n ${missing.join("\n ")}`, + ); + process.exit(1); +} +const sources = ORDERED.map((fileName) => ({ + fileName, + source: readFileSync(resolve(sourcesDir, fileName), "utf-8"), +})); + +const result = compileStlib(sources, { + name: config.name, + version: config.version, + namespace: config.namespace, + noSource: false, + builtin: config.isBuiltin === true, +}); + +if (!result.success) { + console.error( + "Failed to compile Additional Function Blocks library:", + result.errors.map((e) => `\n - ${e.message}`).join(""), + ); + process.exit(1); +} + +if (config.description) { + result.archive.manifest.description = config.description; +} + +const docReport = applyLibraryConfigDocumentation(result.archive, config); +if ( + docReport.unknownBlockDocs.length > 0 || + docReport.unknownFunctionDocs.length > 0 +) { + console.error("Error: library.json references unknown symbols:"); + for (const name of docReport.unknownBlockDocs) { + console.error(` - blocks["${name}"] — no FB by that name in the compiled manifest`); + } + for (const name of docReport.unknownFunctionDocs) { + console.error(` - functions["${name}"] — no function by that name in the compiled manifest`); + } + process.exit(1); +} + +mkdirSync(libsDir, { recursive: true }); +writeFileSync(outPath, JSON.stringify(result.archive, null, 2) + "\n", "utf-8"); + +const fbCount = result.archive.manifest.functionBlocks.length; +const docCount = docReport.blocksDocumented; +const undoc = fbCount - docCount; +const sizeKB = Math.round(Buffer.byteLength(JSON.stringify(result.archive)) / 1024); +const undocSuffix = undoc > 0 ? `, ${undoc} undocumented` : ""; +console.log( + `Generated ${outPath} (${fbCount} function blocks, ` + + `${docCount} documented${undocSuffix}, ${sizeKB}KB)`, +); diff --git a/scripts/generate-stdlib.mjs b/scripts/generate-stdlib.mjs index f7b8d6e..5b03156 100644 --- a/scripts/generate-stdlib.mjs +++ b/scripts/generate-stdlib.mjs @@ -1,90 +1,118 @@ #!/usr/bin/env node /** - * Generate the standard FB library `.stlib` archive from ST source files. + * Generate the IEC 61131-3 Standard FB library `.stlib` archive. * - * Uses the STruC++ `compileStlib()` API to produce the archive. Sources are - * read from the existing `.stlib` archive (its embedded `sources` field), so - * this script works even after the standalone `.st` files have been removed. + * Sources of truth (all on disk): + * - libs/sources/iec-standard-fb/*.st — the ST source files + * - libs/sources/iec-standard-fb/library.json — manifest metadata + per-block docs * - * If the archive does not yet exist (bootstrap), pass .st file paths as args: - * node scripts/generate-stdlib.mjs edge_detection.st bistable.st counter.st timer.st + * Produces: + * - libs/iec-standard-fb.stlib * - * Run: node scripts/generate-stdlib.mjs - * Called by: npm run build:stdlib + * library.json carries everything that isn't derivable from ST: name, + * version, namespace, description, isBuiltin, and the per-FB + * documentation prose surfaced in editor hover dialogs. Block names + * referenced in library.json must match the FBs the compiler emits — + * the apply step reports any mismatch and fails the build. + * + * Run: npm run build:stdlib */ -import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs"; -import { resolve, dirname, basename } from "path"; +import { readFileSync, readdirSync, writeFileSync, mkdirSync, existsSync } from "fs"; +import { resolve, dirname } from "path"; import { fileURLToPath } from "url"; const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); +const __dirname = dirname(__filename); const projectRoot = resolve(__dirname, ".."); -// Import the compiled library compiler from dist/ const { compileStlib } = await import( resolve(projectRoot, "dist/library/library-compiler.js") ); +const { loadLibraryConfig, applyLibraryConfigDocumentation } = await import( + resolve(projectRoot, "dist/library/library-config.js") +); -const libsDir = resolve(projectRoot, "libs"); -const outPath = resolve(libsDir, "iec-standard-fb.stlib"); +const sourcesDir = resolve(projectRoot, "libs", "sources", "iec-standard-fb"); +const libsDir = resolve(projectRoot, "libs"); +const outPath = resolve(libsDir, "iec-standard-fb.stlib"); -// Determine sources: from existing archive, or from CLI args / default files -let sources; -const cliFiles = process.argv.slice(2); +if (!existsSync(sourcesDir)) { + console.error(`Error: sources directory not found: ${sourcesDir}`); + process.exit(1); +} -if (cliFiles.length > 0) { - // Bootstrap mode: read .st files from provided paths - sources = cliFiles.map((file) => { - const filePath = resolve(file); - return { - source: readFileSync(filePath, "utf-8"), - fileName: basename(filePath), - }; - }); -} else if (existsSync(outPath)) { - // Normal mode: read sources from the existing archive - const existingArchive = JSON.parse(readFileSync(outPath, "utf-8")); - if (!existingArchive.sources || existingArchive.sources.length === 0) { - console.error( - "Error: Existing .stlib archive has no embedded sources. " + - "Provide .st files as arguments to bootstrap." - ); - process.exit(1); - } - sources = existingArchive.sources; -} else { +const config = loadLibraryConfig(sourcesDir); +if (!config) { + console.error(`Error: ${sourcesDir}/library.json not found`); + process.exit(1); +} + +// Order the .st files explicitly so dependencies resolve. The IEC +// standard FBs split across four files; counter.st instantiates +// R_TRIG/F_TRIG from edge_detection.st, so edge_detection must be +// compiled first. Bistable and timer have no inter-file deps. +const ORDERED = ["edge_detection.st", "bistable.st", "counter.st", "timer.st"]; +const onDisk = new Set(readdirSync(sourcesDir).filter((f) => f.endsWith(".st"))); +const missing = ORDERED.filter((f) => !onDisk.has(f)); +if (missing.length > 0) { console.error( - "Error: No existing .stlib archive found and no .st files provided.\n" + - "Usage: node scripts/generate-stdlib.mjs [edge_detection.st bistable.st counter.st timer.st]" + `Error: missing source files in ${sourcesDir}:\n ${missing.join("\n ")}`, ); process.exit(1); } +const sources = ORDERED.map((fileName) => ({ + fileName, + source: readFileSync(resolve(sourcesDir, fileName), "utf-8"), +})); const result = compileStlib(sources, { - name: "iec-standard-fb", - version: "1.0.0", - namespace: "strucpp", + name: config.name, + version: config.version, + namespace: config.namespace, noSource: false, + builtin: config.isBuiltin === true, }); if (!result.success) { console.error( "Failed to compile standard FB library:", - result.errors.map((e) => e.message).join(", "), + result.errors.map((e) => `\n - ${e.message}`).join(""), ); process.exit(1); } -// Override manifest flags for the stdlib -result.archive.manifest.isBuiltin = true; -result.archive.manifest.description = - "IEC 61131-3 Standard Function Blocks (auto-generated from ST sources)"; +if (config.description) { + result.archive.manifest.description = config.description; +} + +const docReport = applyLibraryConfigDocumentation(result.archive, config); +if ( + docReport.unknownBlockDocs.length > 0 || + docReport.unknownFunctionDocs.length > 0 +) { + // Stale doc entries are a build error: usually means an FB was + // renamed/removed in ST without updating library.json, or a typo in + // the JSON. Fail loudly so the mismatch can't sneak into a release. + console.error("Error: library.json references unknown symbols:"); + for (const name of docReport.unknownBlockDocs) { + console.error(` - blocks["${name}"] — no FB by that name in the compiled manifest`); + } + for (const name of docReport.unknownFunctionDocs) { + console.error(` - functions["${name}"] — no function by that name in the compiled manifest`); + } + process.exit(1); +} mkdirSync(libsDir, { recursive: true }); writeFileSync(outPath, JSON.stringify(result.archive, null, 2) + "\n", "utf-8"); +const fbCount = result.archive.manifest.functionBlocks.length; +const docCount = docReport.blocksDocumented; +const undoc = fbCount - docCount; +const sizeKB = Math.round(Buffer.byteLength(JSON.stringify(result.archive)) / 1024); +const undocSuffix = undoc > 0 ? `, ${undoc} undocumented` : ""; console.log( - `Generated ${outPath} (${result.archive.manifest.functionBlocks.length} function blocks, ` + - `${Math.round(Buffer.byteLength(JSON.stringify(result.archive)) / 1024)}KB)`, + `Generated ${outPath} (${fbCount} function blocks, ` + + `${docCount} documented${undocSuffix}, ${sizeKB}KB)`, ); diff --git a/scripts/rebuild-libs.mjs b/scripts/rebuild-libs.mjs index 73f9cc4..5acc37c 100644 --- a/scripts/rebuild-libs.mjs +++ b/scripts/rebuild-libs.mjs @@ -1,36 +1,56 @@ #!/usr/bin/env node /** - * Rebuild all bundled .stlib library archives from their embedded sources. + * Rebuild all bundled .stlib library archives. * - * This script decompiles the existing archives, recompiles them with the - * current compiler, and writes back the updated archives. It ensures the - * bundled libraries always match the current codegen output. + * Every bundled library is rebuilt FROM DISK — `libs/sources//` + * holds the canonical source of truth and the matching .stlib in `libs/` + * is a pure build artefact produced here (and gitignored). + * + * Two shapes of disk-backed source are supported: + * + * - Hand-authored libs (iec-standard-fb, additional-function-blocks): + * library.json + a deterministic list of .st files. The .st files + * are concatenated in `orderedSources` order and fed to the strucpp + * compiler so cross-file type references (e.g. PID instantiating + * INTEGRAL/DERIVATIVE) resolve consistently regardless of filesystem + * traversal order. + * + * - CODESYS-imported libs (oscat-basic): library.json names a + * `codesysSource` (.library file). We run the codesys-importer + * against that file to extract POUs/TYPEs/GVLs into in-memory ST + * sources, then feed those into the same compile step. The .library + * file is the canonical source of truth — never the .stlib. * * Used as: - * - vitest globalSetup (runs before all tests) - * - npm run build:libs (manual invocation) + * - the canonical "build strucpp" entry point (`npm run build`) + * - vitest's globalSetup, so tests always see freshly-built archives * - * Refreshes `dist/` via tsc before importing from it. Otherwise a `src/` - * change without a manual `npm run build` would silently regenerate the - * .stlib archives against stale codegen — the on-disk libs would no - * longer match `src/`. tsc on this codebase runs in ~1s so the cost is - * negligible compared to the test suite that follows. + * Refreshes `dist/` via tsc before importing from it: a `src/` change + * without a manual `npm run build:tsc-only` would otherwise regenerate + * libs against stale codegen. tsc on this codebase runs in ~1s so the + * cost is negligible. */ import { execSync } from "child_process"; -import { readFileSync, writeFileSync, existsSync, copyFileSync } from "fs"; -import { resolve, dirname } from "path"; +import { readFileSync, readdirSync, writeFileSync, existsSync, copyFileSync, statSync } from "fs"; +import { resolve, dirname, relative, sep, posix } from "path"; import { fileURLToPath } from "url"; +import { buildIecTypesJson } from "./build-iec-types-json.mjs"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const projectRoot = resolve(__dirname, ".."); const libsDir = resolve(projectRoot, "libs"); +const sourcesRoot = resolve(libsDir, "sources"); const vscodeLibsDir = resolve(projectRoot, "vscode-extension", "bundled-libs"); let compileStlib; let loadStlibFromFile; +let loadLibraryConfig; +let applyLibraryConfigDocumentation; +let importCodesysLibrary; +let StdFunctionRegistry; /** * Refresh `dist/` from `src/` and import the freshly compiled modules. @@ -62,79 +82,442 @@ async function refreshAndLoadCompiler() { const loader = await import( resolve(projectRoot, "dist/library/library-loader.js") ); + const config = await import( + resolve(projectRoot, "dist/library/library-config.js") + ); + const codesysImport = await import( + resolve(projectRoot, "dist/library/codesys-import/index.js") + ); + const stdFnRegistry = await import( + resolve(projectRoot, "dist/semantic/std-function-registry.js") + ); compileStlib = compiler.compileStlib; loadStlibFromFile = loader.loadStlibFromFile; + loadLibraryConfig = config.loadLibraryConfig; + applyLibraryConfigDocumentation = config.applyLibraryConfigDocumentation; + importCodesysLibrary = codesysImport.importCodesysLibrary; + StdFunctionRegistry = stdFnRegistry.StdFunctionRegistry; } /** - * Rebuild a single .stlib archive from its embedded sources. + * Compile + archive a library from a list of in-memory ST sources. + * + * Shared core for both the disk-backed (.st files) and codesys-imported + * (.library file) build paths — the only thing that differs upstream is + * how the `sources` array gets produced. */ -function rebuildLibrary(stlibPath, options) { - const archive = loadStlibFromFile(stlibPath); - - if (!archive.sources || archive.sources.length === 0) { - throw new Error(`${stlibPath}: no embedded sources — cannot rebuild`); - } - - const result = compileStlib(archive.sources, { - name: archive.manifest.name, - version: archive.manifest.version, - namespace: archive.manifest.namespace, +function compileAndWrite({ sources, config, stlibPath, dependencies, sourcesDir }) { + const result = compileStlib(sources, { + name: config.name, + version: config.version, + namespace: config.namespace, noSource: false, - builtin: archive.manifest.isBuiltin, - dependencies: options.dependencies, - globalConstants: archive.globalConstants, + builtin: config.isBuiltin === true, + dependencies, + globalConstants: config.globalConstants, }); if (!result.success) { const errs = result.errors.map((e) => ` ${e.file ?? ""}:${e.line ?? 0}: ${e.message}`); throw new Error( - `Failed to rebuild ${archive.manifest.name}:\n${errs.join("\n")}`, + `Failed to rebuild ${config.name}:\n${errs.join("\n")}`, ); } - // Preserve description from original manifest - if (archive.manifest.description) { - result.archive.manifest.description = archive.manifest.description; + if (config.displayName) { + result.archive.manifest.displayName = config.displayName; + } + if (config.description) { + result.archive.manifest.description = config.description; + } + + const docReport = applyLibraryConfigDocumentation(result.archive, config); + if ( + docReport.unknownBlockDocs.length > 0 || + docReport.unknownFunctionDocs.length > 0 + ) { + const lines = [ + ...docReport.unknownBlockDocs.map((n) => ` blocks["${n}"] — not in compiled manifest`), + ...docReport.unknownFunctionDocs.map((n) => ` functions["${n}"] — not in compiled manifest`), + ]; + throw new Error( + `${sourcesDir}/library.json references unknown symbols:\n${lines.join("\n")}`, + ); } writeFileSync(stlibPath, JSON.stringify(result.archive, null, 2) + "\n", "utf-8"); return result.archive; } +/** + * Recursively collect all `.st` files under `dir`, returning their paths + * relative to `dir` using POSIX separators (so the values are usable as + * both file lookups and category strings on every platform). Sorted to + * keep filesystem-traversal order deterministic when no explicit + * `orderedSources` list is provided. + */ +function collectStFilesRecursive(dir) { + const out = []; + function walk(current) { + for (const entry of readdirSync(current).sort()) { + const full = resolve(current, entry); + if (statSync(full).isDirectory()) { + walk(full); + } else if (entry.endsWith(".st")) { + out.push(relative(dir, full).split(sep).join(posix.sep)); + } + } + } + walk(dir); + return out; +} + +/** + * Rebuild a hand-authored library from disk: reads library.json plus + * every .st file under libs/sources// (recursing into + * subdirectories), recompiles, applies block docs, writes the .stlib + * archive. + * + * Folder layout drives manifest hierarchy: a file at + * `libs/sources/my_lib/some_category/foo.st` produces manifest entries + * tagged with `category: "some_category"`. Files at the lib root carry + * no category. Hierarchy is purely metadata — every source is still + * stored flat-by-filename inside the .stlib archive (just with the + * `category` field set on the source entry, mirroring the manifest). + * + * `orderedSources` is optional. When provided it enforces a + * deterministic compile order (so cross-file type resolution doesn't + * depend on filesystem traversal — see PID needing INTEGRAL/DERIVATIVE + * first). Each entry is a path relative to the lib's source directory + * and may include subfolders (e.g. `["motion/ramp.st", "motion/pid.st"]`). + * When omitted, every .st under the lib directory is picked up in + * sorted order. + */ +function rebuildLibraryFromDisk({ libDirName, stlibPath, orderedSources, dependencies }) { + const sourcesDir = resolve(sourcesRoot, libDirName); + if (!existsSync(sourcesDir)) { + throw new Error(`Source directory not found: ${sourcesDir}`); + } + + const config = loadLibraryConfig(sourcesDir); + if (!config) { + throw new Error(`${sourcesDir}/library.json not found`); + } + + const allRelative = collectStFilesRecursive(sourcesDir); + let pickedRelative; + if (orderedSources && orderedSources.length > 0) { + const onDisk = new Set(allRelative); + const missing = orderedSources.filter((f) => !onDisk.has(f)); + if (missing.length > 0) { + throw new Error( + `Missing source files in ${sourcesDir}:\n ${missing.join("\n ")}`, + ); + } + pickedRelative = orderedSources; + } else { + pickedRelative = allRelative; + } + + const sources = pickedRelative.map((relPath) => { + const slashIdx = relPath.lastIndexOf("/"); + const fileName = slashIdx === -1 ? relPath : relPath.slice(slashIdx + 1); + const category = slashIdx === -1 ? undefined : relPath.slice(0, slashIdx); + const entry = { + fileName, + source: readFileSync(resolve(sourcesDir, relPath), "utf-8"), + }; + if (category) entry.category = category; + return entry; + }); + + return compileAndWrite({ sources, config, stlibPath, dependencies, sourcesDir }); +} + +/** + * Rebuild a CODESYS-imported library from disk: reads library.json plus + * the bundled .library file from libs/sources//, runs the + * codesys-importer to extract ST sources, then compiles them through + * the same path as hand-authored libs. + * + * `library.json.codesysSource` names the .library file relative to the + * lib's source directory. We resolve it, hand it off to importCodesysLibrary + * (which auto-detects V2.3 vs V3), and feed the resulting in-memory ST + * sources into compileAndWrite. The .library file is the canonical source + * of truth — never the .stlib output. + */ +function rebuildLibraryFromCodesys({ libDirName, stlibPath, dependencies }) { + const sourcesDir = resolve(sourcesRoot, libDirName); + if (!existsSync(sourcesDir)) { + throw new Error(`Source directory not found: ${sourcesDir}`); + } + + const config = loadLibraryConfig(sourcesDir); + if (!config) { + throw new Error(`${sourcesDir}/library.json not found`); + } + if (!config.codesysSource) { + throw new Error( + `${sourcesDir}/library.json missing 'codesysSource' field — required for codesys-imported libs`, + ); + } + + const codesysPath = resolve(sourcesDir, config.codesysSource); + if (!existsSync(codesysPath)) { + throw new Error(`CODESYS source file not found: ${codesysPath}`); + } + + const importResult = importCodesysLibrary(codesysPath); + if (!importResult.success) { + throw new Error( + `Failed to import ${codesysPath}:\n ${importResult.errors.join("\n ")}`, + ); + } + + // Merge constants discovered by the importer (VAR_GLOBAL CONSTANT + // integer blocks promoted to compile-time values) over any explicit + // overrides in library.json — explicit wins, since users sometimes + // override OSCAT defaults like STRING_LENGTH for memory-constrained + // targets. + const mergedConfig = { + ...config, + globalConstants: { + ...importResult.globalConstants, + ...(config.globalConstants ?? {}), + }, + }; + + return compileAndWrite({ + sources: importResult.sources, + config: mergedConfig, + stlibPath, + dependencies, + sourcesDir, + }); +} + +/** + * Display-name mapping for std-function categories. + * + * StdFunctionRegistry uses lowercase identifiers ("numeric", "trig", + * "arithmetic", …); the .stlib `category` field lives next to user- + * authored hierarchy paths, so we capitalize them here for consistent + * presentation in editor library trees. Two registry buckets fold into + * "Numerical" since IEC 61131-3 groups numeric and trig functions + * together visually; everything else is one-to-one. + */ +const STD_FN_CATEGORY_DISPLAY = { + numeric: "Numerical", + trig: "Numerical", + arithmetic: "Arithmetic", + selection: "Selection", + comparison: "Comparison", + bitwise: "Bitwise", + bitshift: "BitShift", + conversion: "TypeConversion", + string: "CharacterString", + time: "Time", + system: "System", +}; + +/** + * Map one StdFunctionRegistry descriptor onto a LibraryFunctionEntry. + * + * Type encoding: a `specific` constraint emits the concrete IEC type + * name (`INT`, `BOOL`, …); any other constraint passes through as the + * generic name (`ANY_NUM`, `ANY_INT`, …). Tooling unifies parameters + * and the return type by matching identical generic names — see the + * docstring on LibraryFunctionEntry for the contract. + * + * Variadic shape: `{ minArgs }` is forwarded so editor blocks can grow + * extra input pins past the declared parameter list (ADD/MUL accept any + * number of operands ≥ 2, MUX accepts a selector + any number of + * inputs ≥ 2). + */ +function descriptorToFunctionEntry(desc) { + const returnType = + desc.returnConstraint === "specific" + ? desc.specificReturnType + : desc.returnConstraint; + + const parameters = desc.params.map((p) => ({ + name: p.name, + type: p.constraint === "specific" ? p.specificType : p.constraint, + direction: "input", + })); + + const entry = { + name: desc.name, + returnType, + parameters, + }; + if (desc.isVariadic) { + entry.variadic = { minArgs: desc.minArgs ?? desc.params.length }; + } + const category = STD_FN_CATEGORY_DISPLAY[desc.category]; + if (category) entry.category = category; + return entry; +} + +/** + * Build the synthetic `iec-std-functions.stlib` archive. + * + * No ST sources, no codesys-importer involvement, no compileStlib call: + * the std functions are runtime intrinsics that the strucpp codegen + * inlines via `StdFunctionRegistry`, so the .stlib is purely a metadata + * carrier for editors and other tooling. We synthesise a valid + * `StlibArchive` shape directly (empty headerCode/cppCode/dependencies, + * one `LibraryFunctionEntry` per descriptor) and then run the existing + * `applyLibraryConfigDocumentation` step against it so a future + * `library.json` `functions: { ADD: { documentation: "…" } }` entry can + * supply hand-curated docs without changing this script. + */ +function synthesizeStdFunctionsLibrary({ libDirName, stlibPath }) { + const sourcesDir = resolve(sourcesRoot, libDirName); + if (!existsSync(sourcesDir)) { + throw new Error(`Source directory not found: ${sourcesDir}`); + } + const config = loadLibraryConfig(sourcesDir); + if (!config) { + throw new Error(`${sourcesDir}/library.json not found`); + } + + const registry = new StdFunctionRegistry(); + const functions = registry + .getAll() + .map(descriptorToFunctionEntry) + .sort((a, b) => a.name.localeCompare(b.name)); + + const archive = { + formatVersion: 1, + manifest: { + name: config.name, + version: config.version, + namespace: config.namespace, + functions, + functionBlocks: [], + types: [], + headers: [], + isBuiltin: config.isBuiltin === true, + }, + chunks: [], + dependencies: [], + }; + if (config.displayName) archive.manifest.displayName = config.displayName; + if (config.description) archive.manifest.description = config.description; + + const docReport = applyLibraryConfigDocumentation(archive, config); + if (docReport.unknownFunctionDocs.length > 0) { + const lines = docReport.unknownFunctionDocs.map( + (n) => ` functions["${n}"] — not in compiled manifest`, + ); + throw new Error( + `${sourcesDir}/library.json references unknown symbols:\n${lines.join("\n")}`, + ); + } + + writeFileSync(stlibPath, JSON.stringify(archive, null, 2) + "\n", "utf-8"); + return archive; +} + // ── Main ────────────────────────────────────────────────────────────────────── export async function setup() { const iecPath = resolve(libsDir, "iec-standard-fb.stlib"); + const additionalFbPath = resolve(libsDir, "additional-function-blocks.stlib"); const oscatPath = resolve(libsDir, "oscat-basic.stlib"); + const stdFnPath = resolve(libsDir, "iec-std-functions.stlib"); - if (!existsSync(iecPath)) { - console.warn("[rebuild-libs] iec-standard-fb.stlib not found — skipping"); - return; - } - - // 0. Refresh dist/ before pulling the compiler from it. Without this - // a src/ edit without a manual `npm run build` would regenerate - // the libs against stale codegen. await refreshAndLoadCompiler(); - // 1. Rebuild IEC standard FB library (no dependencies) + // 1. IEC standard FB library — disk-backed, no inter-lib deps. console.log("[rebuild-libs] Rebuilding iec-standard-fb.stlib..."); - rebuildLibrary(iecPath, {}); + rebuildLibraryFromDisk({ + libDirName: "iec-standard-fb", + stlibPath: iecPath, + orderedSources: [ + "edge_detection.st", + "bistable.st", + "sema.st", + "counter.st", + "timer.st", + ], + }); + + // 2. Additional Function Blocks — disk-backed; PID instantiates + // INTEGRAL/DERIVATIVE intra-library so the file order matters. + if (existsSync(resolve(sourcesRoot, "additional-function-blocks"))) { + console.log("[rebuild-libs] Rebuilding additional-function-blocks.stlib..."); + rebuildLibraryFromDisk({ + libDirName: "additional-function-blocks", + stlibPath: additionalFbPath, + orderedSources: [ + "integral.st", + "derivative.st", + "rtc.st", + "pid.st", + "ramp.st", + "hysteresis.st", + ], + }); + } - // 2. Rebuild OSCAT (depends on IEC standard FB library) - if (existsSync(oscatPath)) { - console.log("[rebuild-libs] Rebuilding oscat-basic.stlib..."); + // 3. OSCAT — codesys-imported from libs/sources/oscat-basic/. The + // canonical source is the bundled .library file (V3 binary); + // rebuild-libs runs the codesys-importer at build time to extract + // ST sources, then compiles them. Depends on iec-standard-fb. + if (existsSync(resolve(sourcesRoot, "oscat-basic"))) { + console.log("[rebuild-libs] Rebuilding oscat-basic.stlib (from codesys)..."); const iecArchive = loadStlibFromFile(iecPath); - rebuildLibrary(oscatPath, { dependencies: [iecArchive] }); + rebuildLibraryFromCodesys({ + libDirName: "oscat-basic", + stlibPath: oscatPath, + dependencies: [iecArchive], + }); + } + + // 4. IEC std functions — synthesized from StdFunctionRegistry. Pure + // metadata: no .st sources, no codegen output. Editor tooling + // consumes the manifest to render ADD/SUB/MUX/SHL/CONCAT/... in + // the same library tree it uses for compiled .stlibs. + if (existsSync(resolve(sourcesRoot, "iec-std-functions"))) { + console.log("[rebuild-libs] Synthesizing iec-std-functions.stlib..."); + synthesizeStdFunctionsLibrary({ + libDirName: "iec-std-functions", + stlibPath: stdFnPath, + }); } - // 3. Copy to VSCode extension bundled-libs if directory exists + // 5. iec-types.json — canonical base-type registry. Pure metadata + // derived from `src/semantic/iec-types-data.ts`; downstream tools + // (OpenPLC Editor's variables table / debugger / XML emitter) + // read this rather than maintaining their own type tables. + console.log("[rebuild-libs] Building iec-types.json..."); + await buildIecTypesJson(); + const iecTypesJsonPath = resolve(libsDir, "iec-types.json"); + + // 6. Copy compiled archives into vscode-extension/bundled-libs/. The + // extension's esbuild bundler also does this at .vsix package time + // — this copy keeps the extension's local development workflow + // (`cd vscode-extension && npx vitest run`) working without an + // extra build step. if (existsSync(vscodeLibsDir)) { copyFileSync(iecPath, resolve(vscodeLibsDir, "iec-standard-fb.stlib")); + if (existsSync(additionalFbPath)) { + copyFileSync( + additionalFbPath, + resolve(vscodeLibsDir, "additional-function-blocks.stlib"), + ); + } if (existsSync(oscatPath)) { copyFileSync(oscatPath, resolve(vscodeLibsDir, "oscat-basic.stlib")); } + if (existsSync(stdFnPath)) { + copyFileSync(stdFnPath, resolve(vscodeLibsDir, "iec-std-functions.stlib")); + } + if (existsSync(iecTypesJsonPath)) { + copyFileSync(iecTypesJsonPath, resolve(vscodeLibsDir, "iec-types.json")); + } } console.log("[rebuild-libs] All libraries rebuilt successfully."); diff --git a/src/backend/codegen.ts b/src/backend/codegen.ts index 9a5f48f..0ed0ec0 100644 --- a/src/backend/codegen.ts +++ b/src/backend/codegen.ts @@ -41,7 +41,17 @@ import type { ConfigurationDecl, ProgramDecl, } from "../project-model.js"; -import { getProjectNamespace, parseTimeLiteral } from "../project-model.js"; +import type { + LibraryChunk, + StlibArchive, +} from "../library/library-manifest.js"; +import { + getProjectNamespace, + parseDateLiteralToNs, + parseDtLiteralToNs, + parseTimeLiteral, + parseTodLiteralToNs, +} from "../project-model.js"; import { TypeRegistry } from "../semantic/type-registry.js"; import { TypeCodeGenerator } from "./type-codegen.js"; import { formatArrayType, iecBaseToCppLiteral } from "./codegen-utils.js"; @@ -54,7 +64,6 @@ import { buildEnumMemberMap, type EnumMemberEntry, } from "../semantic/type-utils.js"; -import type { StlibArchive } from "../library/library-manifest.js"; // ============================================================================= // Located Variable Support @@ -162,6 +171,13 @@ export interface CodeGenOptions { /** Override filename used in #line directives (absolute path for debugger). * Falls back to fileName when not set. */ lineDirectiveFileName?: string; + + /** Emit `//@chunk:begin/end::` comment markers around each + * top-level declaration in both header and cpp output. The library + * compiler uses these to slice emitted code into per-symbol chunks + * for function-level tree-shaking. Off by default — production + * compiles produce identical output regardless. */ + emitChunkMarkers?: boolean; } /** @@ -361,11 +377,18 @@ export class CodeGenerator { /** Topologically sorted function blocks (computed once in generate(), used by header + impl) */ private sortedFBs: CompilationUnit["functionBlocks"] = []; - /** Library preamble code blocks injected into header and implementation */ - private libraryPreambles: Array<{ - name: string; - headerCode: string; - cppCode: string; + /** Per-archive reachable-chunk emission state. + * + * Built by `addLibraryChunks` — one entry per library the consumer + * pulled at least one chunk from. The emission loop iterates this + * in insertion order (= the order index.ts hands archives over, + * which is library load order). For each library, only chunks + * whose name appears in `reachable` are emitted; the array order + * matches the library's `chunks[]` declaration order so symbol + * layout in the user's `generated.hpp` is stable across builds. */ + private libraryEmissions: Array<{ + archive: StlibArchive; + reachable: Set; }> = []; /** Map of UPPER(fbTypeName) → ordered VAR_INPUT parameter names (UPPER case). @@ -708,11 +731,41 @@ export class CodeGenerator { } /** - * Add library preamble code to inject into the generated header and implementation. - * Supports multiple libraries — each is injected in order. + * Hand the codegen a library archive and the set of chunk names + * the consumer determined to be reachable from the user's AST. + * Only those chunks are emitted into the final header/cpp. + * + * Single per-call entry point: nothing else mutates + * `libraryEmissions`. The caller (index.ts) computes the reachable + * set via function-level tree-shake before invoking this method. + */ + addLibraryChunks(archive: StlibArchive, reachable: Set): void { + this.libraryEmissions.push({ archive, reachable }); + } + + /** + * Emit a chunk-boundary marker in the active header stream. No-op + * when `emitChunkMarkers` is off. See `CodeGenOptions.emitChunkMarkers` + * — the markers exist so the library compiler can slice emitted code + * into per-symbol chunks for function-level tree-shaking. */ - addLibraryPreamble(name: string, headerCode: string, cppCode: string): void { - this.libraryPreambles.push({ name, headerCode, cppCode }); + protected emitHeaderChunkMarker( + boundary: "begin" | "end", + kind: "function" | "functionBlock" | "type" | "inlineGlobal", + name: string, + ): void { + if (!this.options.emitChunkMarkers) return; + this.emitHeader(`//@chunk:${boundary}:${kind}:${name}`); + } + + /** Emit a chunk-boundary marker in the active cpp stream. */ + protected emitCppChunkMarker( + boundary: "begin" | "end", + kind: "function" | "functionBlock" | "type" | "inlineGlobal", + name: string, + ): void { + if (!this.options.emitChunkMarkers) return; + this.emit(`//@chunk:${boundary}:${kind}:${name}`); } /** @@ -941,7 +994,21 @@ export class CodeGenerator { } } - // Undefine macros that collide with IEC identifiers (e.g. macOS math.h OVERFLOW) + // Undefine macros that collide with IEC identifiers. + // + // `` (transitively included via `` in iec_std_lib.hpp) + // defines `OVERFLOW` as a legacy SVID numeric-error constant on both + // glibc/macOS and avr-libc. That collides with several OSCAT FB + // struct fields named OVERFLOW, and the preprocessor expansion would + // turn those into integer literals before the C++ parser sees them. + // The architecturally-correct fixes — wrapping in a namespace, + // renaming the IEC identifier — either don't help (macros expand + // before scope resolution) or break IEC FB ABI. The `#undef` has + // zero cost on platforms where the macro isn't defined. + // + // (``'s `SP` macro used to need the same treatment, but + // post the Arduino-glue split no TU that parses `generated.hpp` + // also pulls in ``, so the SP undef was retired.) this.emitHeader(""); this.emitHeader("#undef OVERFLOW"); @@ -974,6 +1041,7 @@ export class CodeGenerator { const typeCodeGen = new TypeCodeGenerator({ indent: this.options.indent, lineEnding: this.options.lineEnding, + emitChunkMarkers: this.options.emitChunkMarkers ?? false, }); const typeCode = typeCodeGen.generateFromRegistry(typeRegistry); for (const line of typeCode.split(this.options.lineEnding)) { @@ -989,6 +1057,7 @@ export class CodeGenerator { for (const decl of block.declarations) { const cppType = this.mapTypeRefToCpp(decl.type); for (const name of decl.names) { + this.emitHeaderChunkMarker("begin", "inlineGlobal", name); if (decl.initialValue) { const initExpr = this.generateExpression(decl.initialValue); this.emitHeader( @@ -997,18 +1066,46 @@ export class CodeGenerator { } else { this.emitHeader(`inline ${cppType} ${name}{};`); } + this.emitHeaderChunkMarker("end", "inlineGlobal", name); } } } this.emitHeader(""); } - // Inject library preambles (stdlib + user libraries) - for (const lib of this.libraryPreambles) { - this.emitHeader(`// Library: ${lib.name}`); - for (const line of lib.headerCode.split("\n")) { - this.emitHeader(line); + // Inject reachable library chunks (header side). + // + // Per archive: emit `// Library: ` header, then `class X;` + // forward decls for every reachable functionBlock chunk + // (libraries' FB classes are sometimes mutually-referential and + // the bodies are emitted in declaration order — the forward + // decls ahead of any body keep the layout linkable in every + // ordering). Then emit each reachable chunk's `header` slice in + // chunk-array order; types come first, FBs next, functions last + // because that's the order the library compiler emitted them + // before slicing. + for (const { archive, reachable } of this.libraryEmissions) { + const reachableChunks: LibraryChunk[] = []; + for (const chunk of archive.chunks ?? []) { + if (chunk.header.length === 0) continue; + if (reachable.has(chunk.name)) reachableChunks.push(chunk); + } + if (reachableChunks.length === 0) continue; + + this.emitHeader(`// Library: ${archive.manifest.name}`); + + for (const chunk of reachableChunks) { + if (chunk.kind === "functionBlock") { + this.emitHeader(`class ${chunk.name};`); + } + } + + for (const chunk of reachableChunks) { + for (const line of chunk.header.split("\n")) { + this.emitHeader(line); + } } + this.emitHeader(""); } @@ -1036,30 +1133,56 @@ export class CodeGenerator { // Generate interface declarations (before FBs since FBs may implement interfaces) for (const iface of ast.interfaces) { + this.emitHeaderChunkMarker("begin", "type", iface.name); this.generateInterfaceHeaderDeclaration(iface); + this.emitHeaderChunkMarker("end", "type", iface.name); } // Generate function block class declarations (topologically sorted by dependency) for (const fb of this.sortedFBs) { + this.emitHeaderChunkMarker("begin", "functionBlock", fb.name); this.generateFBHeaderDeclaration(fb); + this.emitHeaderChunkMarker("end", "functionBlock", fb.name); } // Generate program class declarations if (this.projectModel) { // Use project model for enhanced generation with VAR_EXTERNAL support for (const prog of this.projectModel.programs.values()) { + this.emitHeaderChunkMarker( + "begin", + "functionBlock", + `Program_${prog.name}`, + ); this.generateProgramHeaderFromModel(prog); + this.emitHeaderChunkMarker( + "end", + "functionBlock", + `Program_${prog.name}`, + ); } } else { // Fallback to AST-based generation for (const prog of ast.programs) { + this.emitHeaderChunkMarker( + "begin", + "functionBlock", + `Program_${prog.name}`, + ); this.generateProgramHeaderDeclaration(prog); + this.emitHeaderChunkMarker( + "end", + "functionBlock", + `Program_${prog.name}`, + ); } } // Generate function declarations for (const func of ast.functions) { + this.emitHeaderChunkMarker("begin", "function", func.name); this.generateFunctionHeaderDeclaration(func); + this.emitHeaderChunkMarker("end", "function", func.name); } // Generate configuration class declarations @@ -1103,10 +1226,23 @@ export class CodeGenerator { // definition of …"). this.startTranslationUnit("configuration.cpp"); - for (const lib of this.libraryPreambles) { - this.emit(`// Library: ${lib.name}`); - for (const line of lib.cppCode.split("\n")) { - this.emit(line); + // Inject reachable library chunks (cpp side). Same per-archive + // iteration order as the header side; only chunks whose `cpp` + // slice is non-empty get emitted (types and inline globals are + // header-only). + for (const { archive, reachable } of this.libraryEmissions) { + const reachableChunks: LibraryChunk[] = []; + for (const chunk of archive.chunks ?? []) { + if (chunk.cpp.length === 0) continue; + if (reachable.has(chunk.name)) reachableChunks.push(chunk); + } + if (reachableChunks.length === 0) continue; + + this.emit(`// Library: ${archive.manifest.name}`); + for (const chunk of reachableChunks) { + for (const line of chunk.cpp.split("\n")) { + this.emit(line); + } } this.emit(""); } @@ -1129,13 +1265,25 @@ export class CodeGenerator { if (this.projectModel) { for (const prog of this.projectModel.programs.values()) { this.startTranslationUnit(this.pouFileName(prog.name)); + this.emitCppChunkMarker( + "begin", + "functionBlock", + `Program_${prog.name}`, + ); this.generateProgramImplementationFromModel(prog); + this.emitCppChunkMarker("end", "functionBlock", `Program_${prog.name}`); this.endTranslationUnit(); } } else { for (const prog of ast.programs) { this.startTranslationUnit(this.pouFileName(prog.name)); + this.emitCppChunkMarker( + "begin", + "functionBlock", + `Program_${prog.name}`, + ); this.generateProgramImplementation(prog); + this.emitCppChunkMarker("end", "functionBlock", `Program_${prog.name}`); this.endTranslationUnit(); } } @@ -1145,14 +1293,18 @@ export class CodeGenerator { // class declarations); ordering only mattered for the header. for (const fb of this.sortedFBs) { this.startTranslationUnit(this.pouFileName(fb.name)); + this.emitCppChunkMarker("begin", "functionBlock", fb.name); this.generateFBImplementation(fb); + this.emitCppChunkMarker("end", "functionBlock", fb.name); this.endTranslationUnit(); } // 4. One TU per function. for (const func of ast.functions) { this.startTranslationUnit(this.pouFileName(func.name)); + this.emitCppChunkMarker("begin", "function", func.name); this.generateFunctionImplementation(func); + this.emitCppChunkMarker("end", "function", func.name); this.endTranslationUnit(); } } @@ -3051,18 +3203,27 @@ export class CodeGenerator { return `"${escaped}"`; } case "WSTRING": { - const wInner = expr.rawValue.replace(/^'|'$/g, ""); + // IEC WSTRING literals are double-quoted in source; strip either + // form for safety. The C++ prefix is `u` (char16_t), not `L` + // (wchar_t — wchar_t is 32-bit on Linux/AVR, so L"…" wouldn't + // bind to IECWStringVar's char16_t* constructor). + const wInner = expr.rawValue.replace(/^["']|["']$/g, ""); const wEscaped = this.translateIECString(wInner); - return `L"${wEscaped}"`; + return `u"${wEscaped}"`; } case "TIME": { const timeVal = parseTimeLiteral(String(expr.value)); return `${timeVal.nanoseconds}LL`; } case "DATE": + // DATE: int64 nanoseconds since Unix epoch (UTC), time-of-day 0. + return `${parseDateLiteralToNs(String(expr.value))}LL`; case "TIME_OF_DAY": + // TOD: int64 nanoseconds since midnight. + return `${parseTodLiteralToNs(String(expr.value))}LL`; case "DATE_AND_TIME": - return String(expr.value); + // DT: int64 nanoseconds since Unix epoch (UTC). + return `${parseDtLiteralToNs(String(expr.value))}LL`; case "NULL": return "IEC_NULL"; default: @@ -3535,10 +3696,21 @@ export class CodeGenerator { } // Fallback to ad-hoc inference for standalone codegen (tests without semantic analysis) switch (expr.kind) { - case "VariableExpression": - return this.currentScopeVarTypes - .get(expr.name.toUpperCase()) - ?.toUpperCase(); + case "VariableExpression": { + // Walk `fieldAccess` so `FB_INSTANCE.OUTPUT` resolves to the + // output's element type rather than the FB's type — without + // this, type-driven literal casts (see `harmonizeStdFuncArgs`) + // would synthesise `static_cast>(literal)`, and + // `IEC_` aliases don't exist (only types emit them). + let type = this.currentScopeVarTypes.get(expr.name.toUpperCase()); + if (!type) return undefined; + for (const field of expr.fieldAccess ?? []) { + const next = this.resolveMemberType(type, field); + if (!next) return undefined; + type = next; + } + return type.toUpperCase(); + } case "LiteralExpression": { if (expr.typePrefix) return expr.typePrefix.toUpperCase(); // Map literal types to IEC names @@ -3753,10 +3925,15 @@ export class CodeGenerator { // Cast literals to dominant type. // Bare literals (no typePrefix) are untyped — castable to dominant unless - // this would narrow a REAL/LREAL literal to an integer type (losing precision). + // this would narrow a REAL/LREAL literal to an integer type (losing + // precision). When the call also carries a variable argument we must + // ALWAYS wrap bare literals: the variable side is an `IECVar` but a + // bare literal lowers to a raw `int`/`double`, so C++ template deduction + // sees conflicting `T`s (`IECVar` vs `int`) even when both share + // the same IEC type name on our side. for (const i of literalIndices) { const litType = argTypes[i]; - if (!litType || litType === dominant) continue; + if (!litType) continue; const expr = argExprs[i]!.value; const litCat = getTypeCategory(litType); const domCat = getTypeCategory(dominant); @@ -3764,6 +3941,14 @@ export class CodeGenerator { if (litCat === "REAL" && domCat !== "REAL" && this.isBareLiteral(expr)) { continue; } + // Bare literal paired with at least one IEC variable: cast even when + // the inferred IEC type matches `dominant`, to lift raw C++ literals + // into the IECVar<> template space. + if (this.isBareLiteral(expr) && varTypes.length > 0) { + args[i] = `static_cast(${args[i]})`; + continue; + } + if (litType === dominant) continue; if ( this.isBareLiteral(expr) || this.canImplicitWiden(litType, dominant) @@ -4697,19 +4882,33 @@ export class CodeGenerator { // Convert IEC BOOL literals to C++ bool literals if (upperInit === "TRUE") return "true"; if (upperInit === "FALSE") return "false"; - // Convert IEC string literals ('hello') to C++ string literals ("hello") + // Convert IEC string literals to the matching C++ literal shape: + // 'foo' (STRING) → "foo" (const char*) + // "foo" (WSTRING) → u"foo" (const char16_t*, what IECWStringVar + // binds to — `L"…"` is wchar_t and + // 32-bit on Linux/AVR, wrong type) + // The two literal kinds are NOT interchangeable per IEC 61131-3; + // a mismatch (e.g. WSTRING := 'foo') is a type error and is the + // type-checker's responsibility, not codegen's. Codegen just + // mirrors the literal it was handed. if (initialValue.startsWith("'") && initialValue.endsWith("'")) { const inner = initialValue.slice(1, -1); const escaped = this.translateIECString(inner); return `"${escaped}"`; } + if (initialValue.startsWith('"') && initialValue.endsWith('"')) { + const inner = initialValue.slice(1, -1); + const escaped = this.translateIECString(inner); + return `u"${escaped}"`; + } return initialValue; } const upperType = typeName.toUpperCase(); if (upperType === "BOOL") return "false"; if (upperType === "REAL" || upperType === "LREAL") return "0.0"; - if (upperType === "STRING" || upperType === "WSTRING") return '""'; + if (upperType === "STRING") return '""'; + if (upperType === "WSTRING") return 'u""'; // Check if it's an elementary type that uses numeric default const numericTypes = [ diff --git a/src/backend/type-codegen.ts b/src/backend/type-codegen.ts index 3669666..688cdc7 100644 --- a/src/backend/type-codegen.ts +++ b/src/backend/type-codegen.ts @@ -22,7 +22,12 @@ import type { } from "../frontend/ast.js"; import { TypeRegistry, isElementaryType } from "../semantic/type-registry.js"; import { formatArrayType } from "./codegen-utils.js"; -import { parseTimeLiteral } from "../project-model.js"; +import { + parseDateLiteralToNs, + parseDtLiteralToNs, + parseTimeLiteral, + parseTodLiteralToNs, +} from "../project-model.js"; import { buildEnumMemberMap, type EnumMemberEntry, @@ -34,6 +39,11 @@ import { export interface TypeCodeGenOptions { indent: string; lineEnding: string; + /** Wrap each generated type's emission with `//@chunk:begin/end:type:` + * marker comments. Off by default; the library compiler enables it so + * it can slice per-symbol chunks for tree-shaking. See + * `CodeGenOptions.emitChunkMarkers`. */ + emitChunkMarkers: boolean; } /** @@ -42,6 +52,7 @@ export interface TypeCodeGenOptions { export const defaultTypeCodeGenOptions: TypeCodeGenOptions = { indent: " ", lineEnding: "\n", + emitChunkMarkers: false, }; /** @@ -166,7 +177,13 @@ export class TypeCodeGenerator { this.emit(""); for (const type of types) { + if (this.options.emitChunkMarkers) { + this.emit(`//@chunk:begin:type:${type.name}`); + } this.generateTypeDeclaration(type); + if (this.options.emitChunkMarkers) { + this.emit(`//@chunk:end:type:${type.name}`); + } } return this.output.join(this.options.lineEnding); @@ -521,14 +538,31 @@ export class TypeCodeGenerator { switch (expr.literalType) { case "BOOL": return expr.value === true ? "true" : "false"; - case "STRING": - return `"${expr.rawValue}"`; - case "WSTRING": - return `L"${expr.rawValue}"`; + case "STRING": { + // IEC STRING literals carry their surrounding single quotes + // in `rawValue` (`'wide hello'`); strip them before wrapping + // in C++ double quotes — otherwise we end up with `"'…'"`. + const inner = expr.rawValue.replace(/^'|'$/g, ""); + return `"${inner}"`; + } + case "WSTRING": { + // IEC WSTRING literals are double-quoted; strip either form + // for safety. The C++ prefix is `u` (char16_t) — `L"…"` + // (wchar_t) is 32-bit on Linux/AVR and wouldn't bind to + // IECWStringVar's char16_t* ctor. + const inner = expr.rawValue.replace(/^["']|["']$/g, ""); + return `u"${inner}"`; + } case "TIME": { const timeVal = parseTimeLiteral(String(expr.value)); return `${timeVal.nanoseconds}LL`; } + case "DATE": + return `${parseDateLiteralToNs(String(expr.value))}LL`; + case "TIME_OF_DAY": + return `${parseTodLiteralToNs(String(expr.value))}LL`; + case "DATE_AND_TIME": + return `${parseDtLiteralToNs(String(expr.value))}LL`; default: return String(expr.value); } diff --git a/src/cli.ts b/src/cli.ts index 4f90d72..b421823 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -37,7 +37,7 @@ import { existsSync, statSync, } from "fs"; -import { resolve, basename, dirname, join } from "path"; +import { resolve, basename, dirname, join, relative, sep } from "path"; import { tmpdir, platform } from "os"; import { execFileSync } from "child_process"; import { compile, getVersion, compileStlib } from "./index.js"; @@ -474,8 +474,13 @@ function compileLibraryMode(options: CLIOptions): void { const libNamespace = options.libNamespace ?? options.libName.replace(/[^a-zA-Z0-9_]/g, "_"); - // Collect input files — if an input is a directory, discover .st files recursively - const filePaths: string[] = []; + // Collect input files — if an input is a directory, discover .st files + // recursively. Each entry remembers its discovery root so we can later + // derive a category from the path relative to that root: a file at + // `/some_category/foo.st` ends up tagged `some_category` in the + // manifest. Files passed directly (not via a directory) carry no + // category — they're treated as flat root-level inputs. + const filePaths: Array<{ path: string; rootDir?: string }> = []; for (const input of options.inputs) { const inputPath = resolve(input); try { @@ -488,9 +493,10 @@ function compileLibraryMode(options: CLIOptions): void { ); process.exit(1); } - filePaths.push(...discovered); + for (const p of discovered) + filePaths.push({ path: p, rootDir: inputPath }); } else { - filePaths.push(inputPath); + filePaths.push({ path: inputPath }); } } catch { console.error(`Error: Cannot read input: ${inputPath}`); @@ -499,13 +505,25 @@ function compileLibraryMode(options: CLIOptions): void { } // Read all source files - const sources: Array<{ source: string; fileName: string }> = []; - for (const filePath of filePaths) { + const sources: Array<{ + source: string; + fileName: string; + category?: string; + }> = []; + for (const { path: filePath, rootDir } of filePaths) { try { - sources.push({ + const entry: { source: string; fileName: string; category?: string } = { source: readFileSync(filePath, "utf-8"), fileName: basename(filePath), - }); + }; + if (rootDir) { + const rel = relative(rootDir, filePath); + const parts = rel.split(sep); + if (parts.length > 1) { + entry.category = parts.slice(0, -1).join("/"); + } + } + sources.push(entry); } catch { console.error(`Error: Cannot read input file: ${filePath}`); process.exit(1); @@ -789,6 +807,12 @@ function runTestMode(options: CLIOptions): void { /** * Decompile mode: extract ST source files from a .stlib archive. + * + * If the archive carries `category` metadata on its source entries, each + * file is written under that subfolder (`outputDir//`), + * recreating the folder hierarchy the library was compiled from. + * Categoryless entries land at the output root, so flat archives extract + * exactly the same way they did before hierarchy support was added. */ function decompileLibMode(options: CLIOptions): void { let archive: import("./library/library-manifest.js").StlibArchive; @@ -810,7 +834,13 @@ function decompileLibMode(options: CLIOptions): void { mkdirSync(outputDir, { recursive: true }); for (const src of archive.sources) { - const outPath = join(outputDir, src.fileName); + // Normalize forward-slash category paths to platform separators and + // ensure the destination folder exists before writing. + const subdir = src.category + ? join(outputDir, ...src.category.split("/")) + : outputDir; + mkdirSync(subdir, { recursive: true }); + const outPath = join(subdir, src.fileName); writeFileSync(outPath, src.source, "utf-8"); console.log(` ${outPath}`); } diff --git a/src/diagnostic-formatter.ts b/src/diagnostic-formatter.ts index 4966617..67f3cec 100644 --- a/src/diagnostic-formatter.ts +++ b/src/diagnostic-formatter.ts @@ -98,6 +98,28 @@ function getSourceLine(source: string, line: number): string | undefined { return lines[line - 1]; } +/** + * Options for {@link formatDiagnostic}. All fields are optional; the + * default rendering matches the long-standing CLI / vscode-extension + * behaviour — programmatic consumers opt in to the newer behaviours. + */ +export interface FormatDiagnosticOptions { + /** + * When `true`, body-attributed diagnostics (`error.section === 'body'` + * with `error.bodyLine` set) are rendered with the body-relative + * line number in both the header column and the snippet gutter, + * matching what an editor like the OpenPLC Editor shows in its + * Monaco body view. The source content is still read from the + * raw `error.line` in the per-POU file under the hood; only the + * displayed numbers change. + * + * Default: `false` (preserves the absolute file line in every + * field — this is what `strucpp` CLI users and the vscode + * extension see today). + */ + preferBodyLine?: boolean; +} + /** * Format a single diagnostic in gcc style. Returns a multi-line string with * no trailing newline. @@ -105,12 +127,25 @@ function getSourceLine(source: string, line: number): string | undefined { export function formatDiagnostic( error: CompileError, sourceMap: Map, + options?: FormatDiagnosticOptions, ): string { const palette = getPalette(); const sevColor = severityColor(error.severity, palette); const fileLabel = error.file ?? ""; + + // Body-relative numbering is opt-in: CLI and vscode users keep the + // absolute (file, line) reporting they've always had; programmatic + // consumers like the OpenPLC Editor pass `preferBodyLine: true` to + // get numbers that match their Monaco body view. + const displayLine = + options?.preferBodyLine === true && + error.section === "body" && + error.bodyLine !== undefined + ? error.bodyLine + : error.line; + const header = - `${palette.bold}${fileLabel}:${error.line}:${error.column}:${palette.reset} ` + + `${palette.bold}${fileLabel}:${displayLine}:${error.column}:${palette.reset} ` + `${sevColor}${palette.bold}${error.severity}:${palette.reset} ` + `${error.message}` + (error.code ? ` [${error.code}]` : ""); @@ -125,7 +160,7 @@ export function formatDiagnostic( // Render gutter with the line number right-aligned to a 4-space minimum, // matching gcc's typical output width. - const lineNumStr = String(error.line); + const lineNumStr = String(displayLine); const gutterWidth = Math.max(lineNumStr.length, 4); const lineGutter = `${palette.cyan}${lineNumStr.padStart(gutterWidth)} | ${palette.reset}`; const blankGutter = `${palette.cyan}${" ".repeat(gutterWidth)} | ${palette.reset}`; diff --git a/src/diagnostic-pou-context.ts b/src/diagnostic-pou-context.ts new file mode 100644 index 0000000..768dc1a --- /dev/null +++ b/src/diagnostic-pou-context.ts @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (C) 2025 Autonomy / OpenPLC Project +/** + * Diagnostic POU context — annotate `CompileError` records with the + * POU + section that contains them, plus a body-relative line number + * for body errors. + * + * Why a post-pass instead of populating the fields where each error is + * created: errors are emitted from many places (parser, AST builder, + * project model, semantic analyzer, codegen) and they all already carry + * `(line, column, file)`. A single post-pass walks the AST once, + * builds an interval table per `(file, line)`, and decorates every + * collected error in O(errors × log POUs) — much cheaper than threading + * POU/section state through every diagnostic site. + * + * Standalone CLI use of strucpp doesn't read these fields; they're only + * surfaced through the programmatic API to consumers like the OpenPLC + * Editor that need to remap from "line in monolithic program.st" to + * "line in the user's POU body view". + */ + +import type { + CompilationUnit, + ProgramDeclaration, + FunctionDeclaration, + FunctionBlockDeclaration, + MethodDeclaration, + VarBlock, + Statement, +} from "./frontend/ast.js"; +import type { CompileError } from "./types.js"; + +interface PouSectionRange { + pouName: string; + pouKind: "PROGRAM" | "FUNCTION" | "FUNCTION_BLOCK"; + /** Source file the POU was parsed from. */ + file: string; + /** Start line of the POU declaration (the `PROGRAM`/`FUNCTION`/ + * `FUNCTION_BLOCK` keyword line). */ + pouStartLine: number; + /** End line of the POU declaration (the matching `END_*` line). */ + pouEndLine: number; + /** Spans of every VAR…END_VAR block inside this POU. Multiple + * ranges because IEC allows VAR_INPUT/VAR_OUTPUT/VAR_TEMP/etc. as + * separate blocks. */ + varBlockSpans: Array<{ start: number; end: number }>; + /** Per-declaration spans inside the var blocks, paired with the + * declaration's first variable name — used to back-fill + * `variableName` on errors anchored at a declaration line. */ + varDeclarations: Array<{ start: number; end: number; name: string }>; + /** Span of the executable body (min/max statement line). Undefined + * for empty bodies. */ + bodySpan?: { start: number; end: number }; +} + +/** + * Build the per-POU section table for a compilation unit. Walks every + * top-level POU plus every method body inside a function block. + */ +function buildPouRanges(ast: CompilationUnit): PouSectionRange[] { + const out: PouSectionRange[] = []; + + for (const prog of ast.programs) { + out.push(rangeFromPou(prog, "PROGRAM")); + } + for (const fn of ast.functions) { + out.push(rangeFromPou(fn, "FUNCTION")); + } + for (const fb of ast.functionBlocks) { + out.push(rangeFromPou(fb, "FUNCTION_BLOCK")); + // Methods are addressable as POU bodies in their own right — surface + // them under the parent FB's name with kind FUNCTION_BLOCK so the + // editor opens the right tab. (Method-level addressing would need + // a separate mechanism that the editor doesn't currently expose.) + for (const m of fb.methods) { + out.push(rangeFromMethod(fb, m)); + } + } + + return out; +} + +function rangeFromPou( + pou: ProgramDeclaration | FunctionDeclaration | FunctionBlockDeclaration, + kind: "PROGRAM" | "FUNCTION" | "FUNCTION_BLOCK", +): PouSectionRange { + const bodySpan = spanOfStatements(pou.body); + return { + pouName: pou.name, + pouKind: kind, + file: pou.sourceSpan.file, + pouStartLine: pou.sourceSpan.startLine, + pouEndLine: pou.sourceSpan.endLine, + varBlockSpans: pou.varBlocks.map(spanOfBlock), + varDeclarations: collectVarDeclarations(pou.varBlocks), + ...(bodySpan ? { bodySpan } : {}), + }; +} + +function rangeFromMethod( + fb: FunctionBlockDeclaration, + method: MethodDeclaration, +): PouSectionRange { + const bodySpan = spanOfStatements(method.body); + return { + pouName: fb.name, + pouKind: "FUNCTION_BLOCK", + file: method.sourceSpan.file, + pouStartLine: method.sourceSpan.startLine, + pouEndLine: method.sourceSpan.endLine, + varBlockSpans: method.varBlocks.map(spanOfBlock), + varDeclarations: collectVarDeclarations(method.varBlocks), + ...(bodySpan ? { bodySpan } : {}), + }; +} + +function spanOfBlock(block: VarBlock): { start: number; end: number } { + return { start: block.sourceSpan.startLine, end: block.sourceSpan.endLine }; +} + +function collectVarDeclarations( + blocks: VarBlock[], +): Array<{ start: number; end: number; name: string }> { + const out: Array<{ start: number; end: number; name: string }> = []; + for (const block of blocks) { + for (const decl of block.declarations) { + // A single VAR statement can declare multiple names + // (`a, b, c : INT;`); attribute the diagnostic to the first one + // — that's what the type-checker's synthetic anchor uses too. + const name = decl.names[0]; + if (!name) continue; + out.push({ + start: decl.sourceSpan.startLine, + end: decl.sourceSpan.endLine, + name, + }); + } + } + return out; +} + +function spanOfStatements( + body: Statement[], +): { start: number; end: number } | undefined { + if (body.length === 0) return undefined; + let start = Infinity; + let end = -Infinity; + for (const s of body) { + if (s.sourceSpan.startLine < start) start = s.sourceSpan.startLine; + if (s.sourceSpan.endLine > end) end = s.sourceSpan.endLine; + } + return { start, end }; +} + +function lineInside( + line: number, + span: { start: number; end: number }, +): boolean { + return line >= span.start && line <= span.end; +} + +/** + * Mutate `errors` in place, populating `pouName` / `pouKind` / + * `section` / `bodyLine` on every record that maps into one of the + * POU ranges built from `ast`. Errors with no `line` (or `line === 0`, + * which we use as a sentinel for diagnostics not tied to a source + * location) are left untouched. + * + * Errors whose `file` doesn't match any POU's source file (e.g. the + * synthetic `_types.st` / `_config.st` chunks the editor splits out) + * also fall through unchanged — those map to non-POU sections in the + * editor and don't need POU-relative location. + */ +export function annotateErrorsWithPouContext( + errors: CompileError[], + ast: CompilationUnit, +): void { + if (errors.length === 0) return; + const ranges = buildPouRanges(ast); + if (ranges.length === 0) return; + + for (const err of errors) { + if (err.line <= 0) continue; + const fileMatch = err.file ?? ""; + // Find the POU whose declaration span covers this line. When + // multiple POUs share a file (the typical multi-POU program.st + // case) we pick the first whose span includes the line. Method + // ranges deliberately come after the parent FB in `ranges`, but + // method spans are tighter — we match the tightest by preferring + // the smallest enclosing range. + let best: PouSectionRange | undefined; + let bestSize = Infinity; + for (const r of ranges) { + if (r.file !== fileMatch) continue; + if (err.line < r.pouStartLine || err.line > r.pouEndLine) continue; + const size = r.pouEndLine - r.pouStartLine; + if (size < bestSize) { + best = r; + bestSize = size; + } + } + if (!best) continue; + + err.pouName = best.pouName; + err.pouKind = best.pouKind; + + // Section detection — var-block spans win over body span when + // they overlap (var blocks always precede the body in IEC). + const inVarBlock = best.varBlockSpans.some((s) => lineInside(err.line, s)); + if (inVarBlock) { + err.section = "var-block"; + // The editor uses `line` directly for var-block errors — the + // var block sits at the top of the per-POU .st file, so file + // line and Monaco vars-text line align. + const decl = best.varDeclarations.find((d) => lineInside(err.line, d)); + if (decl) err.variableName = decl.name; + continue; + } + + if (best.bodySpan && lineInside(err.line, best.bodySpan)) { + err.section = "body"; + err.bodyLine = err.line - best.bodySpan.start + 1; + continue; + } + + err.section = "interface"; + } +} diff --git a/src/frontend/ast-builder.ts b/src/frontend/ast-builder.ts index d1ea74e..f662619 100644 --- a/src/frontend/ast-builder.ts +++ b/src/frontend/ast-builder.ts @@ -2582,6 +2582,17 @@ export class ASTBuilder { }; } + if (children.WideStringLiteral) { + const token = getFirstToken(children.WideStringLiteral)!; + return { + kind: "LiteralExpression", + sourceSpan: tokenToSourceSpan(token), + literalType: "WSTRING", + value: token.image, + rawValue: token.image, + }; + } + if (children.TimeLiteral) { const token = getFirstToken(children.TimeLiteral)!; return { @@ -2593,6 +2604,39 @@ export class ASTBuilder { }; } + if (children.DateLiteral) { + const token = getFirstToken(children.DateLiteral)!; + return { + kind: "LiteralExpression", + sourceSpan: tokenToSourceSpan(token), + literalType: "DATE", + value: token.image, + rawValue: token.image, + }; + } + + if (children.TimeOfDayLiteral) { + const token = getFirstToken(children.TimeOfDayLiteral)!; + return { + kind: "LiteralExpression", + sourceSpan: tokenToSourceSpan(token), + literalType: "TIME_OF_DAY", + value: token.image, + rawValue: token.image, + }; + } + + if (children.DateTimeLiteral) { + const token = getFirstToken(children.DateTimeLiteral)!; + return { + kind: "LiteralExpression", + sourceSpan: tokenToSourceSpan(token), + literalType: "DATE_AND_TIME", + value: token.image, + rawValue: token.image, + }; + } + if (children.NULL) { const token = getFirstToken(children.NULL)!; return { diff --git a/src/index.ts b/src/index.ts index b3b8f73..3d8fa49 100644 --- a/src/index.ts +++ b/src/index.ts @@ -44,6 +44,7 @@ import { LibraryManifestError, } from "./library/library-loader.js"; import type { StlibArchive } from "./library/library-manifest.js"; +import { annotateErrorsWithPouContext } from "./diagnostic-pou-context.js"; /** * Default compilation options @@ -82,33 +83,63 @@ function validateCompileOptions(options: CompileOptions): void { // --------------------------------------------------------------------------- /** - * Determine which libraries are actually used by the user program. - * Walks the AST to collect all referenced symbol names, then matches them - * against library manifests to find which libraries are needed. - * Includes transitive dependencies. + * Function-level tree-shake: determine which library chunks are + * reachable from the user's AST and need to be emitted into the + * final `generated.hpp` / `generated.cpp`. + * + * Walks every kind of cross-symbol reference the codegen relies on + * (function calls, variable & inline-global reads, type references, + * FB inheritance / interface implements), maps each name through a + * symbol→chunk index built across all archives, then BFS-traverses + * the chunk dep graph baked into each archive at library compile + * time. + * + * Returns a `Map>` describing the + * reachable subset of each archive. Archives whose entry is empty + * (or absent) contribute nothing to the user's output. + * + * Test builds bypass the shake: every chunk of every archive is + * declared reachable so the test harness sees the full symbol set + * regardless of what the source AST happens to reference. */ -function collectUsedLibraries( +function collectUsedSymbols( ast: CompilationUnit, archives: StlibArchive[], -): Set { - // Build symbol→library name map (uppercase keys for case-insensitive match) - const symbolToLib = new Map(); + includeEverything: boolean, +): Map> { + // When asked to include everything (test builds), short-circuit. + if (includeEverything) { + const all = new Map>(); + for (const archive of archives) { + const chunkNames = new Set(); + for (const chunk of archive.chunks ?? []) { + chunkNames.add(chunk.name); + } + all.set(archive.manifest.name, chunkNames); + } + return all; + } + + // Build symbol→{library, chunk} index across every archive. Names + // are uppercased to match how chunks are keyed (the codegen + // normalises every emitted identifier to uppercase before sealing + // chunk boundaries). + const symbolIndex = new Map(); + // Per-library chunk-name lookup so the dep BFS can resolve chunks + // it already named when the consumer didn't reference them directly. + const chunkByKey = new Map(); + for (const archive of archives) { const libName = archive.manifest.name; - for (const fn of archive.manifest.functions) { - symbolToLib.set(fn.name.toUpperCase(), libName); - } - for (const fb of archive.manifest.functionBlocks) { - symbolToLib.set(fb.name.toUpperCase(), libName); - } - for (const t of archive.manifest.types) { - symbolToLib.set(t.name.toUpperCase(), libName); + for (const chunk of archive.chunks ?? []) { + const entry = { library: libName, chunk: chunk.name }; + symbolIndex.set(chunk.name.toUpperCase(), entry); + chunkByKey.set(`${libName}:${chunk.name}`, entry); } } - // Collect all symbol names referenced in the AST + // Seed the reachable set from names the user AST references. const referencedNames = new Set(); - walkAST(ast, (node: ASTNode): void => { switch (node.kind) { case "FunctionCallExpression": { @@ -116,6 +147,13 @@ function collectUsedLibraries( referencedNames.add(fc.functionName.toUpperCase()); break; } + case "VariableExpression": { + // Inline-global reads (e.g. `MATH.PI2`) show up as + // VariableExpression with name="MATH". + const ve = node as unknown as { name: string }; + referencedNames.add(ve.name.toUpperCase()); + break; + } case "TypeReference": { const tr = node as TypeReference; referencedNames.add(tr.name.toUpperCase()); @@ -146,39 +184,68 @@ function collectUsedLibraries( } }); - // Match referenced names to libraries - const usedLibs = new Set(); + // BFS through the chunk dep graph. + const reachable = new Set(); // keys: ":" + const queue: Array<{ library: string; chunk: string }> = []; + for (const name of referencedNames) { - const lib = symbolToLib.get(name); - if (lib) usedLibs.add(lib); + const entry = symbolIndex.get(name); + if (entry) { + const key = `${entry.library}:${entry.chunk}`; + if (!reachable.has(key)) { + reachable.add(key); + queue.push(entry); + } + } } - // Add transitive dependencies - const depMap = new Map(); + // Build a fast lookup from ":" → chunk object so + // the BFS can read each chunk's pre-computed deps without rescanning. + const chunkLookup = new Map< + string, + { + archive: StlibArchive; + chunk: NonNullable[number]; + } + >(); for (const archive of archives) { - depMap.set( - archive.manifest.name, - archive.dependencies.map((d) => d.name), - ); + for (const chunk of archive.chunks ?? []) { + chunkLookup.set(`${archive.manifest.name}:${chunk.name}`, { + archive, + chunk, + }); + } } - let changed = true; - while (changed) { - changed = false; - for (const lib of usedLibs) { - const deps = depMap.get(lib); - if (deps) { - for (const dep of deps) { - if (!usedLibs.has(dep)) { - usedLibs.add(dep); - changed = true; - } - } - } + while (queue.length > 0) { + const cur = queue.shift()!; + const lookup = chunkLookup.get(`${cur.library}:${cur.chunk}`); + if (!lookup) continue; + for (const dep of lookup.chunk.deps) { + const depKey = `${dep.library}:${dep.name}`; + if (reachable.has(depKey)) continue; + const target = chunkByKey.get(depKey); + if (!target) continue; + reachable.add(depKey); + queue.push(target); + } + } + + // Group reachable chunks by library. + const byLibrary = new Map>(); + for (const key of reachable) { + const sepIdx = key.indexOf(":"); + const lib = key.slice(0, sepIdx); + const name = key.slice(sepIdx + 1); + let set = byLibrary.get(lib); + if (!set) { + set = new Set(); + byLibrary.set(lib, set); } + set.add(name); } - return usedLibs; + return byLibrary; } // --------------------------------------------------------------------------- @@ -307,10 +374,38 @@ function runPipeline( ); const units: CompilationUnit[] = [primaryAst]; - // Parse additional source files + // Parse additional source files. Each gets the same Phase 0 + // IL→ST transpilation as the primary source — without it, an IL + // POU surfaced through `additionalSources` (e.g. the editor's + // per-POU split of program.st) would reach the ST parser as + // raw IL and fail with a confusing "expecting Identifier but + // found 'LD'" error. if (mergedOptions.additionalSources) { for (const addlSource of mergedOptions.additionalSources) { - const addlParseResult = parseSource(addlSource.source); + let effectiveAddlSource = addlSource.source; + const addlIlResult = transpileILSource( + addlSource.source, + addlSource.fileName, + ); + if (addlIlResult.hasIL) { + effectiveAddlSource = addlIlResult.stSource; + for (const err of addlIlResult.errors) { + const entry: CompileError = { + message: err.message, + line: err.line, + column: err.column, + severity: err.severity, + }; + if (err.file) entry.file = err.file; + else entry.file = addlSource.fileName; + errors.push(entry); + } + if (errors.length > 0 && !continueOnError) { + continue; + } + } + + const addlParseResult = parseSource(effectiveAddlSource); if (addlParseResult.errors.length > 0) { for (const err of addlParseResult.errors) { const errObj = err as { @@ -567,6 +662,16 @@ function runPipeline( // In analyze mode, semantic failure is non-fatal — return whatever we have } + // Annotate errors/warnings with POU + section context so programmatic + // consumers (e.g. the OpenPLC Editor) can route diagnostics to the + // right POU tab and remap body-line numbers to the user's view. + // Skipped silently when no AST is available — the fields remain unset + // and downstream code falls back to plain (file, line) display. + if (ast) { + annotateErrorsWithPouContext(errors, ast); + annotateErrorsWithPouContext(warnings, ast); + } + return { ast, projectModel, @@ -648,32 +753,31 @@ export function compile( pouIncludes: pipeline.mergedOptions.pouIncludes ?? [], isTestBuild: pipeline.mergedOptions.isTestBuild ?? false, globalConstants: pipeline.mergedOptions.globalConstants ?? {}, + ...(pipeline.mergedOptions.emitChunkMarkers + ? { emitChunkMarkers: true } + : {}), }); codegen.setProjectModel(pipeline.projectModel!); // Register all library metadata (FB types, field mappings, enum/struct types) codegen.registerLibraryArchives(pipeline.allArchives); - // Tree-shake: only include libraries whose symbols are referenced by the - // program. Skip for test builds — the test harness (test_main.cpp) may - // reference library symbols that aren't in the source AST. + // Function-level tree-shake: figure out which library chunks the + // user's AST actually reaches (transitively through chunk dep + // edges), then hand the reachable subset of each archive to the + // codegen for emission. Test builds bypass the shake — the test + // harness may reference symbols not present in the source AST. const isTestBuild = pipeline.mergedOptions.isTestBuild ?? false; - const usedLibs = isTestBuild - ? null - : collectUsedLibraries(pipeline.ast, pipeline.allArchives); + const reachableByArchive = collectUsedSymbols( + pipeline.ast, + pipeline.allArchives, + isTestBuild, + ); - // Inject compiled C++ preamble code from libraries for (const archive of pipeline.allArchives) { - if ( - archive.headerCode && - (usedLibs === null || usedLibs.has(archive.manifest.name)) - ) { - codegen.addLibraryPreamble( - archive.manifest.name, - archive.headerCode, - archive.cppCode, - ); - } + const reachable = reachableByArchive.get(archive.manifest.name); + if (!reachable || reachable.size === 0) continue; + codegen.addLibraryChunks(archive, reachable); } const codeResult = codegen.generate(pipeline.ast); @@ -919,6 +1023,19 @@ export { } from "./semantic/type-utils.js"; export { isElementaryType } from "./semantic/type-registry.js"; +// Canonical IEC base-type registry — same data published as +// libs/iec-types.json. Downstream tooling that prefers a typed +// import over the JSON artefact can pull these directly. +export { + IEC_BASE_TYPES, + lookupBaseType, + isBaseTypeName, +} from "./semantic/iec-types-data.js"; +export type { + IECTypeMetadata, + IECWireFormat, +} from "./semantic/iec-types-data.js"; + // Re-export project model export type { ProjectModel } from "./project-model.js"; diff --git a/src/library/codesys-import/codesys-importer.ts b/src/library/codesys-import/codesys-importer.ts index ad33ca9..fdfd043 100644 --- a/src/library/codesys-import/codesys-importer.ts +++ b/src/library/codesys-import/codesys-importer.ts @@ -60,6 +60,7 @@ export function importCodesysLibrary(filePath: string): CodesysImportResult { return { success: false, sources: [], + globalConstants: {}, metadata: { format: "v23", pouCount: 0, counts: {} }, warnings: [], errors: [ @@ -73,6 +74,7 @@ export function importCodesysLibrary(filePath: string): CodesysImportResult { return { success: false, sources: [], + globalConstants: {}, metadata: { format: "v23", pouCount: 0, counts: {} }, warnings: [], errors: [ @@ -99,6 +101,7 @@ function importV23(data: Buffer): CodesysImportResult { return { success: false, sources: [], + globalConstants: {}, metadata: { format: "v23", pouCount: 0, counts: {} }, warnings, errors: ["No POUs found in library file."], @@ -111,6 +114,7 @@ function importV23(data: Buffer): CodesysImportResult { return { success: true, sources, + globalConstants: {}, metadata: { format: "v23", pouCount: pous.length, counts }, warnings, errors: [], @@ -121,12 +125,13 @@ function importV23(data: Buffer): CodesysImportResult { * Import a CODESYS V3 library from pre-read ZIP binary data. */ function importV3(data: Buffer): CodesysImportResult { - const { pous, guid, warnings } = parseV3Library(data); + const { pous, guid, globalConstants, warnings } = parseV3Library(data); if (pous.length === 0) { return { success: false, sources: [], + globalConstants, metadata: { format: "v3", pouCount: 0, guid, counts: {} }, warnings, errors: ["No POUs found in library archive."], @@ -139,6 +144,7 @@ function importV3(data: Buffer): CodesysImportResult { return { success: true, sources, + globalConstants, metadata: { format: "v3", pouCount: pous.length, guid, counts }, warnings, errors: [], diff --git a/src/library/codesys-import/pou-formatter.ts b/src/library/codesys-import/pou-formatter.ts index 888c3a4..3792b75 100644 --- a/src/library/codesys-import/pou-formatter.ts +++ b/src/library/codesys-import/pou-formatter.ts @@ -45,13 +45,30 @@ export function formatPOU(pou: ExtractedPOU): string { /** * Convert an array of ExtractedPOUs into source file entries suitable - * for `compileStlib()`. + * for `compileStlib()`. The POU's `category` (folder path inside the + * source library) and `documentation` (variables-pane doc block) are + * forwarded so the compiler can attach them to the resulting manifest + * entries — sources stay flat in the archive, but the manifest carries + * the metadata the upstream binary preserved. */ -export function pouToSources( - pous: ExtractedPOU[], -): Array<{ fileName: string; source: string }> { - return pous.map((pou) => ({ - fileName: pou.type === "GVL" ? `${pou.name}.gvl.st` : `${pou.name}.st`, - source: formatPOU(pou), - })); +export function pouToSources(pous: ExtractedPOU[]): Array<{ + fileName: string; + source: string; + category?: string; + documentation?: string; +}> { + return pous.map((pou) => { + const entry: { + fileName: string; + source: string; + category?: string; + documentation?: string; + } = { + fileName: pou.type === "GVL" ? `${pou.name}.gvl.st` : `${pou.name}.st`, + source: formatPOU(pou), + }; + if (pou.category) entry.category = pou.category; + if (pou.documentation) entry.documentation = pou.documentation; + return entry; + }); } diff --git a/src/library/codesys-import/types.ts b/src/library/codesys-import/types.ts index 67e73d2..7201299 100644 --- a/src/library/codesys-import/types.ts +++ b/src/library/codesys-import/types.ts @@ -30,6 +30,20 @@ export interface ExtractedPOU { implementation: string; /** Byte offset in original file (for ordering) */ offset: number; + /** Folder path within the library (slash-separated, e.g. "POUs/Time&Date"). + * Empty/undefined → POU lives at the library root. V3 .library files + * encode this in their per-object .meta records (parent-folder GUID + * chain); V2.3 .lib files predate folders and always omit it. */ + category?: string; + /** + * POU documentation pulled from the structurally-anchored slot CODESYS + * reserves for the variables-pane comment (the records after the last + * `END_VAR` / `END_TYPE` in the decl sub-object). Independent of any + * trigger-word convention: whatever comment lives in that slot becomes + * the POU's doc. Body comments end up in the impl sub-object so they + * never bleed in. Undefined when the POU has no comment in that slot. + */ + documentation?: string; } /** Detected CODESYS library format. */ @@ -43,6 +57,15 @@ export interface CodesysImportResult { success: boolean; /** Extracted ST source files ready for compilation */ sources: Array<{ fileName: string; source: string }>; + /** + * Compile-time integer constants extracted from any VAR_GLOBAL CONSTANT + * blocks in the imported library. These need to flow into compileStlib + * via its `globalConstants` option (rather than living in `sources` as a + * runtime GVL) so the C++ codegen can fold them into template parameters + * — e.g. OSCAT's STRING_LENGTH gets used as `IECStringVar`, + * which requires a constexpr value, not a runtime variable. + */ + globalConstants: Record; /** Import metadata */ metadata: { format: CodesysFormat; diff --git a/src/library/codesys-import/v3-parser.ts b/src/library/codesys-import/v3-parser.ts index 78a2227..0e81ea2 100644 --- a/src/library/codesys-import/v3-parser.ts +++ b/src/library/codesys-import/v3-parser.ts @@ -5,23 +5,57 @@ * * Extracts POU source code from CODESYS V3 .library files (ZIP archives). * - * The V3 .library format: - * - ZIP archive containing GUID-named .meta/.object pairs + auxiliary files + * Format overview (reverse-engineered, undocumented): + * - ZIP archive containing GUID-named .meta/.object pairs + auxiliary files. * - String table: __shared_data_storage_string_table__.auxiliary * All source text stored as sequential LEB128-indexed UTF-8 entries. + * Strings are added to the table in the order POUs are saved, so the + * indices for any single POU's lines tend to form a contiguous + * monotonically-increasing range. Common lines like "ELSE", "END_IF;", + * "" (empty), "*)" reuse low-varint shared entries — this matters + * because filtering rows by varint range would drop legitimate source + * that happens to use a shared string. * - Object files: UUID.object — per-POU binary with two sub-objects: - * 1) Implementation (code body): records 1..boundary, column A - * 2) Declaration (VAR blocks + header): records after boundary, column A - * Records are 3-varint tuples delimited by 8 zero bytes. - * A boundary record (>3 varints) separates the two sub-objects. + * 1) Implementation (code body): records 1..boundary + * 2) Declaration (header + VAR blocks + comment): records after boundary + * Records are varint tuples delimited by 8 zero bytes. * * Object file binary layout: * [20-byte header: magic 02200928 + 12 zeros + uint32LE data length] - * [Record 0: 9+ varints + 8-zero terminator] (metadata) - * [Records 1..N: 3 varints + 8-zero terminator] (implementation lines) - * [Boundary record: 6+ varints + 8-zero terminator] - * [Records: 3-4 varints + 8-zero terminator] (declaration lines) - * [Final record: varints, NO terminator] + * [Record 0 — metadata, n=9: varint[5] = total impl line count] + * [Records 1..N-1 — thin impl rows, n=3: col 0 = line content] + * [Boundary record — fat row-packed overflow, holds remaining impl lines] + * [Header record — col 0 (or col 1 for n=4) = "FUNCTION_BLOCK X" / etc.] + * [Decl thin records — col 0 = decl line] + * [Final record — variable, no terminator] + * + * Boundary record (fat) row layout: + * The boundary record packs the trailing impl-section lines that didn't + * fit in thin records. Each "row" begins with the line-content varint at + * col 0, followed by 0+ non-zero metadata varints, followed by exactly + * 7+ zero varints as padding. The next row's col 0 starts immediately + * after the zero run. We don't rely on a fixed stride: per-row width + * varies (observed 10 cols for short impls, 11 cols partway through long + * ones — the extra column appears once additional row metadata kicks in + * for the trailing comment block). A zero-run delimiter is the only + * reliable boundary, and the total row count is bounded by R0[5] minus + * the thin record count, which lets us stop before any post-impl junk. + * + * For very short impls (boundary record n in [4..16]), the boundary + * record's col 0 is simply the last impl line (often "*)" closing a + * trailing block comment) and the row detector terminates after one row. + * + * Folder hierarchy: + * The ZIP also contains every POU's matching `.meta` file plus + * "folder placeholder" entries (tiny `.meta` + 23-byte `.object` pairs) + * that describe the project explorer tree (CODESYS Library Manager + * shows them as `POUs/Time&Date/DCF77` etc.). Each .meta carries the + * own GUID, a parent-folder GUID, and a display-name string-table + * index, so walking the parent chain from any POU's .meta resolves to + * a slash-separated path that we surface as `ExtractedPOU.category`. + * Library-root and namespace-scope GUIDs (which appear in *every* meta + * and would otherwise be misread as a parent) are filtered out by + * reference-frequency: they're the most-referenced GUIDs in the file. */ import { inflateRawSync } from "zlib"; @@ -153,26 +187,322 @@ function parseObjectRecords(data: Buffer): number[][] { return records; } +/** GUID format used in CODESYS .meta files. */ +const META_GUID_RE = + /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/; +/** Special "no parent" / "root" GUID. */ +const META_ROOT_GUID = "00000000-0000-0000-0000-000000000000"; + +/** Per-object metadata extracted from an UUID.meta file. */ +interface MetaInfo { + /** Display name (for folder placeholders) — empty for POU metas. */ + displayName: string; + /** All non-self GUID references found in the meta varints, in order. */ + guidRefs: string[]; +} + /** - * Extract a POU from a parsed object file's record stream. + * Decode every LEB128 varint in a binary buffer (skipping the 20-byte + * header that .meta files share with .object files). + */ +function decodeVarintsAfterHeader(data: Buffer): number[] { + if (data.length < OBJECT_HEADER_SIZE) return []; + const out: number[] = []; + let offset = OBJECT_HEADER_SIZE; + while (offset < data.length) { + const [val, newOffset] = readLEB128(data, offset); + out.push(val); + offset = newOffset; + } + return out; +} + +/** + * Pull the parent-GUID-candidate list and display name out of a .meta file. + * + * .meta layout (reverse-engineered): + * offset[2] = string-table index of OWN GUID + * offset[4] = string-table index of display name (folder placeholders only) + * Various GUID-resolved indices appear at higher positions; one of them + * is the parent folder's GUID, and a couple are namespace/library-root + * GUIDs that appear in EVERY meta (filtered separately by frequency). + */ +function parseMetaInfo( + data: Buffer, + ownGuid: string, + strings: Map, +): MetaInfo { + const varints = decodeVarintsAfterHeader(data); + const guidRefs: string[] = []; + let displayName = ""; + for (let i = 0; i < varints.length; i++) { + const s = strings.get(varints[i]!); + if (s === undefined) continue; + if (META_GUID_RE.test(s)) { + if (s !== ownGuid && s !== META_ROOT_GUID) guidRefs.push(s); + } else if (i === 4 && !displayName && s.length > 0) { + // Display-name slot (only meaningful for folder placeholders). + displayName = s; + } + } + return { displayName, guidRefs }; +} + +/** + * Build the folder-path map (POU GUID → "Folder/Subfolder" string) by + * walking every .meta file in the archive. + * + * Two-pass algorithm: + * 1. Collect every meta's GUID refs and compute reference frequency. + * The library-namespace and scope-root GUIDs appear in all ~600 + * metas, so they sit at the top of the frequency table and are + * filtered out as "ambient" references rather than parent links. + * 2. For each meta, pick the first remaining GUID ref as its parent. + * Walk the parent chain to construct the slash-separated path. + * + * V3 .library files without folders (or whose folder records were + * stripped) just produce empty paths — every POU lives at the root. + */ +function buildFolderPaths( + entries: Map, + strings: Map, +): Map { + // Pass 1: parse every .meta, count GUID-reference frequency. + const metaByGuid = new Map(); + const refCount = new Map(); + for (const [name, buf] of entries) { + if (!name.endsWith(".meta")) continue; + const guid = name.replace(/\.meta$/, ""); + const info = parseMetaInfo(buf, guid, strings); + metaByGuid.set(guid, info); + for (const ref of info.guidRefs) { + refCount.set(ref, (refCount.get(ref) ?? 0) + 1); + } + } + + // GUIDs referenced by more metas than there are folders are ambient + // (library namespace, scope root). The hand-decoded sample showed 4 + // such GUIDs in OSCAT, each appearing in 545+ metas. A folder, by + // contrast, can only be the parent of however many objects sit in it, + // and folders bottom out at a few dozen references at most. So any + // GUID with reference count above the largest folder size is noise — + // we err generous (top half of the metas) to keep the heuristic stable + // across smaller libraries. + const ambientThreshold = Math.floor(metaByGuid.size / 2); + const ambient = new Set(); + for (const [guid, count] of refCount) { + if (count > ambientThreshold) ambient.add(guid); + } + + // Resolve each meta's "real" parent GUID (first non-ambient ref). + const parentByGuid = new Map(); + for (const [guid, info] of metaByGuid) { + const parent = info.guidRefs.find((r) => !ambient.has(r)); + if (parent) parentByGuid.set(guid, parent); + } + + // Walk the parent chain to build path strings (folder names only — + // POU metas have empty displayName so they don't contribute their own + // segment, just their parent's path). + const pathByGuid = new Map(); + function pathOf(startGuid: string): string { + if (pathByGuid.has(startGuid)) return pathByGuid.get(startGuid)!; + const segments: string[] = []; + const seen = new Set(); + let cur: string | undefined = parentByGuid.get(startGuid); + while (cur && !seen.has(cur)) { + seen.add(cur); + const meta = metaByGuid.get(cur); + if (!meta) break; + if (meta.displayName) segments.unshift(meta.displayName); + cur = parentByGuid.get(cur); + } + const path = segments.join("/"); + pathByGuid.set(startGuid, path); + return path; + } + for (const guid of metaByGuid.keys()) pathOf(guid); + return pathByGuid; +} + +/** + * Drop the redundant top-level "POUs/" segment from a CODESYS V3 path. + * + * V3 libraries follow a fixed project-explorer convention: every code + * object (FUNCTION_BLOCK, FUNCTION, PROGRAM) lives under a top-level + * "POUs" folder, types under "Data types", globals under "Global + * Variables". Once the archive is compiled into a single .stlib, that + * library IS the POUs container by construction, so re-emitting "POUs" + * as a folder inside it nests every block one level deeper than the + * editor's library tree should display them. Strip it here so + * `POUs/Time&Date/DCF77` becomes `Time&Date/DCF77` and a POU sitting + * directly under "POUs" (no subcategory) becomes uncategorized. * - * Object files contain two sub-objects: - * 1) Implementation: records 1..boundary-1, varint[0] = string index - * 2) Declaration: records boundary+1..end + * Other top-level folders pass through unchanged — "Data types" and + * "Global Variables" carry meaningful classification information for + * downstream tooling. + * + * Returns null when the path collapses to empty (top-level POUs). + */ +function stripCodesysCategoryPrefix(path: string): string | null { + if (path === "POUs") return null; + if (path.startsWith("POUs/")) return path.slice("POUs/".length); + return path; +} + +/** + * Test if a string is a recognized POU/TYPE/GVL header. + */ +function isHeaderString(s: string): boolean { + return POU_DECL_RE.test(s) || TYPE_DECL_RE.test(s) || GVL_DECL_RE.test(s); +} + +/** + * Find the header record's column where the keyword lives. * - * The boundary record is the first record after record 0 with > 3 varints. + * Header encoding varies by POU type: + * - FUNCTION_BLOCK / PROGRAM / TYPE: typically n=4 with col 1 holding the + * keyword and col 0 = 0 (padding). + * - FUNCTION (and a few others): n=3 with col 0 holding the keyword. + * - GVL (VAR_GLOBAL): n=4 with col 1, same shape as FUNCTION_BLOCK. * - * The POU/TYPE header string is found in the first 4-varint record at or - * after the boundary, at varint[1]. For TYPEs (boundary=1, no impl), this - * is the boundary itself; for FBs/FUNCTIONs, it's the first decl record. + * Returns [columnIndex, headerString] or null. + */ +function findHeaderInRecord( + rec: number[], + strings: Map, +): { col: number; header: string } | null { + if (rec.length === 4) { + const s = strings.get(rec[1]!) ?? ""; + if (isHeaderString(s)) return { col: 1, header: s }; + } + if (rec.length >= 1) { + const s = strings.get(rec[0]!) ?? ""; + if (isHeaderString(s)) return { col: 0, header: s }; + } + return null; +} + +/** + * Extract impl lines from a fat boundary record using row-delimiter detection. + * + * Each row in the fat record consists of: + * - 1 content varint (col 0 = line text; can be any value, including + * empty strings or shared low-varint references like `*)`, `ELSE`) + * - 0+ non-zero metadata varints + * - 7+ zero varints as padding + * + * The next row's col 0 starts immediately after the zero run. Stops once + * `expected` rows have been emitted (R0[5] gives the total impl line count, + * so we always know exactly how many rows to read). + */ +function extractBoundaryRows( + br: number[], + strings: Map, + expected: number, +): string[] { + const lines: string[] = []; + let pos = 0; + while (pos < br.length && lines.length < expected) { + lines.push(strings.get(br[pos]!) ?? ""); + pos++; + while (pos < br.length && br[pos] !== 0) pos++; + let zeroRun = 0; + while (pos < br.length && br[pos] === 0) { + pos++; + zeroRun++; + } + // No trailing zero run means the record doesn't follow row-packed format + // (e.g. a non-overflow boundary). Bail out — the caller will have already + // captured what's available. + if (zeroRun === 0 && pos < br.length) break; + } + return lines; +} + +/** + * Extract the POU documentation from the trailing decl records. + * + * CODESYS's editor renders a POU in two panes: a declarations pane (top) + * and a body pane (bottom). The decl sub-object in the .object file + * mirrors the top pane exactly, and CODESYS reserves the slot AFTER the + * last `END_VAR` (or `END_TYPE` for type definitions) for the POU's + * documentation comment — that's why a `(* foo *)` written as the first + * line of the body still ends up in the body sub-object, while the doc + * block always lives in this trailing decl slot regardless of what the + * user types where in either pane. + * + * Structural extraction: + * 1. Walk the decl records and remember the index of the LAST one whose + * col 0 is "END_VAR" or "END_TYPE". + * 2. Concatenate col 0 of every record after that anchor. + * 3. Pull the first complete `(* … *)` block from the joined text. + * That's the POU's doc — no content heuristics, no trigger words. + * + * Returns null when no anchor is found, when the trailing tail is empty, + * or when no closed `(* … *)` block is present (e.g. plain TYPE structs + * with no comment, or POUs that omit a doc entirely). + */ +function extractDocFromDeclRecords( + records: number[][], + declStartIdx: number, + strings: Map, +): string | null { + let anchorIdx = -1; + for (let i = declStartIdx; i < records.length; i++) { + const line = (strings.get(records[i]![0]!) ?? "").trim(); + if (line === "END_VAR" || line === "END_TYPE") anchorIdx = i; + } + if (anchorIdx === -1) return null; + + const tailLines: string[] = []; + for (let i = anchorIdx + 1; i < records.length; i++) { + if (records[i]!.length === 0) continue; + tailLines.push(strings.get(records[i]![0]!) ?? ""); + } + const tail = tailLines.join("\n"); + const docMatch = tail.match(/\(\*([\s\S]*?)\*\)/); + if (!docMatch) return null; + const inner = docMatch[1]!.trim(); + return inner.length > 0 ? inner : null; +} + +/** + * Extract a POU from a parsed object file's record stream. + * + * Layout: + * R0 — metadata, n=9. R0[5] = total impl line count (authoritative). + * R1..R(boundary-1) — thin impl rows (col 0 = line). + * R(boundary) — fat impl row-packed overflow (or small "last line" record + * when impl fits in thin records alone). + * Header record — col 0 or col 1 holds "FUNCTION X" / "FUNCTION_BLOCK X" + * / "PROGRAM X" / "TYPE X :" / "VAR_GLOBAL [CONSTANT|...]". + * Subsequent thin records — col 0 = decl line. + * + * The boundary is the first record after R0 with > 3 varints; this record + * may carry overflow (fat impl) or just one trailing impl line (small). + * Records between the boundary and the header record are post-impl noise + * (compiler scratch / shared-string slots) and are skipped. */ function extractFromRecords( records: number[][], strings: Map, -): { declaration: string; implementation: string } | null { +): { + declaration: string; + implementation: string; + documentation?: string; +} | null { if (records.length < 3) return null; - // Find boundary: first record after record 0 with more than 3 varints + // R0[5] = total impl line count, but only for POU-shaped objects whose + // R0 has 9 varints. TYPE and GVL objects use a different R0 layout (n=7 + // with semantic varints in different positions); they have no impl + // section, so we treat their impl count as 0 and let the regular + // boundary/header logic skip impl extraction entirely. + const r0 = records[0]!; + const totalImplLines = r0.length === 9 ? r0[5]! : 0; + + // Find boundary: first record after record 0 with more than 3 varints. let boundary = -1; for (let i = 1; i < records.length; i++) { if (records[i]!.length > 3) { @@ -180,10 +510,9 @@ function extractFromRecords( break; } } - if (boundary === -1) return null; - // Implementation: records 1..boundary-1, column A (varint[0]) + // Impl: thin rows R1..R(boundary-1) col 0, then row-detector on boundary. const implLines: string[] = []; for (let i = 1; i < boundary; i++) { const rec = records[i]!; @@ -191,37 +520,69 @@ function extractFromRecords( implLines.push(strings.get(rec[0]!) ?? ""); } } + let cursor = boundary; + if (totalImplLines > implLines.length) { + const want = totalImplLines - implLines.length; + implLines.push(...extractBoundaryRows(records[boundary]!, strings, want)); + cursor = boundary + 1; + } - // Find the POU/TYPE header: scan from boundary for first 4-varint record - // whose rec[1] resolves to a recognized header string. + // Header: scan from cursor, accept col 0 (n>=3) or col 1 (n=4). Records + // between the boundary and the header that aren't themselves header + // records carry the few impl lines that didn't fit in the boundary's + // row-packed overflow (e.g. a single trailing `*)` of a block comment + // for some FUNCTION-shaped POUs); their col 0 picks those up while we + // still need more impl lines per R0[5]. const declLines: string[] = []; let headerRecIdx = -1; - - for (let i = boundary; i < records.length; i++) { + for (let i = cursor; i < records.length; i++) { const rec = records[i]!; - if (rec.length === 4 && rec.length <= 4) { - const headerStr = strings.get(rec[1]!) ?? ""; - if (POU_DECL_RE.test(headerStr) || /^TYPE\s+\w+/.test(headerStr)) { - declLines.push(headerStr); - headerRecIdx = i; - break; - } + const found = findHeaderInRecord(rec, strings); + if (found) { + declLines.push(found.header); + headerRecIdx = i; + break; + } + if (implLines.length < totalImplLines && rec.length > 0) { + implLines.push(strings.get(rec[0]!) ?? ""); } } - // Declaration body: records after boundary (skipping the header record) - for (let i = boundary + 1; i < records.length; i++) { - if (i === headerRecIdx) continue; // already handled - const rec = records[i]!; - if (rec.length > 0) { + // Decl body: col 0 of every record after the header. We skip records + // _before_ the header (post-impl junk: trailing block-comment closer + // packed into a wide pseudo-record, etc.) but include all records after + // it — including wide n=4 records like the closing `END_VAR` of a GVL, + // whose col 0 holds the keyword and whose remaining columns are zero. + if (headerRecIdx !== -1) { + for (let i = headerRecIdx + 1; i < records.length; i++) { + const rec = records[i]!; + if (rec.length === 0) continue; declLines.push(strings.get(rec[0]!) ?? ""); } } - return { + // Documentation — pulled structurally from the slot CODESYS reserves + // for the POU's variables-pane comment (after the last END_VAR / + // END_TYPE in the decl records). See extractDocFromDeclRecords for + // the rationale; returning a `documentation` field instead of + // re-discovering it via text regex downstream eliminates the risk of + // mistaking a body comment or a `(* Initialize variables *)` inline + // annotation for the POU doc. + const documentation = + headerRecIdx !== -1 + ? extractDocFromDeclRecords(records, headerRecIdx + 1, strings) + : null; + + const result: { + declaration: string; + implementation: string; + documentation?: string; + } = { declaration: declLines.join("\n"), implementation: implLines.join("\n"), }; + if (documentation) result.documentation = documentation; + return result; } /** @@ -261,6 +622,13 @@ function classifyPOU( } if (GVL_DECL_RE.test(line)) { + // Empty GVLs (header followed immediately by END_VAR with no variable + // declarations between) carry no semantic content and can use VAR_GLOBAL + // qualifier combinations the strucpp parser doesn't recognize + // (e.g. `VAR_GLOBAL PERSISTENT RETAIN`). Drop them — the resulting + // archive is identical with or without an empty global section. + const hasVars = lines.some((l) => /^\s*\w+\s*:/.test(l)); + if (!hasVars) return null; return { type: "GVL", name: `GVL_${gvlCounter.value++}`, @@ -327,6 +695,75 @@ function handleBareStruct( }; } +/** + * Recognized integer ST types whose VAR_GLOBAL CONSTANT entries can be + * promoted to compile-time globalConstants. Booleans, strings, and + * floating-point types stay as runtime GVL variables — only integer + * widths fold cleanly into compileStlib's globalConstants map (which + * targets C++ template parameters that demand a constexpr value). + */ +const INTEGER_ST_TYPES = new Set([ + "BYTE", + "SINT", + "USINT", + "WORD", + "INT", + "UINT", + "DWORD", + "DINT", + "UDINT", + "LWORD", + "LINT", + "ULINT", +]); + +/** + * Parse a `VAR_GLOBAL CONSTANT` block and return the integer constants it + * declares. Used to promote constants like OSCAT's STRING_LENGTH / + * LIST_LENGTH into compile-time values that can be used as C++ template + * parameters; the GVL itself is dropped to avoid a duplicate definition. + * + * Returns null if the declaration isn't a CONSTANT block, or if any + * non-integer / non-numeric entries are present (the caller keeps the + * GVL as a runtime variable in that case). + */ +function extractConstantGlobals( + declaration: string, +): Record | null { + const lines = declaration.split("\n"); + let inConstantBlock = false; + const out: Record = {}; + for (const raw of lines) { + const line = raw.trim(); + if (!line) continue; + if (/^VAR_GLOBAL\s+CONSTANT\b/.test(line)) { + inConstantBlock = true; + continue; + } + if (line === "END_VAR") { + inConstantBlock = false; + continue; + } + if ( + line.startsWith("(*") || + line.startsWith("//") || + line.startsWith("*") + ) { + continue; + } + if (!inConstantBlock) continue; + + const match = line.match(/^(\w+)\s*:\s*(\w+)\s*:=\s*([+-]?\d+)\s*;?\s*$/); + if (!match) return null; + const [, name, type, valueStr] = match; + if (!INTEGER_ST_TYPES.has(type!.toUpperCase())) return null; + const value = Number.parseInt(valueStr!, 10); + if (!Number.isFinite(value)) return null; + out[name!] = value; + } + return Object.keys(out).length > 0 ? out : null; +} + /** * Try to extract a GVL from an object whose declaration starts with * VAR_INPUT or VAR_GLOBAL or variable declarations directly. @@ -341,6 +778,12 @@ function handleBareGVL( stripped.startsWith("VAR_INPUT") || /^\t[A-Z_]\w+\s*:\s*\w+/.test(stripped) ) { + // Empty GVLs (no `name : type` lines) are dropped here for the same + // reason as in `classifyPOU` — see comment there. + const lines = declaration.split("\n"); + const hasVars = lines.some((l) => /^\s*\w+\s*:/.test(l)); + if (!hasVars) return null; + const name = `GVL_${gvlCounter.value++}`; // Wrap bare variable lists in VAR_GLOBAL if needed let body = declaration; @@ -415,9 +858,11 @@ function* unzipEntries( export function parseV3Library(data: Buffer): { pous: ExtractedPOU[]; guid: string; + globalConstants: Record; warnings: string[]; } { const warnings: string[] = []; + const globalConstants: Record = {}; // Extract all ZIP entries const entries = new Map(); @@ -431,6 +876,7 @@ export function parseV3Library(data: Buffer): { return { pous: [], guid: "", + globalConstants, warnings: ["String table not found in ZIP archive."], }; } @@ -445,6 +891,7 @@ export function parseV3Library(data: Buffer): { return { pous: [], guid: "", + globalConstants, warnings: [ `Failed to parse string table: ${e instanceof Error ? e.message : String(e)}`, ], @@ -454,6 +901,10 @@ export function parseV3Library(data: Buffer): { // Build TYPE name map for matching bare STRUCT objects const typeMap = buildTypeMap(strings); + // Build folder-path map (POU GUID → "Folder/Subfolder"). Empty paths + // (POUs at the library root) just produce no `category` on the result. + const folderPaths = buildFolderPaths(entries, strings); + // Process each .object file const pous: ExtractedPOU[] = []; const seenNames = new Set(); @@ -463,7 +914,7 @@ export function parseV3Library(data: Buffer): { name.endsWith(".object"), ); - for (const [, objData] of objectEntries) { + for (const [name, objData] of objectEntries) { // Skip tiny metadata objects if (objData.length < MIN_OBJECT_SIZE) continue; @@ -471,7 +922,15 @@ export function parseV3Library(data: Buffer): { const extracted = extractFromRecords(records, strings); if (!extracted) continue; - const { declaration, implementation } = extracted; + const { declaration, implementation, documentation } = extracted; + + // VAR_GLOBAL CONSTANT integer blocks promote to compile-time constants + // and the GVL is dropped — see extractConstantGlobals for the rationale. + const constants = extractConstantGlobals(declaration); + if (constants) { + Object.assign(globalConstants, constants); + continue; + } // Try standard POU classification first let pou = classifyPOU(declaration, implementation, gvlCounter); @@ -487,6 +946,23 @@ export function parseV3Library(data: Buffer): { } if (pou && !seenNames.has(pou.name)) { + const objGuid = name.replace(/\.object$/, ""); + const path = folderPaths.get(objGuid); + if (path) { + // CODESYS V3 always wraps user code in a top-level "POUs" + // folder (the project-explorer convention; "Data types" and + // "Global Variables" sit alongside it for type definitions + // and globals). The compiled library IS the POUs container, + // so the prefix is redundant for downstream consumers — drop + // it here so OSCAT's `POUs/Time&Date/DCF77` surfaces as + // `Time&Date/DCF77` in the .stlib manifest. Non-POUs + // top-level folders pass through untouched, since their + // labels carry meaningful information ("Data types" tells + // tooling these are TYPE definitions). + const stripped = stripCodesysCategoryPrefix(path); + if (stripped) pou.category = stripped; + } + if (documentation) pou.documentation = documentation; seenNames.add(pou.name); pous.push(pou); } @@ -495,5 +971,5 @@ export function parseV3Library(data: Buffer): { // Sort by name for deterministic output pous.sort((a, b) => a.name.localeCompare(b.name)); - return { pous, guid, warnings }; + return { pous, guid, globalConstants, warnings }; } diff --git a/src/library/library-chunks.ts b/src/library/library-chunks.ts new file mode 100644 index 0000000..6ea5137 --- /dev/null +++ b/src/library/library-chunks.ts @@ -0,0 +1,401 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (C) 2025 Autonomy / OpenPLC Project +/** + * Per-symbol chunk extraction from codegen output. + * + * The codegen emits chunk-boundary markers (`//@chunk:begin/end::`) + * around each top-level declaration when `emitChunkMarkers` is enabled. This + * module slices the emitted header / cpp text into per-symbol chunks and + * extracts the cross-symbol dep graph from the AST, producing the + * `LibraryChunk[]` array stored in a `.stlib` archive. + * + * The chunked representation is what enables function-level tree-shaking + * in the consumer codegen: only chunks reachable from the user's AST get + * emitted into the final `generated.hpp` / `generated.cpp`. + */ + +import { walkAST } from "../ast-utils.js"; +import type { ASTNode, CompilationUnit } from "../frontend/ast.js"; +import type { + LibraryChunk, + LibraryChunkDep, + LibraryManifest, + StlibArchive, +} from "./library-manifest.js"; + +type ChunkKind = LibraryChunk["kind"]; + +interface ChunkSlice { + kind: ChunkKind; + name: string; + text: string; + /** Position in the input stream — used for stable ordering when + * merging header and cpp slices that may not appear in the same + * sequence. */ + order: number; +} + +const CHUNK_BEGIN_RX = /^\s*\/\/@chunk:begin:([a-zA-Z]+):(.+?)\s*$/; +const CHUNK_END_RX = /^\s*\/\/@chunk:end:([a-zA-Z]+):(.+?)\s*$/; + +const KNOWN_KINDS: ReadonlySet = new Set([ + "function", + "functionBlock", + "type", + "inlineGlobal", +]); + +function isChunkKind(s: string): s is ChunkKind { + return KNOWN_KINDS.has(s); +} + +/** + * Slice codegen output into per-symbol chunks. + * + * Returns the parsed slices keyed by `:` plus the + * marker-stripped text. The stripped text equals the input verbatim + * minus the marker lines, suitable for use as the legacy library-wide + * `headerCode` / `cppCode` blob (kept on `StlibArchive` through the + * migration; retired in Phase 4 when chunks become authoritative). + */ +export function extractChunkSlices( + code: string, + lineEnding: string, +): { slices: Map; stripped: string } { + const lines = code.split(lineEnding); + const slices = new Map(); + const strippedLines: string[] = []; + let current: { + kind: ChunkKind; + name: string; + lines: string[]; + order: number; + } | null = null; + let orderCounter = 0; + + for (const line of lines) { + const beginMatch = line.match(CHUNK_BEGIN_RX); + if (beginMatch) { + const [, kind, name] = beginMatch; + if (kind && name && isChunkKind(kind)) { + current = { kind, name, lines: [], order: orderCounter++ }; + } + continue; + } + + const endMatch = line.match(CHUNK_END_RX); + if (endMatch) { + if (current) { + const [, endKind, endName] = endMatch; + if (endKind === current.kind && endName === current.name) { + slices.set(`${current.kind}:${current.name}`, { + kind: current.kind, + name: current.name, + text: current.lines.join(lineEnding), + order: current.order, + }); + } + current = null; + } + continue; + } + + if (current) { + current.lines.push(line); + } + strippedLines.push(line); + } + + return { slices, stripped: strippedLines.join(lineEnding) }; +} + +/** + * Build a symbol-name → owning-library map from the archive's own AST + * plus the manifest of each declared dependency. The map drives dep + * edge construction: a reference resolves to either the same library + * (`{library: "this", name}`), a declared dep, or nothing (unresolved + * symbol — silently dropped from deps; it's either a built-in or a + * compiler-injected helper neither of which needs tree-shaking). + */ +function buildSymbolOwnership( + ast: CompilationUnit, + ownLibraryName: string, + dependencies: StlibArchive[], +): Map { + const ownership = new Map(); + + // Own AST: every top-level decl is owned by this library + for (const t of ast.types) + ownership.set(t.name.toUpperCase(), ownLibraryName); + for (const i of ast.interfaces) + ownership.set(i.name.toUpperCase(), ownLibraryName); + for (const fb of ast.functionBlocks) + ownership.set(fb.name.toUpperCase(), ownLibraryName); + for (const fn of ast.functions) + ownership.set(fn.name.toUpperCase(), ownLibraryName); + for (const block of ast.globalVarBlocks) { + for (const decl of block.declarations) { + for (const name of decl.names) { + ownership.set(name.toUpperCase(), ownLibraryName); + } + } + } + + // Programs (rare in libraries but defensive — they're emitted as `Program_`) + for (const p of ast.programs) { + ownership.set(`PROGRAM_${p.name.toUpperCase()}`, ownLibraryName); + } + + // Dependencies: every exported symbol from each declared dep + for (const dep of dependencies) { + const depName = dep.manifest.name; + populateManifestSymbols(dep.manifest, depName, ownership); + // Inline globals declared by a dependency live in its chunks. + // Phase 4+ will read these from `chunks`; for now we don't see + // them in the manifest, so cross-library global references stay + // unresolved (they show up as no dep edge — harmless: the + // consumer's symbol→chunk index covers the gap from chunk names). + if (dep.chunks) { + for (const chunk of dep.chunks) { + ownership.set(chunk.name.toUpperCase(), depName); + } + } + } + + return ownership; +} + +function populateManifestSymbols( + manifest: LibraryManifest, + libraryName: string, + ownership: Map, +): void { + for (const fn of manifest.functions) { + ownership.set(fn.name.toUpperCase(), libraryName); + } + for (const fb of manifest.functionBlocks) { + ownership.set(fb.name.toUpperCase(), libraryName); + } + for (const t of manifest.types) { + ownership.set(t.name.toUpperCase(), libraryName); + } +} + +/** + * Walk an AST subtree, collecting every uppercase symbol name it + * references. Recognises every kind of cross-symbol reference the + * codegen relies on: + * + * - `FunctionCallExpression.functionName` — call sites + * - `VariableExpression.name` — variable & inline-global reads + * (`MATH.PI2` shows up as a VariableExpression with name="MATH" + * and fieldAccess=["PI2"]) + * - `TypeReference.name` / `elementTypeName` — type uses, array + * element types + * - `FunctionBlockDeclaration.extends` / `.implements` — FB + * inheritance and interface implementation + * - `InterfaceDeclaration.extends` — interface inheritance + */ +function collectReferencedNames(node: ASTNode, out: Set): void { + walkAST(node, (n) => { + switch (n.kind) { + case "FunctionCallExpression": + out.add( + (n as unknown as { functionName: string }).functionName.toUpperCase(), + ); + break; + case "MethodCallExpression": { + // method call on an FB / interface: object resolution covers + // the type via its own VariableExpression child; the method + // name doesn't need its own dep (methods live with the FB). + break; + } + case "VariableExpression": + out.add((n as unknown as { name: string }).name.toUpperCase()); + break; + case "TypeReference": { + const tr = n as unknown as { name: string; elementTypeName?: string }; + out.add(tr.name.toUpperCase()); + if (tr.elementTypeName) { + out.add(tr.elementTypeName.toUpperCase()); + } + break; + } + case "FunctionBlockDeclaration": { + const fbd = n as unknown as { extends?: string; implements?: string[] }; + if (fbd.extends) out.add(fbd.extends.toUpperCase()); + if (fbd.implements) { + for (const iface of fbd.implements) { + out.add(iface.toUpperCase()); + } + } + break; + } + case "InterfaceDeclaration": { + const id = n as unknown as { extends?: string[] }; + if (id.extends) { + for (const base of id.extends) { + out.add(base.toUpperCase()); + } + } + break; + } + } + }); +} + +/** + * Compute the dep graph edges for a single chunk by walking the AST + * node that produced it and resolving each referenced name through + * the symbol-ownership map. + */ +function computeChunkDeps( + kind: ChunkKind, + name: string, + ast: CompilationUnit, + ownership: Map, +): LibraryChunkDep[] { + const referenced = new Set(); + + switch (kind) { + case "function": { + const fn = ast.functions.find((f) => f.name === name); + if (fn) collectReferencedNames(fn as unknown as ASTNode, referenced); + break; + } + case "functionBlock": { + if (name.startsWith("Program_")) { + const progName = name.slice("Program_".length); + const prog = ast.programs.find((p) => p.name === progName); + if (prog) + collectReferencedNames(prog as unknown as ASTNode, referenced); + } else { + const fb = ast.functionBlocks.find((f) => f.name === name); + if (fb) collectReferencedNames(fb as unknown as ASTNode, referenced); + } + break; + } + case "type": { + const t = ast.types.find((td) => td.name === name); + if (t) { + collectReferencedNames(t as unknown as ASTNode, referenced); + } else { + const iface = ast.interfaces.find((i) => i.name === name); + if (iface) + collectReferencedNames(iface as unknown as ASTNode, referenced); + } + break; + } + case "inlineGlobal": { + // Globals don't have a single wrapping AST node — walk the + // matching declaration's type + initial-value expression. + for (const block of ast.globalVarBlocks) { + for (const decl of block.declarations) { + if (decl.names.includes(name)) { + collectReferencedNames(decl.type as unknown as ASTNode, referenced); + if (decl.initialValue) { + collectReferencedNames( + decl.initialValue as unknown as ASTNode, + referenced, + ); + } + } + } + } + break; + } + } + + // A chunk never depends on itself + referenced.delete(name.toUpperCase()); + + // Map referenced names → (library, name) deps. Names with no known + // owner are intentionally dropped: they're either compiler built-ins, + // helper functions the codegen injects (which always link), or + // user-defined names that don't exist in any library (an error the + // semantic phase already caught). + const deps: LibraryChunkDep[] = []; + for (const refName of referenced) { + const owner = ownership.get(refName); + if (!owner) continue; + deps.push({ library: owner, name: refName }); + } + // Stable ordering so two builds of the same library produce + // byte-identical archives. + deps.sort((a, b) => { + if (a.library !== b.library) return a.library < b.library ? -1 : 1; + return a.name < b.name ? -1 : a.name > b.name ? 1 : 0; + }); + return deps; +} + +/** + * Build the full chunk list for a compiled library. + * + * Combines header-side and cpp-side chunk slices (an FB produces both; + * a type produces only a header chunk; an inline global same) and + * computes dep edges per chunk. The chunk ordering follows the + * header-slice declaration order, with cpp-only chunks (none today, + * defensive) tacked on after. + */ +export function buildChunks( + headerCode: string, + cppCode: string, + lineEnding: string, + ast: CompilationUnit, + ownLibraryName: string, + dependencies: StlibArchive[], +): { chunks: LibraryChunk[]; cleanHeader: string; cleanCpp: string } { + const headerExtraction = extractChunkSlices(headerCode, lineEnding); + const cppExtraction = extractChunkSlices(cppCode, lineEnding); + + const ownership = buildSymbolOwnership(ast, ownLibraryName, dependencies); + + // Canonical chunk order: header order first, then any cpp-only + // chunks (the legacy emit has none, but the rule is defined). + const seenKeys = new Set(); + const orderedKeys: string[] = []; + + const headerByOrder = [...headerExtraction.slices.values()].sort( + (a, b) => a.order - b.order, + ); + for (const slice of headerByOrder) { + const key = `${slice.kind}:${slice.name}`; + orderedKeys.push(key); + seenKeys.add(key); + } + + const cppByOrder = [...cppExtraction.slices.values()].sort( + (a, b) => a.order - b.order, + ); + for (const slice of cppByOrder) { + const key = `${slice.kind}:${slice.name}`; + if (!seenKeys.has(key)) { + orderedKeys.push(key); + seenKeys.add(key); + } + } + + const chunks: LibraryChunk[] = []; + for (const key of orderedKeys) { + const headerSlice = headerExtraction.slices.get(key); + const cppSlice = cppExtraction.slices.get(key); + const slice = headerSlice ?? cppSlice!; + chunks.push({ + name: slice.name, + kind: slice.kind, + header: headerSlice?.text ?? "", + cpp: cppSlice?.text ?? "", + deps: computeChunkDeps(slice.kind, slice.name, ast, ownership), + }); + } + + return { + chunks, + cleanHeader: headerExtraction.stripped, + cleanCpp: cppExtraction.stripped, + }; +} + +// Re-export for type-only consumers that pull through this module. +export type { ChunkKind }; diff --git a/src/library/library-compiler.ts b/src/library/library-compiler.ts index 18abeb1..8261fc7 100644 --- a/src/library/library-compiler.ts +++ b/src/library/library-compiler.ts @@ -13,11 +13,8 @@ import type { StlibArchive, } from "./library-manifest.js"; import { compile } from "../index.js"; +import { buildChunks } from "./library-chunks.js"; import type { LibraryVarType } from "./library-manifest.js"; -import { - extractNamespaceBody, - stripDependencyPreambles, -} from "./library-utils.js"; import type { TypeReference } from "../frontend/ast.js"; /** @@ -41,6 +38,114 @@ function serializeVarType( return entry; } +/** Match a top-of-line POU header. */ +const POU_HEADER_RE = + /^[ \t]*(FUNCTION_BLOCK|FUNCTION|PROGRAM|TYPE)[ \t]+(\w+)/gm; + +/** + * Build a "POU name → category" map from categorized source inputs. + * + * Each .st file may declare multiple POUs (counter.st in iec-standard-fb + * holds 15 counter variants in one file). All POUs declared in the same + * source file inherit that file's category — by construction each input + * file lives in exactly one folder. + * + * Uses a regex over top-of-line POU declarations rather than running the + * parser, which keeps the lookup cheap (~600 sources × cheap regex vs. + * Chevrotain re-parse per source). + */ +function buildCategoryByPouName( + sources: Array<{ source: string; fileName: string; category?: string }>, +): Map { + // Manifest entry names come from the parser, which uppercases POU + // identifiers. Source-text names preserve original casing (CODESYS + // happily exports "FT_Profile" as mixed case). Normalize both sides + // by uppercasing the map keys, so we match regardless of the casing + // used in the original source. + const map = new Map(); + for (const src of sources) { + if (!src.category) continue; + let m: RegExpExecArray | null; + POU_HEADER_RE.lastIndex = 0; + while ((m = POU_HEADER_RE.exec(src.source)) !== null) { + const name = m[2]!.toUpperCase(); + if (!map.has(name)) map.set(name, src.category); + } + } + return map; +} + +/** + * Build a "POU name → documentation" map from caller-supplied per-source + * documentation strings. + * + * Documentation lives in the source entry rather than in the source text + * — only the upstream importer (V3 codesys-importer in particular) knows + * which `(* … *)` block in a source is structurally the POU doc and which + * is an inline variable annotation. The compiler trusts what the importer + * already determined; if `source.documentation` is set, it's the doc. + * + * For hand-authored .st files (e.g. when `--compile-lib` is pointed at a + * directory of .st files without going through the codesys-importer), + * `documentation` is unset and the map stays empty — those libraries get + * their docs from the `library.json` `blocks` / `functions` maps via + * `applyLibraryConfigDocumentation`, which still runs as a post-step. + * + * Each input source maps to all POU names it declares; the strucpp parser + * uppercases identifiers, so we uppercase keys to bridge cases like + * OSCAT's `FT_Profile` → manifest `FT_PROFILE`. + */ +function buildDocByPouName( + sources: Array<{ + source: string; + fileName: string; + documentation?: string; + }>, +): Map { + const map = new Map(); + for (const src of sources) { + if (!src.documentation) continue; + let m: RegExpExecArray | null; + POU_HEADER_RE.lastIndex = 0; + while ((m = POU_HEADER_RE.exec(src.source)) !== null) { + const name = m[2]!.toUpperCase(); + if (!map.has(name)) map.set(name, src.documentation); + } + } + return map; +} + +/** + * Optionally tag a manifest entry with its category. The field is omitted + * entirely when no category was assigned, so an .stlib built from a flat + * source layout serializes byte-identical to the pre-hierarchy format. + */ +function tagCategory( + entry: T, + catByName: Map, +): T { + const cat = catByName.get(entry.name); + if (cat) entry.category = cat; + return entry; +} + +/** + * Optionally tag a manifest entry with documentation extracted from its + * inline source doc-block. Same omit-when-empty contract as `tagCategory` + * — entries without a doc block in their source serialize identically to + * the pre-extraction shape, so library.json's + * `applyLibraryConfigDocumentation` post-processor still works as the + * authoritative override mechanism for hand-curated docs. + */ +function tagDocumentation( + entry: T, + docByName: Map, +): T { + const doc = docByName.get(entry.name); + if (doc) entry.documentation = doc; + return entry; +} + /** * Compile ST source files into a library. * @@ -49,7 +154,12 @@ function serializeVarType( * @returns The compiled library with manifest and C++ code */ export function compileLibrary( - sources: Array<{ source: string; fileName: string }>, + sources: Array<{ + source: string; + fileName: string; + category?: string; + documentation?: string; + }>, options: { name: string; version: string; @@ -60,6 +170,8 @@ export function compileLibrary( globalConstants?: Record; }, ): LibraryCompileResult { + const catByName = buildCategoryByPouName(sources); + const docByName = buildDocByPouName(sources); if (sources.length === 0) { return { success: false, @@ -85,6 +197,12 @@ export function compileLibrary( const compileOpts: Partial = { additionalSources, + // Always emit chunk markers when compiling a library — the + // archive's `chunks[]` is derived from them. The markers are + // stripped from the final `headerCode` / `cppCode` blobs before + // they're persisted, so downstream consumers (legacy and + // chunk-aware alike) see clean output. + emitChunkMarkers: true, }; if (options.dependencies) { compileOpts.libraries = options.dependencies; @@ -127,69 +245,101 @@ export function compileLibrary( const ast = result.ast!; const headerFileName = `${options.name}.hpp`; + // Slice emitted code into per-symbol chunks via the boundary + // markers; the cleaned (marker-stripped) text replaces the original + // `headerCode`/`cppCode` so downstream consumers see no markers. + const { chunks, cleanHeader, cleanCpp } = buildChunks( + result.headerCode, + result.cppCode, + "\n", + ast, + options.name, + options.dependencies ?? [], + ); + return { success: true, manifest: { name: options.name, version: options.version, namespace: options.namespace, - functions: ast.functions.map((fn) => ({ - name: fn.name, - returnType: fn.returnType.name, - parameters: fn.varBlocks.flatMap((block) => - block.declarations.flatMap((decl) => - decl.names.map((name) => ({ - name, - type: decl.type.name, - direction: - block.blockType === "VAR_OUTPUT" - ? "output" - : block.blockType === "VAR_IN_OUT" - ? "inout" - : "input", - })), + functions: ast.functions.map((fn) => + tagDocumentation( + tagCategory( + { + name: fn.name, + returnType: fn.returnType.name, + parameters: fn.varBlocks.flatMap((block) => + block.declarations.flatMap((decl) => + decl.names.map((name) => ({ + name, + type: decl.type.name, + direction: + block.blockType === "VAR_OUTPUT" + ? "output" + : block.blockType === "VAR_IN_OUT" + ? "inout" + : "input", + })), + ), + ), + }, + catByName, ), + docByName, ), - })), - functionBlocks: ast.functionBlocks.map((fb) => ({ - name: fb.name, - inputs: fb.varBlocks - .filter((b) => b.blockType === "VAR_INPUT") - .flatMap((b) => - b.declarations.flatMap((d) => - d.names.map((n) => serializeVarType(n, d.type)), - ), - ), - outputs: fb.varBlocks - .filter((b) => b.blockType === "VAR_OUTPUT") - .flatMap((b) => - b.declarations.flatMap((d) => - d.names.map((n) => serializeVarType(n, d.type)), - ), - ), - inouts: fb.varBlocks - .filter((b) => b.blockType === "VAR_IN_OUT") - .flatMap((b) => - b.declarations.flatMap((d) => - d.names.map((n) => serializeVarType(n, d.type)), - ), + ), + functionBlocks: ast.functionBlocks.map((fb) => + tagDocumentation( + tagCategory( + { + name: fb.name, + inputs: fb.varBlocks + .filter((b) => b.blockType === "VAR_INPUT") + .flatMap((b) => + b.declarations.flatMap((d) => + d.names.map((n) => serializeVarType(n, d.type)), + ), + ), + outputs: fb.varBlocks + .filter((b) => b.blockType === "VAR_OUTPUT") + .flatMap((b) => + b.declarations.flatMap((d) => + d.names.map((n) => serializeVarType(n, d.type)), + ), + ), + inouts: fb.varBlocks + .filter((b) => b.blockType === "VAR_IN_OUT") + .flatMap((b) => + b.declarations.flatMap((d) => + d.names.map((n) => serializeVarType(n, d.type)), + ), + ), + }, + catByName, ), - })), - types: ast.types.map((t) => ({ - name: t.name, - kind: + docByName, + ), + ), + types: ast.types.map((t) => { + const kind: "struct" | "enum" | "alias" = t.definition.kind === "StructDefinition" ? "struct" : t.definition.kind === "EnumDefinition" ? "enum" - : "alias", - })), + : "alias"; + return tagDocumentation( + tagCategory({ name: t.name, kind }, catByName), + docByName, + ); + }), headers: [headerFileName], isBuiltin: false, sourceFiles: sources.map((s) => s.fileName), }, - headerCode: result.headerCode, - cppCode: result.cppCode, + headerCode: cleanHeader, + cppCode: cleanCpp, + chunks, errors: [], }; } @@ -205,7 +355,12 @@ export function compileLibrary( * @returns The compiled `.stlib` archive result */ export function compileStlib( - sources: Array<{ source: string; fileName: string }>, + sources: Array<{ + source: string; + fileName: string; + category?: string; + documentation?: string; + }>, options: { name: string; version: string; @@ -230,58 +385,40 @@ export function compileStlib( archive: { formatVersion: 1, manifest: libResult.manifest, - headerCode: "", - cppCode: "", + chunks: [], dependencies: [], }, errors: libResult.errors, }; } - let headerBody = extractNamespaceBody(libResult.headerCode); - let cppBody = extractNamespaceBody(libResult.cppCode); - - // Strip dependency preamble code from the archive — consumers load - // dependencies separately, so baking them in would cause redefinitions. - if (options.dependencies && options.dependencies.length > 0) { - const depNames = new Set(options.dependencies.map((d) => d.manifest.name)); - const headerPreambles = new Map>(); - const cppPreambles = new Map>(); - for (const dep of options.dependencies) { - headerPreambles.set( - dep.manifest.name, - new Set(dep.headerCode.split("\n")), - ); - cppPreambles.set(dep.manifest.name, new Set(dep.cppCode.split("\n"))); - } - headerBody = stripDependencyPreambles( - headerBody, - depNames, - headerPreambles, - ); - cppBody = stripDependencyPreambles(cppBody, depNames, cppPreambles); - } - // Clear manifest.headers — the .stlib archive inlines its C++ code - // directly into the consumer's output via addLibraryPreamble(), so + // directly into the consumer's output via addLibraryChunks(), so // there are no external .hpp files to #include. const manifest = { ...libResult.manifest, headers: [] as string[] }; + // Chunks own each declared symbol's emit slices, so the dep-preamble + // strip that used to operate on the library-wide blob is no longer + // needed: a chunk only emits its own declaration text, never a + // dependency's, by construction. const archive: StlibCompileResult["archive"] = { formatVersion: 1, manifest, - headerCode: headerBody, - cppCode: cppBody, + chunks: libResult.chunks ?? [], dependencies: (options.dependencies ?? []).map((d) => ({ name: d.manifest.name, version: d.manifest.version, })), }; if (!options.noSource) { - archive.sources = sources.map((s) => ({ - fileName: s.fileName, - source: s.source, - })); + archive.sources = sources.map((s) => { + const entry: { fileName: string; source: string; category?: string } = { + fileName: s.fileName, + source: s.source, + }; + if (s.category) entry.category = s.category; + return entry; + }); } if ( options.globalConstants && diff --git a/src/library/library-config.ts b/src/library/library-config.ts new file mode 100644 index 0000000..9156331 --- /dev/null +++ b/src/library/library-config.ts @@ -0,0 +1,252 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (C) 2025 Autonomy / OpenPLC Project +/** + * Library configuration file (`library.json`). + * + * Each library on disk lives in `libs/sources//` and ships a + * `library.json` next to its `.st` source files. The JSON carries every + * field of the .stlib manifest that ISN'T derivable from the ST sources: + * + * - identity (name, version, namespace) + * - human-readable description + * - the `isBuiltin` flag + * - block-level documentation prose (one entry per FUNCTION_BLOCK) + * - function-level documentation prose (one entry per FUNCTION) + * + * The build flow is: + * + * 1. Read library.json from the library's source directory + * (loadLibraryConfig). + * 2. Read all .st files alongside it. + * 3. Call compileStlib(sources, options-from-config). + * 4. Merge per-block / per-function documentation into the resulting + * manifest entries (applyLibraryConfigDocumentation), validating + * that every doc'd name actually appears in the compiled output. + * + * library.json is the single source of truth for library metadata. + * Build scripts may still hardcode defaults for libraries that haven't + * been migrated yet — loadLibraryConfig returns null when the file is + * absent, and the caller falls back to its own constants. + */ + +import { readFileSync, existsSync } from "fs"; +import { resolve } from "path"; + +import type { StlibArchive } from "./library-manifest.js"; + +/** + * Parsed shape of a `library.json` file. + * + * Required fields mirror the corresponding `.stlib` manifest fields so a + * library with no .st sources at all (purely-imported lib, e.g. OSCAT) + * could in theory ship just a `library.json` + `.stlib` archive. + * + * `blocks` and `functions` are name-keyed maps so the JSON file reads + * naturally — one block per top-level entry — and the build script can + * cross-check each name against the compiled manifest's `functionBlocks[]` + * / `functions[]`. + */ +export interface LibraryConfig { + /** Library identity. Must match what the consumer references. */ + name: string; + /** Optional human-readable name for tooling display (editor library + * trees, package manager UIs). Falls back to `name` when unset. */ + displayName?: string; + /** SemVer-like version string. */ + version: string; + /** C++ namespace the compiled archive lives in. */ + namespace: string; + /** Human-readable summary surfaced in tooling. */ + description?: string; + /** Marks the library as a built-in runtime library (vs. user-installed). */ + isBuiltin?: boolean; + /** Compile-time integer constants the library's ST sources reference + * (e.g. OSCAT's STRING_LENGTH and LIST_LENGTH). Forwarded to + * compileStlib's `globalConstants` option. */ + globalConstants?: Record; + /** Path (relative to the library's source directory) to a CODESYS + * binary library file (.lib for V2.3, .library for V3) that the build + * script should run through the codesys-importer instead of compiling + * hand-authored .st files. When set, the lib's source directory should + * not contain .st files — the importer produces them at build time. */ + codesysSource?: string; + /** Block-level documentation, keyed by FB name. */ + blocks?: Record; + /** Function-level documentation, keyed by function name. */ + functions?: Record; +} + +/** + * Read the `library.json` sitting at `/library.json`. Returns + * `null` if the file is absent — callers fall back to their own defaults. + * + * Throws on parse errors (malformed JSON) and on schema violations + * (missing required fields, wrong type) so build failures are loud and + * pinpoint the misconfigured file. + */ +export function loadLibraryConfig(sourcesDir: string): LibraryConfig | null { + const path = resolve(sourcesDir, "library.json"); + if (!existsSync(path)) return null; + + let raw: unknown; + try { + raw = JSON.parse(readFileSync(path, "utf-8")); + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + throw new Error(`${path}: invalid JSON — ${msg}`); + } + + return validateLibraryConfig(raw, path); +} + +function validateLibraryConfig(raw: unknown, path: string): LibraryConfig { + if (typeof raw !== "object" || raw === null) { + throw new Error(`${path}: top-level value must be an object`); + } + const obj = raw as Record; + for (const required of ["name", "version", "namespace"]) { + if (typeof obj[required] !== "string" || obj[required] === "") { + throw new Error(`${path}: missing or non-string field "${required}"`); + } + } + + const config: LibraryConfig = { + name: obj.name as string, + version: obj.version as string, + namespace: obj.namespace as string, + }; + if (typeof obj.displayName === "string") config.displayName = obj.displayName; + if (typeof obj.description === "string") config.description = obj.description; + if (typeof obj.isBuiltin === "boolean") config.isBuiltin = obj.isBuiltin; + if (typeof obj.codesysSource === "string") + config.codesysSource = obj.codesysSource; + + if (obj.globalConstants !== undefined) { + config.globalConstants = validateGlobalConstants(obj.globalConstants, path); + } + if (obj.blocks !== undefined) { + config.blocks = validateDocMap(obj.blocks, "blocks", path); + } + if (obj.functions !== undefined) { + config.functions = validateDocMap(obj.functions, "functions", path); + } + return config; +} + +function validateGlobalConstants( + value: unknown, + path: string, +): Record { + if (typeof value !== "object" || value === null || Array.isArray(value)) { + throw new Error(`${path}: "globalConstants" must be an object map`); + } + const out: Record = {}; + for (const [key, v] of Object.entries(value as Record)) { + if (typeof v !== "number" || !Number.isFinite(v)) { + throw new Error( + `${path}: globalConstants["${key}"] must be a finite number`, + ); + } + out[key] = v; + } + return out; +} + +function validateDocMap( + value: unknown, + field: string, + path: string, +): Record { + if (typeof value !== "object" || value === null || Array.isArray(value)) { + throw new Error(`${path}: "${field}" must be an object map`); + } + const map = value as Record; + const out: Record = {}; + for (const [name, entry] of Object.entries(map)) { + if (typeof entry !== "object" || entry === null || Array.isArray(entry)) { + throw new Error( + `${path}: ${field}["${name}"] must be an object with a "documentation" field`, + ); + } + const entryObj = entry as Record; + if (typeof entryObj.documentation !== "string") { + throw new Error( + `${path}: ${field}["${name}"].documentation must be a string`, + ); + } + out[name] = { documentation: entryObj.documentation }; + } + return out; +} + +/** + * Result of merging documentation into a compiled archive. + * `unknownBlockDocs` / `unknownFunctionDocs` carry names that appeared + * in `library.json` but don't exist in the compiled manifest — usually + * a typo or a stale entry left behind when an FB was renamed. Build + * scripts should treat this as a hard error. + */ +export interface ApplyDocumentationResult { + /** Number of FBs that received documentation. */ + blocksDocumented: number; + /** Number of functions that received documentation. */ + functionsDocumented: number; + /** Block names doc'd in library.json but absent from the manifest. */ + unknownBlockDocs: string[]; + /** Function names doc'd in library.json but absent from the manifest. */ + unknownFunctionDocs: string[]; +} + +/** + * Merge `LibraryConfig.blocks` and `.functions` documentation into the + * compiled archive's manifest, in place. Returns a report of what was + * applied and what was unmatched so the caller can fail the build on + * mismatch. + * + * Names are matched case-sensitively — STruC++ FB / function names are + * uppercased by the parser before they reach the manifest, so the + * library.json keys must use the same casing the source declares. + */ +export function applyLibraryConfigDocumentation( + archive: StlibArchive, + config: LibraryConfig, +): ApplyDocumentationResult { + const result: ApplyDocumentationResult = { + blocksDocumented: 0, + functionsDocumented: 0, + unknownBlockDocs: [], + unknownFunctionDocs: [], + }; + + if (config.blocks) { + const fbByName = new Map( + archive.manifest.functionBlocks.map((fb) => [fb.name, fb]), + ); + for (const [name, entry] of Object.entries(config.blocks)) { + const fb = fbByName.get(name); + if (!fb) { + result.unknownBlockDocs.push(name); + continue; + } + fb.documentation = entry.documentation; + result.blocksDocumented++; + } + } + + if (config.functions) { + const fnByName = new Map( + archive.manifest.functions.map((fn) => [fn.name, fn]), + ); + for (const [name, entry] of Object.entries(config.functions)) { + const fn = fnByName.get(name); + if (!fn) { + result.unknownFunctionDocs.push(name); + continue; + } + fn.documentation = entry.documentation; + result.functionsDocumented++; + } + } + + return result; +} diff --git a/src/library/library-loader.ts b/src/library/library-loader.ts index 37cc008..1996d8e 100644 --- a/src/library/library-loader.ts +++ b/src/library/library-loader.ts @@ -425,17 +425,12 @@ export function loadStlibArchive(json: unknown): StlibArchive { } const manifest = loadLibraryManifest(obj.manifest); - // Validate headerCode - if (typeof obj.headerCode !== "string") { + // Validate chunks — every per-symbol slice of the library's emitted + // C++ output, plus its dep edges. Empty array is valid (synthetic + // libraries like iec-std-functions ship only symbol-table entries). + if (!Array.isArray(obj.chunks)) { throw new LibraryManifestError( - "Invalid stlib archive: 'headerCode' must be a string", - ); - } - - // Validate cppCode - if (typeof obj.cppCode !== "string") { - throw new LibraryManifestError( - "Invalid stlib archive: 'cppCode' must be a string", + "Invalid stlib archive: 'chunks' must be an array", ); } @@ -449,8 +444,7 @@ export function loadStlibArchive(json: unknown): StlibArchive { const archive: StlibArchive = { formatVersion: 1, manifest, - headerCode: obj.headerCode, - cppCode: obj.cppCode, + chunks: obj.chunks as StlibArchive["chunks"], dependencies: obj.dependencies as Array<{ name: string; version: string }>, }; diff --git a/src/library/library-manifest.ts b/src/library/library-manifest.ts index 5165d59..10cd681 100644 --- a/src/library/library-manifest.ts +++ b/src/library/library-manifest.ts @@ -9,11 +9,21 @@ /** * Library function entry in a manifest. + * + * Parameter and return types are stored as bare type names (`"INT"`, + * `"ANY_NUM"`, etc.). Generic types like `ANY_NUM` / `ANY_INT` / + * `ANY_REAL` / `ANY_BIT` / `ANY_STRING` / `ANY_ELEMENTARY` / `ANY` are + * IEC 61131-3 type categories — when they appear in this entry the + * tooling must unify identically-named generics across params and + * return type to find a concrete type at instantiation. The strucpp + * synthetic `iec-std-functions.stlib` (built from `StdFunctionRegistry`) + * uses these directly; library compilers for ordinary .st sources only + * emit concrete IEC type names. */ export interface LibraryFunctionEntry { /** Function name */ name: string; - /** Return type name */ + /** Return type name (concrete IEC type or generic — see above) */ returnType: string; /** Parameter list */ parameters: Array<{ @@ -21,6 +31,26 @@ export interface LibraryFunctionEntry { type: string; direction: "input" | "output" | "inout"; }>; + /** Variadic call shape. When set, `parameters` describes the leading + * required parameters and the function accepts any number of + * additional arguments matching the LAST parameter's type. `minArgs` + * is the minimum total argument count (typically `parameters.length` + * for variadic-after-required, e.g. `ADD(IN1, IN2, …)` has 2 declared + * params and minArgs=2). Only used by tooling to validate call sites + * / render extensible blocks; codegen reads it from compiler-internal + * metadata directly. */ + variadic?: { minArgs: number }; + /** Function-level help text shown in editor hover dialogs. Authored + * in the library's `library.json` and merged into the manifest at + * build time (see scripts/generate-*.mjs). */ + documentation?: string; + /** Folder path within the library, slash-separated (e.g. "POUs/Time&Date"). + * Empty/undefined means the entry lives at the root. Hierarchy is + * metadata-only — codegen is unaffected. The disk source layout, + * imported library folder structure, or any future tooling-driven + * organization populates this; consumers (editor library trees, + * decompile-to-folder extraction) read it back. */ + category?: string; } /** @@ -53,6 +83,13 @@ export interface LibraryFBEntry { outputs: LibraryVarType[]; /** In-out variables */ inouts: LibraryVarType[]; + /** Block-level help text shown in editor hover dialogs. Authored in + * the library's `library.json` and merged into the manifest at build + * time (see scripts/generate-*.mjs). Optional so existing archives + * without docs still load. */ + documentation?: string; + /** Folder path within the library — see `LibraryFunctionEntry.category`. */ + category?: string; } /** @@ -65,14 +102,27 @@ export interface LibraryTypeEntry { kind: "struct" | "enum" | "alias"; /** Base type (for alias/enum) */ baseType?: string; + /** Type-level help text — same lifecycle as `LibraryFBEntry.documentation`, + * populated automatically from the structured doc-block slot in CODESYS + * imports (typically the type's revision-history comment for OSCAT) and + * overridable via `library.json`. */ + documentation?: string; + /** Folder path within the library — see `LibraryFunctionEntry.category`. */ + category?: string; } /** * Library manifest describing a compiled library's public interface. */ export interface LibraryManifest { - /** Library name */ + /** Library name (kebab-case identifier; matches the .stlib filename + * and is what dependency declarations reference). */ name: string; + /** Optional human-readable label for tooling that surfaces libraries + * to end users (editor library trees, package managers). When unset, + * consumers fall back to `name`. Authored in `library.json` and + * carried unchanged through compile. */ + displayName?: string; /** Library version */ version: string; /** Human-readable description */ @@ -93,6 +143,68 @@ export interface LibraryManifest { sourceFiles?: string[]; } +/** + * Reference to another symbol from a library chunk's dep graph. + * + * Recorded by the library compiler when it scans a chunk's body for + * cross-symbol references. Codegen walks these edges to compute the + * reachable-from-the-user's-AST closure and only emit those chunks. + */ +export interface LibraryChunkDep { + /** Owning archive name (matches `LibraryManifest.name`). The library + * compiler resolves edges at compile time, so this is always the + * actual archive name — including for same-archive deps (no `"this"` + * sentinel). Consumers can index every dep through the + * symbol→archive map without a separate normalisation step. */ + library: string; + /** Referenced symbol's uppercase name (matches `LibraryChunk.name` + * in the target archive). */ + name: string; +} + +/** + * Per-symbol chunk in a compiled library. + * + * One chunk per top-level declaration: function, function block, type + * (struct/enum/alias group), or inline global. `header` + `cpp` + * concatenated in chunk-array order reproduce the legacy library-wide + * header/cpp blobs — the chunked form is a refinement, not a rewrite, + * of what the codegen used to emit as one chunk per library. + * + * The chunks-and-deps representation is what enables function-level + * tree-shaking: codegen walks the user's AST, seeds the closure with + * referenced names, BFS-traverses `deps`, then emits only the chunks + * in the closure. Symbols that no reachable chunk depends on never + * appear in the user's `generated.hpp`/`generated.cpp`. + */ +export interface LibraryChunk { + /** Symbol name (uppercase). Matches an entry in + * `manifest.functions`, `manifest.functionBlocks`, `manifest.types`, + * or names an inline global owned by this library. */ + name: string; + /** Top-level kind. Drives forward-decl ordering during emission + * (function blocks need forward decls so circular FB-to-FB + * references resolve; types and functions don't). */ + kind: "function" | "functionBlock" | "type" | "inlineGlobal"; + /** Slice of this library's emitted header code that declares this + * symbol — class declaration, struct body, function prototype, or + * inline-global definition — plus any same-line `using IEC_X = X;` + * alias that conventionally accompanies it. Concatenating every + * chunk's `header` in array order reproduces the legacy + * library-wide `headerCode` blob byte-for-byte. */ + header: string; + /** Slice of this library's emitted cpp code that implements this + * symbol — constructor + `operator()` bodies for FBs, function + * bodies for free functions. Empty string for types and inline + * globals whose entire materialisation lives in `header`. */ + cpp: string; + /** Symbols this chunk references in its body. Same-archive entries + * use `library: "this"`; cross-archive entries name the owning + * archive's `manifest.name`. The codegen treats these as edges + * in the chunk-reachability graph. */ + deps: LibraryChunkDep[]; +} + /** * Result of compiling a library. */ @@ -105,24 +217,45 @@ export interface LibraryCompileResult { headerCode: string; /** Generated C++ implementation */ cppCode: string; + /** Per-symbol chunks. Populated from Phase 2 onward; Phase 1 ships + * the type definition only so consumers can be migrated + * incrementally. When non-empty, concatenating chunks in array + * order reproduces `headerCode` / `cppCode`. */ + chunks?: LibraryChunk[]; /** Compilation errors */ errors: Array<{ message: string; file?: string; line?: number }>; } /** * Single-file `.stlib` archive format containing metadata + compiled C++ code. + * + * Emission to a consumer is per-symbol via `chunks` — the codegen + * tree-shake walks the user's AST and emits only reachable chunks + * into the final `generated.hpp` / `generated.cpp`. There is no + * library-wide blob field: the legacy `headerCode` / `cppCode` were + * retired in Phase 4 of the function-level tree-shaking work. */ export interface StlibArchive { /** Format version for forward compatibility */ formatVersion: 1; /** Library metadata (function/FB/type signatures for symbol registration) */ manifest: LibraryManifest; - /** Compiled C++ declarations (namespace body only — no includes/pragma/wrapper) */ - headerCode: string; - /** Compiled C++ implementations (namespace body only) */ - cppCode: string; - /** Original ST source files (omitted for closed-source distribution) */ - sources?: Array<{ fileName: string; source: string }>; + /** Per-symbol chunks. One entry per top-level declaration emitted + * by the library compiler: function, function block, type, or + * inline global. Each chunk owns its header/cpp slices plus the + * dep edges to other chunks (in this archive or any declared dep). + * Empty for synthetic libraries that bypass `compileLibrary` + * (e.g. `iec-std-functions` is built from the std-function registry + * and contributes only symbol-table entries, no C++ output). */ + chunks: LibraryChunk[]; + /** Original ST source files (omitted for closed-source distribution). + * `category` mirrors the manifest entry category for the POUs declared + * in this file so `--decompile-lib` can recreate the folder hierarchy + * on disk without re-parsing the source. Sources that span multiple + * POUs (e.g. iec-standard-fb's counter.st) all share one category by + * construction — every POU declared in the same file came from the + * same input folder. */ + sources?: Array<{ fileName: string; source: string; category?: string }>; /** Global constants required by this library (e.g., STRING_LENGTH, LIST_LENGTH) */ globalConstants?: Record; /** Reserved for future library-to-library dependency resolution */ diff --git a/src/library/library-utils.ts b/src/library/library-utils.ts index 4a693bd..f4130e0 100644 --- a/src/library/library-utils.ts +++ b/src/library/library-utils.ts @@ -56,57 +56,6 @@ export function extractNamespaceBody(code: string): string { return bodyLines.join("\n"); } -/** - * Strip library preamble sections from extracted namespace body code. - * Used by `compileStlib()` to remove dependency code that would otherwise - * be baked into the archive — consumers load dependencies separately. - * - * Each dependency's headerCode/cppCode is known exactly, so we build a - * set of lines to skip and match them against the `// Library: ` - * marked section. - */ -export function stripDependencyPreambles( - code: string, - dependencyNames: Set, - /** Map of dependency name → the exact preamble lines injected by codegen */ - preambleLines: Map>, -): string { - if (dependencyNames.size === 0) return code; - - const lines = code.split("\n"); - const result: string[] = []; - let currentDepPreamble: Set | null = null; - - for (const line of lines) { - const match = line.match(/^\/\/ Library: (.+)$/); - if (match) { - const name = match[1]!; - if (dependencyNames.has(name)) { - // Start skipping this dependency's preamble section - currentDepPreamble = preambleLines.get(name) ?? null; - continue; - } else { - currentDepPreamble = null; - } - } - - if (currentDepPreamble !== null) { - // Skip lines that belong to the dependency's preamble. - // We check membership to handle the case where codegen adds - // blank lines around the preamble content. - if (line.trim() === "" || currentDepPreamble.has(line)) { - continue; - } - // Non-matching line means we've exited the preamble section - currentDepPreamble = null; - } - - result.push(line); - } - - return result.join("\n"); -} - /** * Recursively discover all `.st` and `.il` files in a directory. * diff --git a/src/project-model.ts b/src/project-model.ts index e5bd5c2..e5521ca 100644 --- a/src/project-model.ts +++ b/src/project-model.ts @@ -238,6 +238,80 @@ export interface ProjectModelResult { * Parse a TIME literal string to nanoseconds. * Supports formats like T#20ms, T#1s, T#100us, TIME#1h2m3s, etc. */ +/** + * Parse an IEC 61131-3 DATE literal (`D#YYYY-MM-DD` / + * `DATE#YYYY-MM-DD`) into nanoseconds since the Unix epoch (UTC). + * Strucpp's runtime stores DATE as int64 nanoseconds, the same wire + * shape as DT — DATE just truncates the time-of-day component to + * 00:00:00. Returns 0 (Unix epoch) for any unparsable input rather + * than throwing, mirroring `parseTimeLiteral`. + */ +export function parseDateLiteralToNs(literal: string): bigint { + const stripped = literal.replace(/^(D|DATE)#/i, ""); + const m = stripped.match(/^(\d{4})-(\d{2})-(\d{2})$/); + if (!m) return 0n; + const ms = Date.UTC(Number(m[1]), Number(m[2]) - 1, Number(m[3])); + return BigInt(ms) * 1_000_000n; +} + +/** + * Parse an IEC TIME_OF_DAY literal (`TOD#HH:MM:SS[.fff]` / + * `TIME_OF_DAY#…`) into nanoseconds since midnight. The optional + * fractional-seconds tail is treated as a decimal fraction of a + * second, capped at sub-nanosecond precision (extra digits beyond + * 9 are truncated, not rounded — there's no IEC-standardised + * rounding mode). Returns 0 for unparsable input. + */ +export function parseTodLiteralToNs(literal: string): bigint { + const stripped = literal.replace(/^(TOD|TIME_OF_DAY)#/i, ""); + const m = stripped.match(/^(\d{1,2}):(\d{1,2})(?::(\d{1,2})(?:\.(\d+))?)?$/); + if (!m) return 0n; + const hh = m[1] ?? "0"; + const mm = m[2] ?? "0"; + const ss = m[3] ?? "0"; + const frac = m[4] ?? ""; + const NS_PER_SEC = 1_000_000_000n; + const NS_PER_MIN = 60n * NS_PER_SEC; + const NS_PER_HOUR = 60n * NS_PER_MIN; + const fracPadded = (frac + "000000000").slice(0, 9); + return ( + BigInt(hh) * NS_PER_HOUR + + BigInt(mm) * NS_PER_MIN + + BigInt(ss) * NS_PER_SEC + + BigInt(fracPadded || "0") + ); +} + +/** + * Parse an IEC DATE_AND_TIME literal (`DT#YYYY-MM-DD-HH:MM:SS[.fff]` + * / `DATE_AND_TIME#…`) into nanoseconds since the Unix epoch (UTC). + * Returns 0 for unparsable input. + */ +export function parseDtLiteralToNs(literal: string): bigint { + const stripped = literal.replace(/^(DT|DATE_AND_TIME)#/i, ""); + const m = stripped.match( + /^(\d{4})-(\d{2})-(\d{2})-(\d{1,2}):(\d{1,2})(?::(\d{1,2})(?:\.(\d+))?)?$/, + ); + if (!m) return 0n; + const y = m[1] ?? "0"; + const mo = m[2] ?? "0"; + const d = m[3] ?? "0"; + const hh = m[4] ?? "0"; + const mm = m[5] ?? "0"; + const ss = m[6] ?? "0"; + const frac = m[7] ?? ""; + const ms = Date.UTC( + Number(y), + Number(mo) - 1, + Number(d), + Number(hh), + Number(mm), + Number(ss), + ); + const fracPadded = (frac + "000000000").slice(0, 9); + return BigInt(ms) * 1_000_000n + BigInt(fracPadded || "0"); +} + export function parseTimeLiteral(literal: string): TimeValue { const rawValue = literal; let nanoseconds = 0; diff --git a/src/runtime/include/iec_std_lib.hpp b/src/runtime/include/iec_std_lib.hpp index 1deab29..13abef4 100644 --- a/src/runtime/include/iec_std_lib.hpp +++ b/src/runtime/include/iec_std_lib.hpp @@ -24,8 +24,11 @@ #include "iec_traits.hpp" #include "iec_retain.hpp" #include "iec_ptr.hpp" +#include "iec_string.hpp" +#include "iec_wstring.hpp" #include #include +#include #include #include #include @@ -667,6 +670,72 @@ template inline IEC_TOD TO_TOD(T v) noexcept { return IEC_TOD(static_cast(iec_unwrap(v))); } +// ============================================================================= +// String / Wide String Conversion +// ============================================================================= +// +// STRING ↔ WSTRING per IEC 61131-3 §6.5.4.6: codepoint-by-codepoint +// transcoding. Anything outside the BMP would require surrogate +// handling that the runtime does not implement; OpenPLC programs in +// practice deal in 7-bit ASCII or simple Latin-1, so a lossy narrow +// (truncate the high byte) is documented behaviour rather than a +// surprise. Callers that need full Unicode round-tripping should keep +// data in WSTRING throughout. + +template +inline IECWString STRING_TO_WSTRING(const IECString& src) noexcept { + IECWString result; + const size_t n = src.length(); + for (size_t i = 0; i < n; ++i) { + // Treat each STRING byte as a codepoint in the U+0000–U+00FF + // range. Multi-byte UTF-8 sequences pass through byte-for-byte + // and end up as Latin-1 — wrong for non-ASCII, but the IEC + // standard doesn't define UTF-8/UTF-16 transcoding either. + result.append(static_cast(static_cast(src[i]))); + } + return result; +} + +// Overload for the per-variable wrapper (handles auto-unwrap). +template +inline IECWString STRING_TO_WSTRING(const IECStringVar& src) noexcept { + return STRING_TO_WSTRING(iec_unwrap(src)); +} + +template +inline IECString WSTRING_TO_STRING(const IECWString& src) noexcept { + IECString result; + const size_t n = src.length(); + for (size_t i = 0; i < n; ++i) { + // Truncate to the low byte. Codepoints > U+00FF lose + // information; surrogate pairs (rare in IEC programs) collapse + // to garbage. Document as "ASCII / Latin-1 only" round-trip. + result.append(static_cast(src[i] & 0xFF)); + } + return result; +} + +template +inline IECString WSTRING_TO_STRING(const IECWStringVar& src) noexcept { + return WSTRING_TO_STRING(iec_unwrap(src)); +} + +// `*_TO_*` resolution in the frontend collapses STRING_TO_WSTRING / +// WSTRING_TO_STRING to plain TO_WSTRING / TO_STRING calls (cppName is +// `TO_${toType}`), so provide the matching aliases. Templated on the +// source type so they bind to either the bare class or the *Var +// wrapper without relying on conversions. + +template +inline auto TO_WSTRING(const T& src) noexcept -> decltype(STRING_TO_WSTRING(src)) { + return STRING_TO_WSTRING(src); +} + +template +inline auto TO_STRING(const T& src) noexcept -> decltype(WSTRING_TO_STRING(src)) { + return WSTRING_TO_STRING(src); +} + // ============================================================================= // Time Utilities // ============================================================================= @@ -1043,6 +1112,72 @@ inline IEC_TIME TIME() { return IEC_TIME(static_cast(__CURRENT_TIME_NS)); } +/** + * Wall-clock date-and-time override slot, in nanoseconds since the + * Unix epoch. + * + * Platform integrations that *can* deliver real wall-clock time + * (VPP packages with a DS3231 RTC chip wired up, Wi-Fi targets that + * pull NTP, etc.) populate this before each scan and CURRENT_DT() + * returns it verbatim. Targets without that capability leave it at 0 + * and CURRENT_DT() falls back to a meaningful-but-not-wall-clock + * value — see the function comment for the full priority order. + */ +inline int64_t __CURRENT_DT_NS = 0; + +/** + * CURRENT_DT() — wall-clock date-and-time. + * + * Returns the current absolute time as IEC_DT (nanoseconds since the + * Unix epoch). Distinct from TIME() which returns the scan-cycle's + * monotonic elapsed time, not a date. + * + * Used by the Additional Function Blocks library's RTC FB, which under + * MatIEC consumed a `__CURRENT_TIME` global the runtime injected before + * each scan. STruC++ exposes the same capability through this regular + * function so RTC's body can call it without compiler-specific pragmas. + * + * Resolution priority (highest first): + * 1. `__CURRENT_DT_NS` when non-zero — the platform integration + * delivered a real wall-clock value (RTC chip, NTP, host syscall + * wired by an OpenPLC v4 runtime, etc.). Honoured on every + * target. + * 2. std::chrono::system_clock on hosted targets — covers REPL, test + * runner, and any g++ build that didn't populate + * `__CURRENT_DT_NS`. Inherits CLOCK_REALTIME's quirks (can step + * backwards if the system clock is corrected); code needing + * strict monotonicity should use TIME() instead. + * 3. `__CURRENT_TIME_NS` (time since program start) on bare-metal + * targets where std::chrono::system_clock isn't available. + * avr-gcc's libstdc++ ships `` but omits `system_clock`, + * so we can't reach for it on Arduino / AVR. Returning uptime + * keeps the IEC_DT value monotonically advancing — programs that + * diff two CURRENT_DT() readings still see meaningful elapsed + * time, just expressed in seconds-since-boot rather than seconds- + * since-1970. + * + * VPP packages targeting hardware with an RTC override (1) by writing + * `__CURRENT_DT_NS` from their platform glue. Nothing else in the + * runtime needs to change to enable that path. + */ +inline IEC_DT CURRENT_DT() { + if (__CURRENT_DT_NS != 0) { + return IEC_DT(static_cast(__CURRENT_DT_NS)); + } +#ifdef __AVR__ + // No system_clock on avr-gcc. `__CURRENT_TIME_NS` advances + // monotonically as the runtime drives the scan cycle, giving us + // time-since-boot — meaningful for diffing timestamps even when + // no RTC is wired up. + return IEC_DT(static_cast(__CURRENT_TIME_NS)); +#else + using namespace std::chrono; + auto now = system_clock::now(); + auto ns = duration_cast(now.time_since_epoch()).count(); + return IEC_DT(static_cast(ns)); +#endif +} + // ============================================================================= // CODESYS System Functions // ============================================================================= diff --git a/src/semantic/iec-types-data.ts b/src/semantic/iec-types-data.ts new file mode 100644 index 0000000..d62764e --- /dev/null +++ b/src/semantic/iec-types-data.ts @@ -0,0 +1,377 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (C) 2025 Autonomy / OpenPLC Project +/** + * STruC++ Canonical IEC Base Type Metadata + * + * Single source of truth for every IEC 61131-3 elementary type strucpp + * recognizes. Every other consumer — strucpp's own type-checker / + * codegen, the OpenPLC Editor's variables table / debugger / XML + * emitter, future tooling — derives its type knowledge from this list + * (or, for external repos, from the `libs/iec-types.json` artifact this + * file is built into). + * + * Adding a new elementary type goes here first, then a downstream + * artifact rebuild (`npm run build`) refreshes `libs/iec-types.json`. + * + * Aliases (TIME_OF_DAY/TOD, DATE_AND_TIME/DT) are listed under their + * canonical entry rather than getting their own row. The parser + * accepts either spelling; everything downstream sees only canonical + * names. + */ + +/** + * Wire format identifier — keys a small dispatcher in editor runtime + * tooling that maps a strucpp type to byte-decoding (debugger watch + * panel) and byte-encoding (force value) logic. Adding a new format + * here means handling it on both ends; that's intentional friction. + */ +export type IECWireFormat = + | "bool" + | "int8" + | "uint8" + | "int16" + | "uint16" + | "int32" + | "uint32" + | "int64" + | "uint64" + | "float32" + | "float64" + /** TIME — int64 nanoseconds duration, formatted as `T#…` */ + | "duration-ns-i64" + /** DT — int64 nanoseconds since Unix epoch, formatted as `DT#…` */ + | "datetime-ns-i64" + /** DATE — int64 nanoseconds since Unix epoch (date portion only), + * formatted as `D#YYYY-MM-DD` */ + | "date-ns-i64" + /** TOD — int64 nanoseconds since midnight, formatted as `TOD#…` */ + | "tod-ns-i64" + /** STRING — 1 length byte + 126 UTF-8 bytes (strucpp default cap). */ + | "len8-utf8" + /** WSTRING — 1 length byte + 126 UTF-16 LE code units. */ + | "len8-utf16le"; + +/** + * Single elementary type entry. Keep field order stable — it's what + * gets serialised into `libs/iec-types.json` for downstream consumers. + */ +export interface IECTypeMetadata { + /** Canonical IEC 61131-3 name (uppercase). */ + name: string; + /** Alternate names the parser accepts as the same type. Empty if + * the canonical name is the only spelling. */ + aliases: readonly string[]; + /** Byte width on the wire / in memory. `0` for variable-width + * string types (where the actual width is determined by the + * STRING_LENGTH global constant or per-declaration override). */ + byteSize: number; + /** Logical IEC bit width — equals `byteSize * 8` for every type + * except BOOL, which is `1` bit logically but stored as a single + * byte on the wire (`byteSize: 1`). `0` for variable-width strings. + * + * Type-checker widening / compatibility rules read this rather + * than `byteSize` so a SINT-into-BOOL coercion (8 logical bits to + * 1) gets caught the same way the IEC spec calls it out. */ + bits: number; + /** True ⇒ signed integer / IEC duration. False ⇒ unsigned. `null` + * for non-numeric types (BOOL, STRING, WSTRING). */ + signed: boolean | null; + /** C++ type alias from `runtime/include/iec_types.hpp`. Generated + * code emits `strucpp::` for variables of this type. */ + cppType: string; + /** Wire format identifier — see {@link IECWireFormat}. */ + wireFormat: IECWireFormat; + /** PLCopen TC6 v0201 XML mapping. */ + xml: { + /** Element name in PLCopen TC6 wire shape. Lowercase for + * parameterized types (`string`, `wstring`), uppercase + * otherwise. Editors should emit `` for + * PLCopen-standard types and `` for + * everything else. */ + elementName: string; + /** True iff this type is in the PLCopen TC6 XSD elementaryTypes + * group (a closed ``, no extension allowed). False ⇒ + * emit `` instead. */ + plcopenStandard: boolean; + }; + /** Hint for editors / pretty-printers showing literals of this + * type. Optional — only set where it's specific enough to be + * useful (e.g. `"TRUE/FALSE"` for BOOL, `"T#1d2h3m"` for TIME). */ + literalDisplay?: string; +} + +/** + * The full set of strucpp-recognised IEC 61131-3 elementary types. + * + * Order is intentional: groups bit-strings, signed ints, unsigned + * ints, reals, time/date, strings — same flow as the IEC standard + * tables and the iec_types.hpp typedef order. Editors that surface + * this as a dropdown should preserve the order for user familiarity. + */ +export const IEC_BASE_TYPES: readonly IECTypeMetadata[] = [ + // ── Bit strings ────────────────────────────────────────────────── + { + name: "BOOL", + aliases: [], + byteSize: 1, + bits: 1, + signed: null, + cppType: "BOOL_t", + wireFormat: "bool", + xml: { elementName: "BOOL", plcopenStandard: true }, + literalDisplay: "TRUE/FALSE", + }, + { + name: "BYTE", + aliases: [], + byteSize: 1, + bits: 8, + signed: false, + cppType: "BYTE_t", + wireFormat: "uint8", + xml: { elementName: "BYTE", plcopenStandard: true }, + }, + { + name: "WORD", + aliases: [], + byteSize: 2, + bits: 16, + signed: false, + cppType: "WORD_t", + wireFormat: "uint16", + xml: { elementName: "WORD", plcopenStandard: true }, + }, + { + name: "DWORD", + aliases: [], + byteSize: 4, + bits: 32, + signed: false, + cppType: "DWORD_t", + wireFormat: "uint32", + xml: { elementName: "DWORD", plcopenStandard: true }, + }, + { + name: "LWORD", + aliases: [], + byteSize: 8, + bits: 64, + signed: false, + cppType: "LWORD_t", + wireFormat: "uint64", + xml: { elementName: "LWORD", plcopenStandard: true }, + }, + + // ── Signed integers ────────────────────────────────────────────── + { + name: "SINT", + aliases: [], + byteSize: 1, + bits: 8, + signed: true, + cppType: "SINT_t", + wireFormat: "int8", + xml: { elementName: "SINT", plcopenStandard: true }, + }, + { + name: "INT", + aliases: [], + byteSize: 2, + bits: 16, + signed: true, + cppType: "INT_t", + wireFormat: "int16", + xml: { elementName: "INT", plcopenStandard: true }, + }, + { + name: "DINT", + aliases: [], + byteSize: 4, + bits: 32, + signed: true, + cppType: "DINT_t", + wireFormat: "int32", + xml: { elementName: "DINT", plcopenStandard: true }, + }, + { + name: "LINT", + aliases: [], + byteSize: 8, + bits: 64, + signed: true, + cppType: "LINT_t", + wireFormat: "int64", + xml: { elementName: "LINT", plcopenStandard: true }, + }, + + // ── Unsigned integers ──────────────────────────────────────────── + { + name: "USINT", + aliases: [], + byteSize: 1, + bits: 8, + signed: false, + cppType: "USINT_t", + wireFormat: "uint8", + xml: { elementName: "USINT", plcopenStandard: true }, + }, + { + name: "UINT", + aliases: [], + byteSize: 2, + bits: 16, + signed: false, + cppType: "UINT_t", + wireFormat: "uint16", + xml: { elementName: "UINT", plcopenStandard: true }, + }, + { + name: "UDINT", + aliases: [], + byteSize: 4, + bits: 32, + signed: false, + cppType: "UDINT_t", + wireFormat: "uint32", + xml: { elementName: "UDINT", plcopenStandard: true }, + }, + { + name: "ULINT", + aliases: [], + byteSize: 8, + bits: 64, + signed: false, + cppType: "ULINT_t", + wireFormat: "uint64", + xml: { elementName: "ULINT", plcopenStandard: true }, + }, + + // ── Real numbers ───────────────────────────────────────────────── + { + name: "REAL", + aliases: [], + byteSize: 4, + bits: 32, + signed: true, + cppType: "REAL_t", + wireFormat: "float32", + xml: { elementName: "REAL", plcopenStandard: true }, + }, + { + name: "LREAL", + aliases: [], + byteSize: 8, + bits: 64, + signed: true, + cppType: "LREAL_t", + wireFormat: "float64", + xml: { elementName: "LREAL", plcopenStandard: true }, + }, + + // ── Time and date ──────────────────────────────────────────────── + { + name: "TIME", + aliases: [], + byteSize: 8, + bits: 64, + signed: true, + cppType: "TIME_t", + wireFormat: "duration-ns-i64", + xml: { elementName: "TIME", plcopenStandard: true }, + literalDisplay: "T#1d2h3m", + }, + { + name: "DATE", + aliases: [], + byteSize: 8, + bits: 64, + signed: true, + cppType: "DATE_t", + wireFormat: "date-ns-i64", + xml: { elementName: "DATE", plcopenStandard: true }, + literalDisplay: "D#YYYY-MM-DD", + }, + { + name: "TOD", + aliases: ["TIME_OF_DAY"], + byteSize: 8, + bits: 64, + signed: true, + cppType: "TOD_t", + wireFormat: "tod-ns-i64", + xml: { elementName: "TOD", plcopenStandard: true }, + literalDisplay: "TOD#HH:MM:SS", + }, + { + name: "DT", + aliases: ["DATE_AND_TIME"], + byteSize: 8, + bits: 64, + signed: true, + cppType: "DT_t", + wireFormat: "datetime-ns-i64", + xml: { elementName: "DT", plcopenStandard: true }, + literalDisplay: "DT#YYYY-MM-DD-HH:MM:SS", + }, + + // ── Character strings ──────────────────────────────────────────── + // byteSize 0 ⇒ variable-width on the wire (the per-declaration cap + // or the library's STRING_LENGTH constant decides the actual width). + { + name: "STRING", + aliases: [], + byteSize: 0, + bits: 0, + signed: null, + cppType: "IECString", + wireFormat: "len8-utf8", + // PLCopen TC6 ships `string` lowercase and parameterized — see + // the `` schema entry. The element name is + // normalised here; downstream emitters can append `length=` when + // a per-declaration cap exists. + xml: { elementName: "string", plcopenStandard: true }, + literalDisplay: "'text'", + }, + { + name: "WSTRING", + aliases: [], + byteSize: 0, + bits: 0, + signed: null, + cppType: "IECWString", + wireFormat: "len8-utf16le", + xml: { elementName: "wstring", plcopenStandard: true }, + literalDisplay: '"text"', + }, +]; + +/** + * Lookup index keyed by the canonical name AND each alias, so callers + * can resolve either spelling to the same metadata entry without + * paying an O(n) scan per call. Built once at module load. + */ +const IEC_BASE_TYPE_INDEX: ReadonlyMap = (() => { + const m = new Map(); + for (const t of IEC_BASE_TYPES) { + m.set(t.name, t); + for (const alias of t.aliases) m.set(alias, t); + } + return m; +})(); + +/** + * Resolve a type name (canonical or alias, any case) to its metadata + * entry. Returns `undefined` for non-elementary names so callers can + * disambiguate between "elementary type unknown to strucpp" and + * "user-defined type that's expected to look unknown". + */ +export function lookupBaseType(name: string): IECTypeMetadata | undefined { + return IEC_BASE_TYPE_INDEX.get(name.toUpperCase()); +} + +/** + * Whether a name (canonical or alias) refers to an IEC elementary type. + */ +export function isBaseTypeName(name: string): boolean { + return IEC_BASE_TYPE_INDEX.has(name.toUpperCase()); +} diff --git a/src/semantic/std-function-registry.ts b/src/semantic/std-function-registry.ts index 075258c..dd992c2 100644 --- a/src/semantic/std-function-registry.ts +++ b/src/semantic/std-function-registry.ts @@ -769,6 +769,21 @@ export class StdFunctionRegistry { category: "time", }); + // CURRENT_DT() - wall-clock date-and-time as IEC_DT. + // Used by the Additional Function Blocks library's RTC FB. Distinct + // from TIME() (scan-cycle elapsed time): CURRENT_DT() is system clock. + this.register({ + name: "CURRENT_DT", + cppName: "CURRENT_DT", + returnConstraint: "specific", + returnMatchesFirstParam: false, + specificReturnType: "DT", + params: [], + isVariadic: false, + isConversion: false, + category: "time", + }); + this.register({ name: "TIME_FROM_MS", cppName: "TIME_FROM_MS", diff --git a/src/semantic/type-checker.ts b/src/semantic/type-checker.ts index 4f5ee35..086beff 100644 --- a/src/semantic/type-checker.ts +++ b/src/semantic/type-checker.ts @@ -23,6 +23,7 @@ import type { ReferenceType, CompilationUnit, Statement, + VarBlock, } from "../frontend/ast.js"; import type { SymbolTables, Scope } from "./symbol-table.js"; import type { StdFunctionRegistry } from "./std-function-registry.js"; @@ -44,6 +45,70 @@ import { stripEnEno } from "../ast-utils.js"; export { ELEMENTARY_TYPES, TYPE_CATEGORIES } from "./type-utils.js"; export type { TypeCategory } from "./type-utils.js"; +// ============================================================================= +// IEC 61131-3 date/time arithmetic helpers +// ============================================================================= + +/** True when the operand type is one of the absolute-time types. */ +function isInstantType(t: IECType): boolean { + if (t.typeKind !== "elementary") return false; + const name = (t as ElementaryType).name; + return name === "DT" || name === "DATE" || name === "TOD"; +} + +/** True when the operand type is the duration type (TIME). */ +function isDurationType(t: IECType): boolean { + if (t.typeKind !== "elementary") return false; + return (t as ElementaryType).name === "TIME"; +} + +/** True when the operand pair maps to a recognised date/time arithmetic + * rule from IEC 61131-3 §6.6.2.2 — instant minus instant, or instant + * ± duration. Anything else (DT * 2, TIME / DT, …) falls through to + * the normal arithmetic path so we don't widen the rule beyond what + * the standard sanctions. */ +function isDateTimeArithmetic( + left: IECType, + right: IECType, + op: string, +): boolean { + const leftIsInstant = isInstantType(left); + const rightIsInstant = isInstantType(right); + const leftIsTime = isDurationType(left); + const rightIsTime = isDurationType(right); + + // instant - instant → TIME (duration). Both must be the same instant + // type per the standard (DT - TOD is meaningless). + if (op === "-" && leftIsInstant && rightIsInstant) { + return (left as ElementaryType).name === (right as ElementaryType).name; + } + // instant ± duration → instant (offset) + if (leftIsInstant && rightIsTime) return true; + // duration + instant → instant (commutative addition only) + if (op === "+" && leftIsTime && rightIsInstant) return true; + return false; +} + +/** Resolves the result type for a recognised date/time arithmetic pair. + * Pre-condition: isDateTimeArithmetic returned true for the same args. */ +function resolveDateTimeArithmetic( + left: IECType, + right: IECType, + op: string, +): IECType | undefined { + const leftIsInstant = isInstantType(left); + const rightIsInstant = isInstantType(right); + + if (op === "-" && leftIsInstant && rightIsInstant) { + return ELEMENTARY_TYPES["TIME"]; + } + // instant ± duration: result keeps the instant type. + if (leftIsInstant) return left; + // duration + instant (commutative): result is the instant type. + if (rightIsInstant) return right; + return undefined; +} + // ============================================================================= // Type Checker // ============================================================================= @@ -77,6 +142,7 @@ export class TypeChecker { for (const prog of ast.programs) { const scope = this.symbolTables.getProgramScope(prog.name); if (scope) { + this.checkVarBlocks(prog.varBlocks, scope); this.checkStatements(prog.body, scope); } } @@ -85,6 +151,7 @@ export class TypeChecker { for (const func of ast.functions) { const scope = this.symbolTables.getFunctionScope(func.name); if (scope) { + this.checkVarBlocks(func.varBlocks, scope); this.checkStatements(func.body, scope); } } @@ -94,6 +161,7 @@ export class TypeChecker { const scope = this.symbolTables.getFBScope(fb.name); if (scope) { // FB body + this.checkVarBlocks(fb.varBlocks, scope); this.checkStatements(fb.body, scope); // Method bodies (use method scope for local variable resolution) @@ -102,6 +170,7 @@ export class TypeChecker { fb.name, method.name, ); + this.checkVarBlocks(method.varBlocks, methodScope ?? scope); this.checkStatements(method.body, methodScope ?? scope); } @@ -429,6 +498,23 @@ export class TypeChecker { else if (["AND", "OR", "XOR"].includes(expr.operator)) { type = ELEMENTARY_TYPES["BOOL"]; } + // IEC 61131-3 date/time arithmetic (table 30 of the standard). + // Date types are int64_t aliases at the C++ level so the operator- + // overload returns IECVar, but the *semantic* result type + // depends on the operands: + // DT/DATE/TOD - DT/DATE/TOD = TIME (duration between two instants) + // DT/DATE/TOD ± TIME = DT/DATE/TOD (instant offset) + // Without these rules the type checker collapses DT - DT to DT, + // which then refuses assignment to a TIME variable (the natural use + // of the difference). This breaks RTC-style code that captures an + // offset between two datetimes — including the Additional Function + // Blocks library's RTC FB and any user code doing date arithmetic. + else if ( + ["+", "-"].includes(expr.operator) && + isDateTimeArithmetic(leftType, rightType, expr.operator) + ) { + type = resolveDateTimeArithmetic(leftType, rightType, expr.operator); + } // Arithmetic operators return the "wider" type else if (["+", "-", "*", "/", "MOD", "**"].includes(expr.operator)) { type = getCommonType(leftType, rightType) ?? leftType; @@ -606,6 +692,45 @@ export class TypeChecker { // Statement Type Validation (Sub-Phase C) // =========================================================================== + /** + * Walk variable declarations and validate every initialiser against the + * declared type. Without this pass, nonsense like `WSTRING := 'foo'` + * (STRING literal into a WSTRING variable) reaches codegen unchecked, + * surfacing as a confusing C++ "no matching function for call to + * IECWStringVar(const char[N])" instead of a proper IEC type error + * pointing at the declaration. + * + * The check delegates to the same `validateAssignment` used for + * assignment statements — no separate compatibility rules — so anything + * the standard considers an implicit assignment also passes here. + */ + private checkVarBlocks(blocks: VarBlock[], scope: Scope): void { + for (const block of blocks) { + for (const decl of block.declarations) { + if (!decl.initialValue) continue; + const targetType = ELEMENTARY_TYPES[decl.type.name.toUpperCase()]; + if (!targetType) continue; // Non-elementary types — handled elsewhere + const valueType = this.resolveExprType(decl.initialValue, scope); + if (!valueType) continue; + this.validateAssignment( + targetType, + valueType, + // Synthetic VariableExpression for the diagnostic anchor: gives + // validateAssignment a target.name to mention in the error. + { + kind: "VariableExpression", + sourceSpan: decl.sourceSpan, + name: decl.names[0] ?? "", + fieldAccess: [], + subscripts: [], + isDereference: false, + }, + decl.initialValue, + ); + } + } + } + /** * Walk statements, resolve all sub-expressions, and validate type rules. */ diff --git a/src/semantic/type-registry.ts b/src/semantic/type-registry.ts index 292f483..d29e4b4 100644 --- a/src/semantic/type-registry.ts +++ b/src/semantic/type-registry.ts @@ -43,40 +43,18 @@ export interface ValidationWarning { message: string; } -/** - * Set of IEC 61131-3 elementary type names - */ -const ELEMENTARY_TYPES = new Set([ - "BOOL", - "BYTE", - "WORD", - "DWORD", - "LWORD", - "SINT", - "INT", - "DINT", - "LINT", - "USINT", - "UINT", - "UDINT", - "ULINT", - "REAL", - "LREAL", - "TIME", - "DATE", - "TIME_OF_DAY", - "TOD", - "DATE_AND_TIME", - "DT", - "STRING", - "WSTRING", -]); +import { isBaseTypeName } from "./iec-types-data.js"; /** * Check if a type name is an elementary type + * + * Delegates to the canonical IEC type registry + * (`./iec-types-data.ts`), which is also the source emitted as + * `libs/iec-types.json`. Single source of truth — adding a new + * elementary type happens in one place. */ export function isElementaryType(name: string): boolean { - return ELEMENTARY_TYPES.has(name.toUpperCase()); + return isBaseTypeName(name); } /** diff --git a/src/semantic/type-utils.ts b/src/semantic/type-utils.ts index e86aaa1..2df1170 100644 --- a/src/semantic/type-utils.ts +++ b/src/semantic/type-utils.ts @@ -23,45 +23,53 @@ import type { FunctionBlockType, } from "../frontend/ast.js"; import type { TypeConstraint } from "./std-function-registry.js"; +import { IEC_BASE_TYPES, lookupBaseType } from "./iec-types-data.js"; + +/** + * Map an IEC type name to its canonical spelling, collapsing aliases + * (`TIME_OF_DAY` → `TOD`, `DATE_AND_TIME` → `DT`). Returns the input + * unchanged for non-elementary names. Pure passthrough for upper-cased + * canonical names (saves the registry lookup). + * + * Used by assignability / implicit-conversion checks so callers don't + * have to remember to normalise on every comparison. + */ +export function canonicalElementaryName(name: string): string { + return lookupBaseType(name)?.name ?? name.toUpperCase(); +} // ============================================================================= // Elementary Type Data // ============================================================================= /** - * Built-in elementary types with their properties. + * Built-in elementary types as `ElementaryType` AST nodes, indexed by + * canonical name AND every alias the parser accepts. + * + * Source of truth is `IEC_BASE_TYPES` in `iec-types-data.ts` (also + * shipped as `libs/iec-types.json`). This map is just an AST-shaped + * projection: each entry borrows the `bits` field as `sizeBits` + * (the IEC logical width — `1` for BOOL, `8` for SINT, …, `0` for + * variable-width strings). + * + * Each alias gets its own row pointing at an ElementaryType whose + * name matches the alias spelling — so callers that read back + * `.name` get the same string they looked up with. */ -export const ELEMENTARY_TYPES: Record = { - BOOL: { typeKind: "elementary", name: "BOOL", sizeBits: 1 }, - BYTE: { typeKind: "elementary", name: "BYTE", sizeBits: 8 }, - WORD: { typeKind: "elementary", name: "WORD", sizeBits: 16 }, - DWORD: { typeKind: "elementary", name: "DWORD", sizeBits: 32 }, - LWORD: { typeKind: "elementary", name: "LWORD", sizeBits: 64 }, - SINT: { typeKind: "elementary", name: "SINT", sizeBits: 8 }, - INT: { typeKind: "elementary", name: "INT", sizeBits: 16 }, - DINT: { typeKind: "elementary", name: "DINT", sizeBits: 32 }, - LINT: { typeKind: "elementary", name: "LINT", sizeBits: 64 }, - USINT: { typeKind: "elementary", name: "USINT", sizeBits: 8 }, - UINT: { typeKind: "elementary", name: "UINT", sizeBits: 16 }, - UDINT: { typeKind: "elementary", name: "UDINT", sizeBits: 32 }, - ULINT: { typeKind: "elementary", name: "ULINT", sizeBits: 64 }, - REAL: { typeKind: "elementary", name: "REAL", sizeBits: 32 }, - LREAL: { typeKind: "elementary", name: "LREAL", sizeBits: 64 }, - TIME: { typeKind: "elementary", name: "TIME", sizeBits: 64 }, - DATE: { typeKind: "elementary", name: "DATE", sizeBits: 64 }, - TIME_OF_DAY: { typeKind: "elementary", name: "TIME_OF_DAY", sizeBits: 64 }, - DATE_AND_TIME: { - typeKind: "elementary", - name: "DATE_AND_TIME", - sizeBits: 64, - }, - // Aliases - TOD: { typeKind: "elementary", name: "TOD", sizeBits: 64 }, - DT: { typeKind: "elementary", name: "DT", sizeBits: 64 }, - // Variable-width string types — 0 is correct (no fixed bit width) - STRING: { typeKind: "elementary", name: "STRING", sizeBits: 0 }, - WSTRING: { typeKind: "elementary", name: "WSTRING", sizeBits: 0 }, -}; +export const ELEMENTARY_TYPES: Record = (() => { + const out: Record = {}; + for (const t of IEC_BASE_TYPES) { + out[t.name] = { typeKind: "elementary", name: t.name, sizeBits: t.bits }; + for (const alias of t.aliases) { + out[alias] = { + typeKind: "elementary", + name: alias, + sizeBits: t.bits, + }; + } + } + return out; +})(); // ============================================================================= // Type Categories @@ -247,11 +255,16 @@ export function isAssignable(target: IECType, source: IECType): boolean { const t = target as ElementaryType; const s = source as ElementaryType; - // Same type is always assignable - if (t.name === s.name) return true; + // Resolve aliases (TIME_OF_DAY ↔ TOD, DATE_AND_TIME ↔ DT) before + // comparison so the parser/AST tag form doesn't matter. + const tCanon = canonicalElementaryName(t.name); + const sCanon = canonicalElementaryName(s.name); + + // Same canonical type is always assignable + if (tCanon === sCanon) return true; // Use implicit conversion check (includes widening + cross-category) - return isImplicitlyConvertible(s.name, t.name); + return isImplicitlyConvertible(sCanon, tCanon); } // For reference types, check referenced type compatibility diff --git a/src/types.ts b/src/types.ts index 84c0568..7c56f9f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -75,6 +75,15 @@ export interface CompileOptions { * the debug map's md5 field is left empty. */ md5?: string; + + /** + * Wrap each top-level emitted declaration with + * `//@chunk:begin/end::` markers in both header and cpp + * output. The library compiler enables this so it can slice emitted + * code into per-symbol chunks for function-level tree-shaking. + * Production compiles leave it off and see no output change. + */ + emitChunkMarkers?: boolean; } /** @@ -112,6 +121,45 @@ export interface CompileError { /** Optional suggestion for fixing the error */ suggestion?: string; + + // =========================================================================== + // POU-relative location (populated post-parse when the error sits inside a + // POU strucpp parsed). Programmatic consumers like the OpenPLC Editor use + // these to surface errors in the right tab and at a line number that + // matches what the user sees. Standalone CLI use ignores them — the + // existing `line`/`column`/`file` fields are unchanged. + // =========================================================================== + + /** Containing POU name (uppercased per IEC) when known. */ + pouName?: string; + + /** Containing POU kind. */ + pouKind?: "PROGRAM" | "FUNCTION" | "FUNCTION_BLOCK"; + + /** + * Which structural section of the POU the error sits in: + * - 'var-block': inside any VAR…END_VAR block + * - 'body': in the executable body + * - 'interface': in the POU header / between sections (rare) + */ + section?: "var-block" | "body" | "interface"; + + /** + * 1-indexed line within the POU body (only set when section === 'body'). + * The OpenPLC Editor's Monaco body view starts at line 1 with the first + * body statement, so this matches what the user sees. For 'var-block' + * the editor uses `line` directly because the var block is at the top of + * the per-POU file and lines align. + */ + bodyLine?: number; + + /** + * Variable name when the diagnostic is anchored to a specific declaration + * (e.g. an initial-value type mismatch). Lets editors highlight the + * exact row in a variables-table view rather than guessing from a line + * number. + */ + variableName?: string; } /** diff --git a/tests/backend/codegen-functions.test.ts b/tests/backend/codegen-functions.test.ts index 511d456..809eaee 100644 --- a/tests/backend/codegen-functions.test.ts +++ b/tests/backend/codegen-functions.test.ts @@ -486,4 +486,91 @@ describe("Codegen - Function Calls", () => { expect(result.cppCode).toMatch(/SCALE\(3\.14, 0\.0\)/); }); }); + + // Regression tests for two GARAGEDO_CTL-era codegen bugs that + // produced unbuildable C++ from valid IEC ST: + // + // 1. Generic std-fn literal-cast inference using the parent FB + // type (`IEC_CTU`) when the operand was an FB output member + // access (`CTU0.CV`). FBs don't have `IEC_` aliases — + // only types do — so the generated cast was an unknown + // identifier. Correct behaviour: walk `fieldAccess` and use + // the field's own type (`IEC_INT` for CV). + // + // 2. Generic std-fn literal-cast skipped when the literal's + // inferred IEC type matched the dominant variable type (e.g. + // both INT). C++ template deduction nevertheless failed + // because the variable side lowers to `IECVar` while a + // bare literal lowers to raw `int` — distinct `T`s. Correct + // behaviour: always cast bare literals when paired with at + // least one IECVar argument. + describe("regression: std-fn calls with FB outputs and bare literals", () => { + // CTU / CTU_UDINT live in the bundled iec-standard-fb library — + // resolve them via libraryPaths so the program type-checks. + const LIBS_DIR = "libs"; + + function compileWithLibs(source: string) { + const result = compile(source, { libraryPaths: [LIBS_DIR] }); + expect(result.success).toBe(true); + return result; + } + + it("uses the FB output's element type for literal casts, not the FB type itself", () => { + const result = compileWithLibs(` + PROGRAM Main + VAR + counter : CTU; + x : INT; + END_VAR + x := DIV(counter.CV, 10); + END_PROGRAM + `); + // counter.CV is INT — literal must cast to IEC_INT, NOT + // IEC_CTU (which doesn't exist as an alias). + expect(result.cppCode).toContain("static_cast(10)"); + expect(result.cppCode).not.toContain("IEC_CTU>"); + }); + + it("casts bare INT literal even when paired with an INT variable (template deduction)", () => { + const result = compileAndCheck(` + PROGRAM Main + VAR + a : INT := 5; + r : INT; + END_VAR + r := MUL(a, 10); + END_PROGRAM + `); + // Without the cast, MUL(T, T) sees IECVar vs int and + // fails to deduce. + expect(result.cppCode).toContain("static_cast(10)"); + }); + + it("casts bare REAL literal paired with a REAL variable", () => { + const result = compileAndCheck(` + PROGRAM Main + VAR + a : REAL := 1.5; + r : REAL; + END_VAR + r := MUL(a, 2.0); + END_PROGRAM + `); + expect(result.cppCode).toContain("static_cast(2.0)"); + }); + + it("does not synthesise an IEC_ cast for CTU_UDINT.CV (UDINT element)", () => { + const result = compileWithLibs(` + PROGRAM Main + VAR + counter : CTU_UDINT; + x : UDINT; + END_VAR + x := DIV(counter.CV, 10); + END_PROGRAM + `); + expect(result.cppCode).toContain("static_cast(10)"); + expect(result.cppCode).not.toContain("IEC_CTU_UDINT>"); + }); + }); }); diff --git a/tests/backend/codegen-wstring-literals.test.ts b/tests/backend/codegen-wstring-literals.test.ts new file mode 100644 index 0000000..e47f584 --- /dev/null +++ b/tests/backend/codegen-wstring-literals.test.ts @@ -0,0 +1,175 @@ +/** + * WSTRING literal handling — parser, type-checker, and codegen. + * + * Background: a real user report failed to compile after adding a + * WSTRING variable with a STRING-shaped initial value via the + * OpenPLC Editor's variables table: + * + * pou_MAIN.cpp: error: no matching function for call to + * 'IECWStringVar<254>::IECWStringVar(const char [22])' + * + * Per IEC 61131-3, `'foo'` is a STRING literal and `"foo"` is a + * WSTRING literal — the two are NOT interchangeable. The bug had + * two layers: + * + * 1. The lexer recognised `"foo"` as `WideStringLiteral`, but the + * AST builder had no branch for it — so a WSTRING literal got + * silently rewritten to `LiteralExpression { literalType: INT, + * value: 0 }`. The mismatch then fell through every downstream + * type check. + * + * 2. Codegen emitted WSTRING literal expressions with `L"…"` + * (wchar_t — 32-bit on Linux/AVR) instead of `u"…"` (char16_t, + * what IECWStringVar's string ctor binds to). + * + * Both are fixed. The test suite below pins: + * + * - parser: `"foo"` ⇒ WSTRING literal; `'foo'` ⇒ STRING literal + * - type-checker: STRING-into-WSTRING (and the reverse) is rejected + * - codegen: WSTRING literals emit with the `u` prefix; STRING with + * no prefix + */ + +import { describe, it, expect } from "vitest"; +import { compile, parse } from "../../dist/index.js"; + +describe("WSTRING literal handling", () => { + describe("parser", () => { + it("tags double-quoted literals as WSTRING", () => { + const result = parse(` + PROGRAM Main + VAR msg : WSTRING := "hello world"; END_VAR + END_PROGRAM + `); + expect(result.errors).toEqual([]); + const init = result.ast?.programs?.[0]?.varBlocks?.[0]?.declarations?.[0] + ?.initialValue; + expect(init?.kind).toBe("LiteralExpression"); + expect(init && "literalType" in init && init.literalType).toBe("WSTRING"); + }); + + it("tags single-quoted literals as STRING", () => { + const result = parse(` + PROGRAM Main + VAR msg : STRING := 'hello world'; END_VAR + END_PROGRAM + `); + expect(result.errors).toEqual([]); + const init = result.ast?.programs?.[0]?.varBlocks?.[0]?.declarations?.[0] + ?.initialValue; + expect(init && "literalType" in init && init.literalType).toBe("STRING"); + }); + }); + + describe("type-checker", () => { + it("rejects WSTRING := 'string' (single-quoted STRING into WSTRING)", () => { + // Per the user report: this is the case that previously slipped + // through and produced broken C++. With the AST tagged + // correctly, the assignability check catches the mismatch. + const result = compile(` + PROGRAM Main + VAR msg : WSTRING := 'this is my new string'; END_VAR + END_PROGRAM + `); + expect(result.success).toBe(false); + expect(result.errors.length).toBeGreaterThan(0); + const messages = result.errors.map((e) => e.message).join("\n"); + expect(messages).toMatch(/STRING|WSTRING|incompat/i); + }); + + it("rejects STRING := \"wstring\" (double-quoted WSTRING into STRING)", () => { + const result = compile(` + PROGRAM Main + VAR msg : STRING := "hello"; END_VAR + END_PROGRAM + `); + expect(result.success).toBe(false); + expect(result.errors.length).toBeGreaterThan(0); + }); + }); + + describe("codegen", () => { + it("emits u\"…\" for a WSTRING-typed variable initialised with a WSTRING literal", () => { + const result = compile(` + PROGRAM Main + VAR msg : WSTRING := "hello world"; END_VAR + END_PROGRAM + `); + expect(result.success).toBe(true); + // Strucpp uppercases ST variable names in the C++ initialiser + // list. The `u"hello world"` token is what binds to + // IECWStringVar's char16_t* ctor. + expect(result.cppCode).toContain('MSG(u"hello world")'); + }); + + it("emits \"…\" (no prefix) for a STRING-typed variable", () => { + const result = compile(` + PROGRAM Main + VAR msg : STRING := 'hello world'; END_VAR + END_PROGRAM + `); + expect(result.success).toBe(true); + expect(result.cppCode).toContain('MSG("hello world")'); + }); + + it("does not emit a bare \"\" initialiser for a defaulted WSTRING", () => { + const result = compile(` + PROGRAM Main + VAR msg : WSTRING; END_VAR + END_PROGRAM + `); + expect(result.success).toBe(true); + // Default-value path (`MSG(u"")`) or {} default init is OK; + // the regression we're guarding against is a bare `""` + // (char* form) leaking in. + expect(result.cppCode).not.toMatch(/MSG\(""\)/); + }); + + it("STRING_TO_WSTRING resolves to TO_WSTRING and compiles", () => { + const result = compile(` + PROGRAM Main + VAR + s : STRING := 'hello'; + w : WSTRING; + END_VAR + w := STRING_TO_WSTRING(s); + END_PROGRAM + `); + expect(result.success).toBe(true); + // Frontend collapses *_TO_* to TO_${toType} for codegen. + expect(result.cppCode).toMatch(/TO_WSTRING\(/); + }); + + it("WSTRING_TO_STRING resolves to TO_STRING and compiles", () => { + const result = compile(` + PROGRAM Main + VAR + w : WSTRING := "hello"; + s : STRING; + END_VAR + s := WSTRING_TO_STRING(w); + END_PROGRAM + `); + expect(result.success).toBe(true); + expect(result.cppCode).toMatch(/TO_STRING\(/); + }); + + it("emits u\"…\" for a WSTRING literal in a struct field initialiser", () => { + // Struct fields go through type-codegen.ts, a separate code + // path from program variables. The literal still has to land + // with the `u` prefix. + const result = compile(` + TYPE + Greeting : STRUCT + message : WSTRING := "wide hello"; + END_STRUCT; + END_TYPE + PROGRAM Main + VAR g : Greeting; END_VAR + END_PROGRAM + `); + expect(result.success).toBe(true); + expect(result.headerCode).toMatch(/MESSAGE\s*=\s*u"wide hello"/); + }); + }); +}); diff --git a/tests/backend/codegen.test.ts b/tests/backend/codegen.test.ts index 89dd151..7880cd6 100644 --- a/tests/backend/codegen.test.ts +++ b/tests/backend/codegen.test.ts @@ -67,6 +67,40 @@ describe('CodeGenerator', () => { expect(result.cppCode).toContain('Generated by STruC++'); expect(result.headerCode).toContain('Generated by STruC++'); }); + + it('should #undef OVERFLOW to avoid macro collisions', () => { + // `` is pulled into every TU via iec_std_lib.hpp, and on + // both glibc/macOS and avr-libc `` defines OVERFLOW as + // a legacy SVID numeric-error constant. Without this undef, any + // OSCAT FB struct field named OVERFLOW would get token-replaced + // before the C++ parser sees it. Pin the line + placement so a + // regression that drops or relocates it surfaces here. + // + // (The companion `#undef SP` for was retired once + // the Arduino glue split moved `generated.hpp` out of any TU + // that pulls in avr/io.h — no current TU defines `SP` as a + // macro before parsing the generated header.) + const ast = createCompilationUnit(); + const result = generator.generate(ast); + + expect(result.headerCode).toContain('#undef OVERFLOW'); + + // Must sit AFTER the runtime includes (so the includes can't + // re-define OVERFLOW after we drop it) and BEFORE the + // namespace open (so it covers every emitted struct). + const headerLines = result.headerCode.split('\n'); + const lastInclude = headerLines.findLastIndex((l) => + l.startsWith('#include'), + ); + const namespaceOpen = headerLines.findIndex((l) => + l.startsWith('namespace '), + ); + const undefLine = headerLines.findIndex( + (l) => l === '#undef OVERFLOW', + ); + expect(undefLine).toBeGreaterThan(lastInclude); + expect(undefLine).toBeLessThan(namespaceOpen); + }); }); }); }); diff --git a/tests/cli/cli-library.test.ts b/tests/cli/cli-library.test.ts index ba341fe..c7a93f7 100644 --- a/tests/cli/cli-library.test.ts +++ b/tests/cli/cli-library.test.ts @@ -101,8 +101,8 @@ describe("CLI Library Features", () => { expect(archive.manifest.version).toBe("1.0.0"); expect(archive.manifest.functions).toHaveLength(1); expect(archive.manifest.functions[0].name).toBe("MATHADD"); - expect(archive.headerCode).toBeTruthy(); - expect(archive.cppCode).toBeTruthy(); + expect(Array.isArray(archive.chunks)).toBe(true); + expect(archive.chunks.length).toBeGreaterThan(0); expect(archive.dependencies).toEqual([]); // Should NOT produce separate .hpp/.cpp files @@ -537,4 +537,156 @@ describe("CLI Library Features", () => { expect(stderr).toContain("Cannot read stlib archive"); }); }); + + describe("hierarchy (folder-based categories)", () => { + it("compile-from-folder tags manifest entries with subfolder paths", () => { + // A directory passed to --compile-lib carries hierarchy: each + // .st file's path relative to the root becomes its category. + // This pins that flow end-to-end via the CLI rather than the + // programmatic compileStlib() API. + const workDir = freshDir("compile-folder-hier"); + const libRoot = join(workDir, "src"); + mkdirSync(join(libRoot, "math"), { recursive: true }); + mkdirSync(join(libRoot, "io", "serial"), { recursive: true }); + writeFileSync( + join(libRoot, "math", "add.st"), + "FUNCTION ADD2 : INT VAR_INPUT a:INT;b:INT;END_VAR ADD2:=a+b; END_FUNCTION\n", + ); + writeFileSync( + join(libRoot, "io", "serial", "echo.st"), + "FUNCTION_BLOCK ECHO_FB VAR_INPUT s:INT;END_VAR VAR_OUTPUT o:INT;END_VAR o:=s; END_FUNCTION_BLOCK\n", + ); + writeFileSync( + join(libRoot, "rootlevel.st"), + "FUNCTION ROOTFN : INT VAR_INPUT x:INT;END_VAR ROOTFN:=x; END_FUNCTION\n", + ); + + const libDir = join(workDir, "out"); + runCLI([ + "--compile-lib", + libRoot, + "-o", + libDir, + "--lib-name", + "hier-lib", + ]); + + const archive = JSON.parse( + readFileSync(join(libDir, "hier-lib.stlib"), "utf-8"), + ); + const fnByName = new Map( + archive.manifest.functions.map((f: { name: string }) => [f.name, f]), + ); + const fbByName = new Map( + archive.manifest.functionBlocks.map( + (fb: { name: string }) => [fb.name, fb], + ), + ); + + expect((fnByName.get("ADD2") as { category?: string }).category).toBe( + "math", + ); + expect((fbByName.get("ECHO_FB") as { category?: string }).category).toBe( + "io/serial", + ); + // Root-level files have no category. + expect((fnByName.get("ROOTFN") as { category?: string }).category).toBe( + undefined, + ); + + // Sources mirror the manifest categories so --decompile-lib can + // recreate the folder layout without re-parsing the .st content. + const srcByName = new Map( + archive.sources.map( + (s: { fileName: string; category?: string }) => [s.fileName, s], + ), + ); + expect(srcByName.get("add.st")?.category).toBe("math"); + expect(srcByName.get("echo.st")?.category).toBe("io/serial"); + expect(srcByName.get("rootlevel.st")?.category).toBe(undefined); + }); + + it("decompile-lib recreates the folder hierarchy on disk", () => { + // Round-trip: compile a folder layout into a .stlib, then + // decompile and check every .st landed back under its category + // path. Categoryless files write at the output root. + const workDir = freshDir("decompile-hier"); + const libRoot = join(workDir, "src"); + mkdirSync(join(libRoot, "alpha"), { recursive: true }); + mkdirSync(join(libRoot, "beta", "deep"), { recursive: true }); + writeFileSync( + join(libRoot, "alpha", "a.st"), + "FUNCTION FA : INT VAR_INPUT x:INT;END_VAR FA:=x; END_FUNCTION\n", + ); + writeFileSync( + join(libRoot, "beta", "deep", "b.st"), + "FUNCTION FB : INT VAR_INPUT y:INT;END_VAR FB:=y; END_FUNCTION\n", + ); + writeFileSync( + join(libRoot, "top.st"), + "FUNCTION FT : INT VAR_INPUT z:INT;END_VAR FT:=z; END_FUNCTION\n", + ); + + const libDir = join(workDir, "out"); + runCLI([ + "--compile-lib", + libRoot, + "-o", + libDir, + "--lib-name", + "rt-lib", + ]); + + const extractDir = join(workDir, "extracted"); + runCLI([ + "--decompile-lib", + join(libDir, "rt-lib.stlib"), + "-o", + extractDir, + ]); + + expect(existsSync(join(extractDir, "alpha", "a.st"))).toBe(true); + expect(existsSync(join(extractDir, "beta", "deep", "b.st"))).toBe(true); + expect(existsSync(join(extractDir, "top.st"))).toBe(true); + }); + + it("flat archives extract flat (no spurious folders)", () => { + // No category metadata → identical extraction behaviour to + // pre-hierarchy versions of the CLI. Pins backwards compat. + const workDir = freshDir("decompile-flat"); + const stFile = join(workDir, "flat.st"); + writeFileSync( + stFile, + "FUNCTION FZ : INT VAR_INPUT q:INT;END_VAR FZ:=q; END_FUNCTION\n", + ); + + const libDir = join(workDir, "out"); + runCLI([ + "--compile-lib", + stFile, + "-o", + libDir, + "--lib-name", + "flat-lib", + ]); + + const archive = JSON.parse( + readFileSync(join(libDir, "flat-lib.stlib"), "utf-8"), + ); + const fz = archive.manifest.functions.find( + (f: { name: string }) => f.name === "FZ", + ); + expect(fz.category).toBe(undefined); + expect(archive.sources[0].category).toBe(undefined); + + const extractDir = join(workDir, "extracted"); + runCLI([ + "--decompile-lib", + join(libDir, "flat-lib.stlib"), + "-o", + extractDir, + ]); + expect(existsSync(join(extractDir, "flat.st"))).toBe(true); + }); + }); }); diff --git a/tests/diagnostic-formatter.test.ts b/tests/diagnostic-formatter.test.ts index 6f04903..9613826 100644 --- a/tests/diagnostic-formatter.test.ts +++ b/tests/diagnostic-formatter.test.ts @@ -179,6 +179,81 @@ describe("diagnostic-formatter", () => { expect(out).toContain("error: msg [E0042]"); }); + describe("preferBodyLine option (CLI/vscode default unchanged)", () => { + it("default (no options) shows the absolute file line — CLI behaviour", () => { + const map = buildSourceMap([{ fileName: "Manual_Override.st", source: program }]); + const out = formatDiagnostic( + { + message: "Cannot assign WSTRING to BOOL", + file: "Manual_Override.st", + line: 6, + column: 10, + severity: "error", + // POU-context fields populated, but caller didn't opt in: + pouName: "MANUAL_OVERRIDE", + pouKind: "FUNCTION_BLOCK", + section: "body", + bodyLine: 2, + }, + map, + ); + // Must show 6 (the file line), not 2 (the body line). + expect(out).toContain("Manual_Override.st:6:10:"); + expect(out).toMatch(/\n {3}6 \|/); + expect(out).not.toContain(":2:10:"); + expect(out).not.toMatch(/\n {3}2 \|/); + }); + + it("`preferBodyLine: true` swaps the displayed line for body-section errors", () => { + const map = buildSourceMap([{ fileName: "Manual_Override.st", source: program }]); + const out = formatDiagnostic( + { + message: "Cannot assign WSTRING to BOOL", + file: "Manual_Override.st", + line: 6, + column: 10, + severity: "error", + pouName: "MANUAL_OVERRIDE", + pouKind: "FUNCTION_BLOCK", + section: "body", + bodyLine: 2, + }, + map, + { preferBodyLine: true }, + ); + // Header column and gutter both render the body-relative line (2). + expect(out).toContain("Manual_Override.st:2:10:"); + expect(out).toMatch(/\n {3}2 \|/); + // But the source content under the gutter is still the actual + // line at file line 6 — `count := undefined_var + 1;` is the + // 6th line of `program`. + expect(out).toContain("count := undefined_var + 1;"); + }); + + it("`preferBodyLine: true` is a no-op for var-block errors (line passes through)", () => { + const map = buildSourceMap([{ fileName: "Manual_Override.st", source: program }]); + const out = formatDiagnostic( + { + message: "Cannot assign STRING to WSTRING", + file: "Manual_Override.st", + line: 3, + column: 5, + severity: "error", + pouName: "MANUAL_OVERRIDE", + pouKind: "FUNCTION_BLOCK", + section: "var-block", + variableName: "FOO", + // bodyLine intentionally undefined for var-block + }, + map, + { preferBodyLine: true }, + ); + // Var-block keeps `error.line` — the editor's vars-text Monaco + // view aligns with the per-POU file's line numbering. + expect(out).toContain("Manual_Override.st:3:5:"); + }); + }); + it("formatDiagnostics joins multiple entries with blank lines", () => { const out = formatDiagnostics( [ diff --git a/tests/diagnostic-pou-context.test.ts b/tests/diagnostic-pou-context.test.ts new file mode 100644 index 0000000..9f9527c --- /dev/null +++ b/tests/diagnostic-pou-context.test.ts @@ -0,0 +1,145 @@ +/** + * POU-context error annotation — pin tests. + * + * Standalone CLI behaviour is unchanged; these tests verify that + * programmatic consumers (the OpenPLC Editor) receive the new + * pouName / pouKind / section / bodyLine / variableName fields on + * `CompileError` records when the underlying diagnostic sits inside + * a POU strucpp parsed. + */ + +import { describe, it, expect } from "vitest"; +import { compile } from "../dist/index.js"; + +describe("CompileError POU annotation", () => { + describe("var-block errors", () => { + it("annotates a WSTRING := 'foo' mismatch with section='var-block' and the variable name", () => { + // Reproduces the user-reported scenario: a WSTRING declared with + // a single-quoted (STRING) initial value. The type-checker + // catches it as a `Cannot assign STRING to WSTRING` error; the + // editor needs the POU name + variable name to surface it in the + // right tab. + const result = compile(` +PROGRAM Manual_Override + VAR + foo : WSTRING := 'this is a string'; + END_VAR +END_PROGRAM +`); + expect(result.success).toBe(false); + const err = result.errors.find((e) => /STRING|WSTRING/.test(e.message)); + expect(err).toBeDefined(); + expect(err?.pouName).toBe("MANUAL_OVERRIDE"); + expect(err?.pouKind).toBe("PROGRAM"); + expect(err?.section).toBe("var-block"); + expect(err?.variableName).toBe("FOO"); + // var-block errors keep their file line (no bodyLine) + expect(err?.bodyLine).toBeUndefined(); + }); + + it("works inside a FUNCTION_BLOCK as well", () => { + const result = compile(` +FUNCTION_BLOCK Tank_Controller + VAR + setpoint : WSTRING := 'oops'; + END_VAR +END_FUNCTION_BLOCK +`); + expect(result.success).toBe(false); + const err = result.errors.find((e) => /STRING|WSTRING/.test(e.message)); + expect(err?.pouName).toBe("TANK_CONTROLLER"); + expect(err?.pouKind).toBe("FUNCTION_BLOCK"); + expect(err?.section).toBe("var-block"); + expect(err?.variableName).toBe("SETPOINT"); + }); + }); + + describe("body errors", () => { + it("annotates a body assignment mismatch with section='body' and a body-relative line", () => { + // Body is supposed to start at bodyLine 1 — the first line + // after END_VAR (excluding leading blank lines). Two statements + // here; the error is on the second, so bodyLine should be 2. + const result = compile(` +PROGRAM Main + VAR + flag : BOOL; + END_VAR + flag := TRUE; + flag := "wstring lit"; +END_PROGRAM +`); + expect(result.success).toBe(false); + const err = result.errors.find((e) => /BOOL|WSTRING/.test(e.message)); + expect(err?.pouName).toBe("MAIN"); + expect(err?.pouKind).toBe("PROGRAM"); + expect(err?.section).toBe("body"); + expect(err?.bodyLine).toBe(2); + // file line is preserved alongside + expect(err?.line).toBeGreaterThan(0); + }); + + it("first body statement maps to bodyLine 1", () => { + const result = compile(` +PROGRAM Main + VAR + flag : BOOL; + END_VAR + flag := "wstring lit"; +END_PROGRAM +`); + expect(result.success).toBe(false); + const err = result.errors.find((e) => /BOOL|WSTRING/.test(e.message)); + expect(err?.section).toBe("body"); + expect(err?.bodyLine).toBe(1); + }); + }); + + describe("multi-POU programs", () => { + it("attributes each error to the right POU when many POUs share a file", () => { + // The editor's monolithic program.st case: two POUs, two errors, + // one in each. Both must be annotated correctly without leaking + // the wrong POU name onto the other. + const result = compile(` +PROGRAM Alpha + VAR + a : WSTRING := 'oops_in_alpha'; + END_VAR +END_PROGRAM + +PROGRAM Beta + VAR flag : BOOL; END_VAR + flag := "wstring_in_beta_body"; +END_PROGRAM +`); + expect(result.success).toBe(false); + const alphaErr = result.errors.find( + (e) => /STRING|WSTRING/.test(e.message) && e.pouName === "ALPHA", + ); + const betaErr = result.errors.find( + (e) => /BOOL|WSTRING/.test(e.message) && e.pouName === "BETA", + ); + expect(alphaErr?.section).toBe("var-block"); + expect(alphaErr?.variableName).toBe("A"); + expect(betaErr?.section).toBe("body"); + expect(betaErr?.bodyLine).toBe(1); + }); + }); + + describe("non-annotated cases", () => { + it("leaves errors with line=0 untouched", () => { + // Synthetic errors (e.g. failed phase wrappers) come in with + // line=0; the annotation pass must skip them. Use a totally + // bad input that fails before semantic analysis; resulting + // errors should have at most the basic location info. + const result = compile("THIS IS NOT VALID ST"); + expect(result.success).toBe(false); + // Whether or not strucpp's recovery produces line>0 errors here, + // the contract is: line=0 errors never carry pouName. + for (const e of result.errors) { + if (e.line === 0) { + expect(e.pouName).toBeUndefined(); + } + } + }); + }); +}); diff --git a/tests/il/il-additional-sources.test.ts b/tests/il/il-additional-sources.test.ts new file mode 100644 index 0000000..dc32a18 --- /dev/null +++ b/tests/il/il-additional-sources.test.ts @@ -0,0 +1,54 @@ +/** + * IL transpilation must run on every source the compiler ingests — + * primary `source` AND every entry in `additionalSources`. The OpenPLC + * Editor's program.st splitter feeds per-POU files via + * `additionalSources`, and any of them can be IL; without this pass the + * IL POU reaches the ST parser as raw `LD x / ST y` and fails with a + * confusing "expecting Identifier but found 'LD'" error. + */ + +import { describe, it, expect } from "vitest"; +import { compile } from "../../dist/index.js"; + +describe("IL transpilation across additionalSources", () => { + it("compiles an IL POU passed via additionalSources alongside an ST primary", () => { + const stPrimary = ` +PROGRAM Main + VAR a : INT := 5; END_VAR + a := a + 1; +END_PROGRAM +`; + const ilAdditional = ` +FUNCTION_BLOCK State_Display + VAR State : INT; Out : INT; END_VAR + LD State + ST Out +END_FUNCTION_BLOCK +`; + const result = compile(stPrimary, { + additionalSources: [{ fileName: "State_Display.st", source: ilAdditional }], + }); + expect(result.success).toBe(true); + expect(result.errors).toEqual([]); + }); + + it("surfaces IL transpile errors from additionalSources with the right file name", () => { + const stPrimary = `PROGRAM Main VAR x : INT; END_VAR x := 0; END_PROGRAM\n`; + const broken = ` +FUNCTION_BLOCK Bad + VAR x : INT; END_VAR + LD nonexistent_variable + ST x +END_FUNCTION_BLOCK +`; + const result = compile(stPrimary, { + additionalSources: [{ fileName: "Bad.st", source: broken }], + }); + // Either the IL transpiler errors out or the downstream type + // checker does — what matters is the file attribution. + if (!result.success) { + const fromBad = result.errors.find((e) => e.file === "Bad.st"); + expect(fromBad).toBeDefined(); + } + }); +}); diff --git a/tests/library/additional-fb-library.test.ts b/tests/library/additional-fb-library.test.ts new file mode 100644 index 0000000..e7f67e8 --- /dev/null +++ b/tests/library/additional-fb-library.test.ts @@ -0,0 +1,302 @@ +/** + * Additional Function Blocks Library Tests + * + * Verifies the .stlib archive bundled at libs/additional-function-blocks.stlib + * contains the IEC 61131-3 Annex E Additional Function Blocks (RTC, INTEGRAL, + * DERIVATIVE, PID, RAMP, HYSTERESIS), that each compiles cleanly, and that + * the manifest exposes the FB signatures the editor expects. + * + * The library's source is checked into libs/sources/additional-function-blocks/ + * and compiled into the .stlib by scripts/generate-additional-fb.mjs. + */ + +import { describe, it, expect } from "vitest"; +import { resolve } from "path"; +import { compileLibrary } from "../../src/library/library-compiler.js"; +import { loadStlibFromFile } from "../../src/library/library-loader.js"; +import { compile } from "../../src/index.js"; + +const LIBS_DIR = resolve(__dirname, "../../libs"); +const STLIB_PATH = resolve(LIBS_DIR, "additional-function-blocks.stlib"); + +const stlibArchive = loadStlibFromFile(STLIB_PATH); +const archiveSources = stlibArchive.sources!; + +function getSource(fileName: string): string { + const entry = archiveSources.find((s) => s.fileName === fileName); + if (!entry) throw new Error(`Source ${fileName} not found in archive`); + return entry.source; +} + +describe("Additional Function Blocks Library", () => { + describe(".stlib archive", () => { + it("declares the expected library identity", () => { + expect(stlibArchive.manifest.name).toBe("additional-function-blocks"); + expect(stlibArchive.manifest.namespace).toBe("strucpp"); + expect(stlibArchive.manifest.isBuiltin).toBe(true); + }); + + it("ships all six Annex E function blocks", () => { + const fbNames = stlibArchive.manifest.functionBlocks + .map((fb) => fb.name) + .sort(); + expect(fbNames).toEqual( + ["DERIVATIVE", "HYSTERESIS", "INTEGRAL", "PID", "RAMP", "RTC"].sort(), + ); + }); + + it("embeds source for every declared FB", () => { + const sourceFiles = (stlibArchive.sources ?? []).map((s) => s.fileName); + expect(sourceFiles).toEqual( + expect.arrayContaining([ + "integral.st", + "derivative.st", + "rtc.st", + "pid.st", + "ramp.st", + "hysteresis.st", + ]), + ); + }); + + it("populates per-block documentation from library.json", () => { + // Block-level docs are merged into the manifest at build time + // from libs/sources/additional-function-blocks/library.json. If + // an FB ever lands without docs, the editor's hover dialog has + // nothing to show — tests catch that here so a stale library.json + // doesn't sneak through. + const fbsByName = Object.fromEntries( + stlibArchive.manifest.functionBlocks.map((fb) => [fb.name, fb]), + ); + for (const name of ["RTC", "INTEGRAL", "DERIVATIVE", "PID", "RAMP", "HYSTERESIS"]) { + const fb = fbsByName[name]; + expect(fb, `${name} should be in the manifest`).toBeDefined(); + expect(fb!.documentation, `${name} should have documentation`).toMatch(/\S/); + } + }); + + it("RTC documentation matches the editor's prose for hover dialogs", () => { + // Locks in the exact wording when the editor migration lands so + // users see the same hover text they get today from the editor's + // hardcoded library catalog. Update this assertion intentionally + // when the prose is revised — drift is the bug we want to catch. + const rtc = stlibArchive.manifest.functionBlocks.find((fb) => fb.name === "RTC"); + expect(rtc?.documentation).toBe( + "The real time clock has many uses including time stamping, setting dates and times of day in batch reports, in alarm messages and so on.", + ); + }); + }); + + describe("FB signatures", () => { + /** Returns the manifest entry for an FB by name. */ + function fb(name: string) { + const entry = stlibArchive.manifest.functionBlocks.find( + (f) => f.name === name, + ); + if (!entry) throw new Error(`FB ${name} not in manifest`); + return entry; + } + + it("RTC declares the IN/PDT inputs and Q/CDT outputs", () => { + const rtc = fb("RTC"); + expect(rtc.inputs.map((i) => i.name)).toEqual(["IN", "PDT"]); + expect(rtc.outputs.map((o) => o.name)).toEqual(["Q", "CDT"]); + const inputTypes = Object.fromEntries( + rtc.inputs.map((i) => [i.name, i.type]), + ); + expect(inputTypes.IN).toBe("BOOL"); + expect(inputTypes.PDT).toBe("DT"); + }); + + it("INTEGRAL exposes the standard 5-input / 2-output signature", () => { + const integral = fb("INTEGRAL"); + expect(integral.inputs.map((i) => i.name)).toEqual([ + "RUN", + "R1", + "XIN", + "X0", + "CYCLE", + ]); + expect(integral.outputs.map((o) => o.name)).toEqual(["Q", "XOUT"]); + }); + + it("DERIVATIVE exposes RUN / XIN / CYCLE → XOUT", () => { + const derivative = fb("DERIVATIVE"); + expect(derivative.inputs.map((i) => i.name)).toEqual([ + "RUN", + "XIN", + "CYCLE", + ]); + expect(derivative.outputs.map((o) => o.name)).toEqual(["XOUT"]); + }); + + it("PID exposes the classical eight tuning inputs and a single XOUT", () => { + const pid = fb("PID"); + expect(pid.inputs.map((i) => i.name)).toEqual([ + "AUTO", + "PV", + "SP", + "X0", + "KP", + "TR", + "TD", + "CYCLE", + ]); + expect(pid.outputs.map((o) => o.name)).toEqual(["XOUT"]); + }); + + it("RAMP exposes the four-input ramp generator signature", () => { + const ramp = fb("RAMP"); + expect(ramp.inputs.map((i) => i.name)).toEqual([ + "RUN", + "X0", + "X1", + "TR", + "CYCLE", + ]); + expect(ramp.outputs.map((o) => o.name)).toEqual(["BUSY", "XOUT"]); + }); + + it("HYSTERESIS exposes XIN1 / XIN2 / EPS → Q", () => { + const hyst = fb("HYSTERESIS"); + expect(hyst.inputs.map((i) => i.name)).toEqual(["XIN1", "XIN2", "EPS"]); + expect(hyst.outputs.map((o) => o.name)).toEqual(["Q"]); + }); + }); + + describe("library recompilation", () => { + it("compiles cleanly from the embedded sources", () => { + // Order matters: PID instantiates INTEGRAL/DERIVATIVE so they must + // be visible when PID is type-checked. + const sources = [ + "integral.st", + "derivative.st", + "rtc.st", + "pid.st", + "ramp.st", + "hysteresis.st", + ].map((fileName) => ({ fileName, source: getSource(fileName) })); + + const result = compileLibrary(sources, { + name: "additional-function-blocks", + version: "1.0.0", + namespace: "strucpp", + }); + + expect(result.errors).toEqual([]); + expect(result.success).toBe(true); + expect(result.manifest.functionBlocks).toHaveLength(6); + }); + }); + + describe("user-program integration", () => { + it("a user program can instantiate INTEGRAL using the stlib archive", () => { + const userProgram = ` + PROGRAM main + VAR + integ : INTEGRAL ; + in_val : REAL := 1.0 ; + cycle : TIME := T#10ms ; + END_VAR + integ(RUN := TRUE, R1 := FALSE, XIN := in_val, + X0 := 0.0, CYCLE := cycle) ; + END_PROGRAM + `; + + const result = compile(userProgram, { + libraries: [stlibArchive], + }); + + expect(result.errors).toEqual([]); + expect(result.success).toBe(true); + }); + + it("a user program can instantiate PID and chain it with INTEGRAL/DERIVATIVE", () => { + const userProgram = ` + PROGRAM main + VAR + controller : PID ; + measured : REAL := 0.0 ; + target : REAL := 50.0 ; + manual : REAL := 0.0 ; + cycle : TIME := T#10ms ; + END_VAR + controller(AUTO := TRUE, PV := measured, SP := target, + X0 := manual, KP := 1.0, TR := 1.0, TD := 0.1, + CYCLE := cycle) ; + END_PROGRAM + `; + + const result = compile(userProgram, { + libraries: [stlibArchive], + }); + + expect(result.errors).toEqual([]); + expect(result.success).toBe(true); + }); + + it("a user program can use HYSTERESIS for boolean threshold logic", () => { + const userProgram = ` + PROGRAM main + VAR + hyst : HYSTERESIS ; + sensor : REAL := 0.0 ; + setpoint : REAL := 25.0 ; + END_VAR + hyst(XIN1 := sensor, XIN2 := setpoint, EPS := 0.5) ; + END_PROGRAM + `; + + const result = compile(userProgram, { + libraries: [stlibArchive], + }); + + expect(result.errors).toEqual([]); + expect(result.success).toBe(true); + }); + + it("a user program can drive RTC across the rising-edge anchor", () => { + // RTC is hardware-agnostic — body uses only TIME() (monotonic + // scan-cycle time) and the IEC date arithmetic rules added for + // this library. This test invokes the FB twice across the rising + // edge of IN to make sure the anchoring path type-checks AND the + // generated code holds together when the FB is exercised in a + // realistic two-step sequence rather than a single snapshot call. + const userProgram = ` + PROGRAM main + VAR + clock : RTC ; + preset : DT := DT#2026-01-01-00:00:00 ; + END_VAR + (* Pre-anchor scan: CDT counts from DT zero. *) + clock(IN := FALSE, PDT := preset) ; + (* Rising edge: latches preset as the new anchor. *) + clock(IN := TRUE, PDT := preset) ; + END_PROGRAM + `; + + const result = compile(userProgram, { + libraries: [stlibArchive], + }); + + expect(result.errors).toEqual([]); + expect(result.success).toBe(true); + }); + + it("RTC does NOT pull in CURRENT_DT() — runs on hardware-agnostic targets", () => { + // Regression guard for the Arduino constraint: RTC must be self- + // contained on TIME(). If a future change re-introduces a + // CURRENT_DT() call inside the FB body, that call would surface + // in the embedded ST source and this assertion would catch it + // before it broke targets that don't ship std::chrono. + // + // Strip comments before scanning — the file's header comment + // intentionally explains the design choice and mentions the + // function name in prose; the call we want to forbid is in + // executable code only. + const rtcSource = getSource("rtc.st"); + const stripComments = (s: string) => s.replace(/\(\*[\s\S]*?\*\)/g, ""); + expect(stripComments(rtcSource)).not.toMatch(/CURRENT_DT\s*\(/); + }); + }); +}); diff --git a/tests/library/chunk-shake-fuzz.test.ts b/tests/library/chunk-shake-fuzz.test.ts new file mode 100644 index 0000000..9af6b1e --- /dev/null +++ b/tests/library/chunk-shake-fuzz.test.ts @@ -0,0 +1,118 @@ +/** + * STruC++ Library Chunk-Shake Fuzz + * + * Phase 5 of function-level tree-shaking. Every bundled-library chunk + * should be referenceable from a user program in isolation: the + * function-level shake walks the chunk's dep edges, the consumer + * codegen emits the closure, and the resulting C++ should compile + + * link. + * + * If a chunk fails this test, the chunk's `deps` array is missing an + * edge — most likely a symbol referenced only by an implicit codegen + * helper or a transitive type that the AST-walker in + * `src/library/library-chunks.ts:collectReferencedNames` didn't catch. + * Fix the extractor, rebuild the bundled libraries, re-run. + * + * Coverage: + * - Every FB chunk: declared as `VAR inst : ;` in a tiny program + * - Every type chunk: declared as `VAR v : ;` in a tiny program + * - Function chunks: skipped — calling them needs a real argument + * list, which would require interpreting each function's manifest + * entry and synthesizing typed values per parameter. Functions are + * transitively covered by the FB / type fuzz (any FB that calls a + * function pulls that function in through its dep edges). + * - Inline-global chunks: skipped — globals are pulled in only + * transitively (functions / FBs that read them list them as deps), + * same reasoning as the function case. + */ + +import { describe, it, expect } from "vitest"; +import { join } from "path"; +import { fileURLToPath } from "url"; +import { dirname } from "path"; +import { compile, loadStlibFromFile } from "../../src/index.js"; +import type { StlibArchive } from "../../src/library/library-manifest.js"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const LIBS_DIR = join(__dirname, "..", "..", "libs"); + +const BUNDLED_LIBS = [ + "iec-standard-fb", + "additional-function-blocks", + "oscat-basic", +]; + +function loadBundled(name: string): StlibArchive { + return loadStlibFromFile(join(LIBS_DIR, `${name}.stlib`)); +} + +// FBs / types that fail to compile when referenced standalone for +// reasons unrelated to the shake — typically because the symbol's +// declaration shape isn't valid as a top-level VAR (abstract base +// classes, IEC interfaces, types that need init args, etc.). Keep +// this list short and document each entry. +const STANDALONE_EXEMPT = new Set([ + // None today — every FB / type in the bundled libs is currently + // instantiable as a top-level VAR. Add entries here only with a + // comment explaining why standalone instantiation fails. +]); + +function programReferencing(chunk: { kind: string; name: string }): string { + switch (chunk.kind) { + case "functionBlock": + return `PROGRAM Main\n VAR inst : ${chunk.name}; END_VAR\nEND_PROGRAM\n`; + case "type": + return `PROGRAM Main\n VAR v : ${chunk.name}; END_VAR\nEND_PROGRAM\n`; + default: + throw new Error(`programReferencing not implemented for ${chunk.kind}`); + } +} + +for (const libName of BUNDLED_LIBS) { + describe(`chunk-shake fuzz: ${libName}`, () => { + const archive = loadBundled(libName); + const dependencyArchives = archive.dependencies + .map((d) => { + try { + return loadBundled(d.name); + } catch { + return null; + } + }) + .filter((a): a is StlibArchive => a !== null); + + const fbChunks = archive.chunks.filter((c) => c.kind === "functionBlock"); + const typeChunks = archive.chunks.filter((c) => c.kind === "type"); + + it(`has at least one shake-relevant chunk`, () => { + // Phase 1 sanity: if a bundled library ends up with zero + // FB/type chunks, either the library is genuinely + // functions-only (legit) or the compiler dropped them — fail + // loudly so the latter surfaces. + if (libName !== "iec-std-functions") { + expect(fbChunks.length + typeChunks.length).toBeGreaterThan(0); + } + }); + + for (const chunk of [...fbChunks, ...typeChunks]) { + if (STANDALONE_EXEMPT.has(chunk.name)) continue; + + it(`${chunk.kind}:${chunk.name} compiles in isolation`, () => { + const source = programReferencing(chunk); + const result = compile(source, { + libraries: [archive, ...dependencyArchives], + }); + if (!result.success) { + const lines = result.errors + .slice(0, 5) + .map((e) => ` ${e.line}:${e.column} ${e.message}`) + .join("\n"); + throw new Error( + `compile failed for ${chunk.kind} '${chunk.name}' (extractor likely missed a dep edge):\n${lines}`, + ); + } + expect(result.success).toBe(true); + }); + } + }); +} diff --git a/tests/library/codesys-import.test.ts b/tests/library/codesys-import.test.ts index d0ca0d3..f1dcef5 100644 --- a/tests/library/codesys-import.test.ts +++ b/tests/library/codesys-import.test.ts @@ -19,12 +19,15 @@ import { } from "../../dist/library/codesys-import/index.js"; import type { ExtractedPOU } from "../../dist/library/codesys-import/index.js"; -// Path to CODESYS library fixtures checked into the repository +// Path to CODESYS library fixtures checked into the repository. +// The V3 .library file is the canonical source for the bundled OSCAT +// stlib too (see libs/sources/oscat-basic/), so we point at that copy +// to avoid duplicating a 1.2 MB binary blob between fixtures/ and libs/. const FIXTURES_DIR = resolve(__dirname, "../fixtures/codesys"); const OSCAT_V23_PATH = resolve(FIXTURES_DIR, "oscat_basic_335.lib"); const OSCAT_V3_PATH = resolve( - FIXTURES_DIR, - "oscat_basic_335_codesys3.library", + __dirname, + "../../libs/sources/oscat-basic/oscat_basic_335.library", ); const V23_REFERENCE_DIR = resolve(FIXTURES_DIR, "v23-reference"); @@ -386,6 +389,188 @@ describe("V3 integration: OSCAT Basic 335", () => { expect(constLang!.source).toContain("TYPE CONSTANTS_LANGUAGE"); }); + it("extracts the OSCAT VAR_GLOBAL block instantiating CONSTANTS_*", () => { + // The V3 .library encodes a GVL the same way as a POU at the + // structural level — header in column B of a 4-varint record, + // body lines in column A of subsequent records — but with the + // keyword `VAR_GLOBAL` (optionally CONSTANT/RETAIN/PERSISTENT) + // instead of `FUNCTION_BLOCK`/`FUNCTION`/`PROGRAM`/`TYPE`. + // Earlier the header-detection regex only matched the latter four + // and dropped GVLs silently, leaving POUs that reference + // `LANGUAGE.WEEKDAYS[…]` (HOLIDAY / SUN_POS / the date helpers) + // with undeclared globals downstream. This test pins the GVL + // extraction so a regex regression surfaces here. + const result = importCodesysLibrary(OSCAT_V3_PATH); + const gvls = result.sources.filter((s) => /\bVAR_GLOBAL\b/.test(s.source)); + expect(gvls.length).toBeGreaterThanOrEqual(1); + + // OSCAT-specific: at least one GVL must declare the five CONSTANTS_* + // instances. Without these, HOLIDAY/SUN_POS et al. would compile-fail. + const constantsGvl = gvls.find((s) => + /MATH\s*:\s*CONSTANTS_MATH/.test(s.source) && + /LANGUAGE\s*:\s*CONSTANTS_LANGUAGE/.test(s.source) && + /LOCATION\s*:\s*CONSTANTS_LOCATION/.test(s.source), + ); + expect(constantsGvl, "Expected a GVL declaring MATH/LANGUAGE/LOCATION instances").toBeDefined(); + expect(constantsGvl!.source).toMatch(/PHYS\s*:\s*CONSTANTS_PHYS/); + expect(constantsGvl!.source).toMatch(/SETUP\s*:\s*CONSTANTS_SETUP/); + expect(constantsGvl!.source).toMatch(/END_VAR/); + }); + + it("promotes the OSCAT VAR_GLOBAL CONSTANT integers to globalConstants", () => { + // OSCAT's compile-time integer constants live in a `VAR_GLOBAL + // CONSTANT` block in the V3 source. They must be surfaced on the + // import result's `globalConstants` map (not as a runtime GVL), + // because downstream the strucpp codegen uses values like + // STRING_LENGTH as C++ template parameters (`IECStringVar`), + // which require a constexpr — a runtime GVL can't satisfy that. + // The originating GVL is dropped from the source list to avoid a + // duplicate definition when compileStlib also sees globalConstants. + const result = importCodesysLibrary(OSCAT_V3_PATH); + expect(result.globalConstants.STRING_LENGTH).toBeTypeOf("number"); + expect(result.globalConstants.LIST_LENGTH).toBeTypeOf("number"); + const constGvl = result.sources.find((s) => + /\bVAR_GLOBAL\s+CONSTANT\b/.test(s.source) && + /\bSTRING_LENGTH\b/.test(s.source), + ); + expect( + constGvl, + "VAR_GLOBAL CONSTANT block should not appear as a source — it should have been promoted to globalConstants", + ).toBeUndefined(); + }); + + it("extracts the OSCAT folder hierarchy from .meta files", () => { + // OSCAT's V3 .library encodes its project-explorer tree + // (POUs/Time&Date, POUs/Buffer Management, Data types, …) as + // .meta+.object pairs whose .meta carries a parent-folder GUID. + // The importer walks that chain and surfaces a slash-separated + // `category` on each ExtractedPOU; the well-known POUs below pin + // the resolved paths against CODESYS's own UI placement. + // + // Note: the importer strips the redundant top-level "POUs/" segment + // (CODESYS V3 wraps every code object in a "POUs" folder by + // convention; the compiled .stlib IS the POUs container, so the + // prefix nests every block one level deeper than the editor needs). + // "Data types" passes through unchanged since it carries meaningful + // classification information for tooling. + const result = importCodesysLibrary(OSCAT_V3_PATH); + const expected: Record = { + "DCF77.st": "Time&Date", + "HOLIDAY.st": "Time&Date", + "UTC_TO_LTIME.st": "Time&Date", + "BUFFER_COMP.st": "Buffer Management", + "ACOSH.st": "Mathematical", + "COMPLEX.st": "Data types", + "CRC_GEN.st": "Logic/Others", + }; + for (const [fileName, category] of Object.entries(expected)) { + const src = result.sources.find((s) => s.fileName === fileName); + expect(src, `${fileName} extracted`).toBeDefined(); + expect(src!.category).toBe(category); + } + // Spot-check distribution: the largest folders should hold dozens + // of POUs, well above the noise floor of "everything at root". + const counts = new Map(); + for (const s of result.sources) { + const c = s.category ?? ""; + counts.set(c, (counts.get(c) ?? 0) + 1); + } + expect(counts.get("String") ?? 0).toBeGreaterThanOrEqual(50); + expect(counts.get("Mathematical") ?? 0).toBeGreaterThanOrEqual(50); + expect(counts.get("Time&Date") ?? 0).toBeGreaterThanOrEqual(40); + // No POU should still carry the redundant "POUs" prefix. + for (const s of result.sources) { + expect(s.category ?? "").not.toMatch(/^POUs(\/|$)/); + } + }); + + it("structurally extracts documentation from the V3 decl-section slot", () => { + // CODESYS reserves a specific slot for each POU's documentation: the + // records of the decl sub-object that come AFTER the last END_VAR (or + // END_TYPE) of the variables-pane. Body comments live in the impl + // sub-object so they can never bleed into this slot, and inline + // variable annotations like `(* Laufvariable Stack *)` sit BEFORE + // the last END_VAR so they can never shadow the doc either. + // + // We assert here that the V3 importer attaches the right + // `documentation` to each ExtractedPOU directly — without going + // through any text-level regex or trigger-word heuristic. + const result = importCodesysLibrary(OSCAT_V3_PATH); + const pous = result.sources; + expect(pous.length).toBeGreaterThan(550); + + // Coverage: every POU whose V3 source has a comment in the doc slot + // gets that comment as `documentation`. OSCAT's only no-doc POUs are + // GVL_0 (the constants-only block dropped by the parser) and a + // handful of trivial TYPEs (FRACTION etc.) with no trailing comment. + const docCount = pous.filter((p) => p.documentation).length; + expect(docCount).toBeGreaterThan(550); + + // Pin the structure of a known FB doc: the slot has version, + // programmer, tested by, then a description. The opening `(*` and + // closing `*)` are stripped — only the inner text comes through. + const dcf = pous.find((p) => p.fileName === "DCF77.st"); + expect(dcf?.documentation).toBeTypeOf("string"); + expect(dcf?.documentation).not.toMatch(/\(\*/); // wrapper stripped + expect(dcf?.documentation).not.toMatch(/\*\)\s*$/); // wrapper stripped + expect(dcf?.documentation).toMatch(/version\s+1\.10/); + expect(dcf?.documentation).toMatch(/decoder for a DCF77 signal/); + + // FT_Profile (mixed-case source name → uppercase manifest name). + // Pinning this catches a lookup regression where the doc map used + // raw source-text casing instead of normalizing to upper-case. + const ft = pous.find((p) => p.fileName === "FT_Profile.st"); + expect(ft?.documentation).toMatch(/FT_Profile generates an output/); + + // Body comments are NOT documentation — even when they happen to + // contain trigger-shaped words, the V3 record split keeps body + // comments out of the decl-section slot. We verify by picking a + // POU whose body has a `(* … *)` block (BUFFER_COMP starts with + // `(* search for first character match *)` immediately in its + // implementation) and asserting that comment doesn't appear in + // the documentation field. + const buf = pous.find((p) => p.fileName === "BUFFER_COMP.st"); + expect(buf?.source).toMatch(/\(\* search for first character match \*\)/); + expect(buf?.documentation).toBeTypeOf("string"); + expect(buf?.documentation).not.toMatch(/search for first character match/); + }); + + it("compiled OSCAT manifest carries V3-extracted documentation", () => { + // End-to-end: structural extraction at the importer surfaces all + // the way through the compileStlib pipeline onto manifest entries + // (functions / functionBlocks / types). + const archive = JSON.parse( + readFileSync( + resolve(__dirname, "../../libs/oscat-basic.stlib"), + "utf-8", + ), + ); + const fns: Array<{ documentation?: string }> = archive.manifest.functions; + const fbs: Array<{ documentation?: string }> = + archive.manifest.functionBlocks; + const types: Array<{ documentation?: string }> = archive.manifest.types; + + // FBs and FUNCTIONs all have docs (their slot is always populated). + expect(fbs.filter((f) => f.documentation).length).toBe(fbs.length); + expect(fns.filter((f) => f.documentation).length).toBe(fns.length); + // TYPEs: most have a revision-history comment in the slot; only a + // small handful (e.g. FRACTION) ship without any trailing comment. + // Just assert "at least most have it" — we don't pin the exact + // count to avoid coupling to OSCAT's specific TYPE inventory. + expect(types.filter((t) => t.documentation).length).toBeGreaterThanOrEqual( + types.length - 2, + ); + }); + + it("V2.3 import leaves category undefined (no folders in V2.3 format)", () => { + // V2.3 .lib predates the folder feature — the format has no place + // to record one. Asserting "no categories" pins this so a future + // V2.3 parser change can't silently start emitting them. + const result = importCodesysLibrary(OSCAT_V23_PATH); + const categorized = result.sources.filter((s) => s.category); + expect(categorized.length).toBe(0); + }); + it("V3 POU counts are comparable to V2.3 extraction", () => { const v23Result = importCodesysLibrary(OSCAT_V23_PATH); const v3Result = importCodesysLibrary(OSCAT_V3_PATH); diff --git a/tests/library/library-chunks.test.ts b/tests/library/library-chunks.test.ts new file mode 100644 index 0000000..2bf7388 --- /dev/null +++ b/tests/library/library-chunks.test.ts @@ -0,0 +1,332 @@ +/** + * STruC++ Library Chunks Tests + * + * Tests for per-symbol chunk extraction (Phase 2 of function-level + * tree-shaking). Verifies that compileLibrary / compileStlib produce + * `chunks` arrays with correct kinds, names, deps, and that the + * `headerCode` / `cppCode` blobs have all chunk markers stripped. + */ + +import { describe, it, expect } from "vitest"; +import { compileLibrary, compileStlib } from "../../src/library/library-compiler.js"; + +describe("Library chunks", () => { + describe("compileLibrary chunk extraction", () => { + it("emits one chunk per top-level declaration", () => { + const result = compileLibrary( + [ + { + source: ` + TYPE + Color : (RED, GREEN, BLUE); + Counter : STRUCT + v : INT; + END_STRUCT; + END_TYPE + FUNCTION_BLOCK Incrementer + VAR_INPUT step : INT; END_VAR + VAR_OUTPUT total : INT; END_VAR + VAR state : Counter; END_VAR + state.v := state.v + step; + total := state.v; + END_FUNCTION_BLOCK + FUNCTION DoubleIt : INT + VAR_INPUT x : INT; END_VAR + DoubleIt := x * 2; + END_FUNCTION + `, + fileName: "test.st", + }, + ], + { name: "test-lib", version: "1.0.0", namespace: "test_lib" }, + ); + + expect(result.success).toBe(true); + expect(result.chunks).toBeDefined(); + + const byKind: Record = {}; + for (const chunk of result.chunks!) { + (byKind[chunk.kind] ??= []).push(chunk.name); + } + // Names are uppercased (matches codegen normalisation). + expect(byKind.type?.sort()).toEqual(["COLOR", "COUNTER"]); + expect(byKind.functionBlock).toEqual(["INCREMENTER"]); + expect(byKind.function).toEqual(["DOUBLEIT"]); + }); + + it("populates header for every chunk and cpp for FBs/functions only", () => { + const result = compileLibrary( + [ + { + source: ` + TYPE + T : STRUCT v : INT; END_STRUCT; + END_TYPE + FUNCTION_BLOCK FB + VAR_INPUT a : INT; END_VAR + VAR_OUTPUT r : INT; END_VAR + r := a; + END_FUNCTION_BLOCK + FUNCTION FN : INT + VAR_INPUT a : INT; END_VAR + FN := a; + END_FUNCTION + `, + fileName: "test.st", + }, + ], + { name: "test-lib", version: "1.0.0", namespace: "test_lib" }, + ); + + expect(result.success).toBe(true); + const chunks = result.chunks!; + const typeChunk = chunks.find((c) => c.kind === "type")!; + const fbChunk = chunks.find((c) => c.kind === "functionBlock")!; + const fnChunk = chunks.find((c) => c.kind === "function")!; + + expect(typeChunk.header.length).toBeGreaterThan(0); + expect(typeChunk.cpp).toBe(""); // types are header-only + + expect(fbChunk.header.length).toBeGreaterThan(0); + expect(fbChunk.cpp.length).toBeGreaterThan(0); // FBs have both + + expect(fnChunk.header.length).toBeGreaterThan(0); + expect(fnChunk.cpp.length).toBeGreaterThan(0); // functions have both + }); + + it("extracts inline-global chunks from GVL blocks", () => { + const result = compileLibrary( + [ + { + source: ` + VAR_GLOBAL + GLOBAL_COUNT : INT := 42; + END_VAR + FUNCTION USES_IT : INT + USES_IT := GLOBAL_COUNT; + END_FUNCTION + `, + fileName: "test.st", + }, + ], + { name: "test-lib", version: "1.0.0", namespace: "test_lib" }, + ); + + expect(result.success).toBe(true); + const chunks = result.chunks!; + const globalChunk = chunks.find((c) => c.kind === "inlineGlobal"); + expect(globalChunk?.name).toBe("GLOBAL_COUNT"); + expect(globalChunk?.header).toContain("inline"); + }); + }); + + describe("dep graph extraction", () => { + it("records same-library type deps as FB-to-type edges", () => { + const result = compileLibrary( + [ + { + source: ` + TYPE + Counter : STRUCT v : INT; END_STRUCT; + END_TYPE + FUNCTION_BLOCK Incrementer + VAR_INPUT step : INT; END_VAR + VAR state : Counter; END_VAR + state.v := state.v + step; + END_FUNCTION_BLOCK + `, + fileName: "test.st", + }, + ], + { name: "my-lib", version: "1.0.0", namespace: "my_lib" }, + ); + + const fb = result.chunks!.find((c) => c.name === "INCREMENTER")!; + expect(fb.deps).toContainEqual({ library: "my-lib", name: "COUNTER" }); + }); + + it("records same-library function-call deps as edges", () => { + const result = compileLibrary( + [ + { + source: ` + FUNCTION Helper : INT + VAR_INPUT x : INT; END_VAR + Helper := x * 2; + END_FUNCTION + FUNCTION Caller : INT + VAR_INPUT x : INT; END_VAR + Caller := Helper(x) + 1; + END_FUNCTION + `, + fileName: "test.st", + }, + ], + { name: "my-lib", version: "1.0.0", namespace: "my_lib" }, + ); + + const caller = result.chunks!.find((c) => c.name === "CALLER")!; + expect(caller.deps).toContainEqual({ library: "my-lib", name: "HELPER" }); + }); + + it("records same-library inline-global reads as edges", () => { + const result = compileLibrary( + [ + { + source: ` + VAR_GLOBAL + CFG : INT := 10; + END_VAR + FUNCTION Reader : INT + Reader := CFG; + END_FUNCTION + `, + fileName: "test.st", + }, + ], + { name: "my-lib", version: "1.0.0", namespace: "my_lib" }, + ); + + const reader = result.chunks!.find((c) => c.name === "READER")!; + expect(reader.deps).toContainEqual({ library: "my-lib", name: "CFG" }); + }); + + it("never records a chunk as a self-dep", () => { + const result = compileLibrary( + [ + { + source: ` + FUNCTION_BLOCK FB + VAR_INPUT a : INT; END_VAR + VAR_OUTPUT r : INT; END_VAR + r := a; + END_FUNCTION_BLOCK + `, + fileName: "test.st", + }, + ], + { name: "my-lib", version: "1.0.0", namespace: "my_lib" }, + ); + + const fb = result.chunks!.find((c) => c.name === "FB")!; + expect(fb.deps.some((d) => d.name === "FB")).toBe(false); + }); + + it("records cross-library deps using the dep archive's name", () => { + const baseLib = compileStlib( + [ + { + source: ` + FUNCTION BaseFn : INT + VAR_INPUT x : INT; END_VAR + BaseFn := x; + END_FUNCTION + `, + fileName: "base.st", + }, + ], + { name: "base-lib", version: "1.0.0", namespace: "base_lib" }, + ); + expect(baseLib.success).toBe(true); + + const consumer = compileLibrary( + [ + { + source: ` + FUNCTION CallsBase : INT + VAR_INPUT y : INT; END_VAR + CallsBase := BaseFn(y); + END_FUNCTION + `, + fileName: "consumer.st", + }, + ], + { + name: "consumer-lib", + version: "1.0.0", + namespace: "consumer_lib", + dependencies: [baseLib.archive], + }, + ); + expect(consumer.success).toBe(true); + + const fn = consumer.chunks!.find((c) => c.name === "CALLSBASE")!; + expect(fn.deps).toContainEqual({ library: "base-lib", name: "BASEFN" }); + }); + + it("emits deterministic dep ordering across builds", () => { + const source = ` + FUNCTION ZZZ : INT VAR_INPUT x : INT; END_VAR ZZZ := x; END_FUNCTION + FUNCTION AAA : INT VAR_INPUT x : INT; END_VAR AAA := x; END_FUNCTION + FUNCTION Caller : INT + VAR_INPUT x : INT; END_VAR + Caller := ZZZ(x) + AAA(x); + END_FUNCTION + `; + const first = compileLibrary( + [{ source, fileName: "t.st" }], + { name: "my-lib", version: "1.0.0", namespace: "my_lib" }, + ); + const second = compileLibrary( + [{ source, fileName: "t.st" }], + { name: "my-lib", version: "1.0.0", namespace: "my_lib" }, + ); + const callerA = first.chunks!.find((c) => c.name === "CALLER")!; + const callerB = second.chunks!.find((c) => c.name === "CALLER")!; + expect(callerA.deps).toEqual(callerB.deps); + // Sorted alphabetically by name within same library + const names = callerA.deps.map((d) => d.name); + expect(names).toEqual([...names].sort()); + }); + }); + + describe("archive chunk hygiene", () => { + it("never leaks chunk markers into emitted chunk text", () => { + const result = compileStlib( + [ + { + source: ` + TYPE Counter : STRUCT v : INT; END_STRUCT; END_TYPE + FUNCTION_BLOCK FB + VAR_INPUT a : INT; END_VAR + VAR_OUTPUT r : INT; END_VAR + r := a; + END_FUNCTION_BLOCK + FUNCTION FN : INT VAR_INPUT x : INT; END_VAR FN := x; END_FUNCTION + `, + fileName: "t.st", + }, + ], + { name: "test-lib", version: "1.0.0", namespace: "test_lib" }, + ); + + expect(result.success).toBe(true); + // The markers are slicing fenceposts only — every chunk's + // header/cpp must be marker-free or downstream emit would + // surface "//@chunk:..." comments in the user's generated.hpp. + for (const chunk of result.archive.chunks) { + expect(chunk.header).not.toContain("@chunk"); + expect(chunk.cpp).not.toContain("@chunk"); + } + }); + + it("populates the archive's chunks field", () => { + const result = compileStlib( + [ + { + source: ` + FUNCTION FN : INT VAR_INPUT x : INT; END_VAR FN := x; END_FUNCTION + `, + fileName: "t.st", + }, + ], + { name: "test-lib", version: "1.0.0", namespace: "test_lib" }, + ); + + expect(result.success).toBe(true); + expect(result.archive.chunks).toBeDefined(); + expect(result.archive.chunks!.length).toBeGreaterThan(0); + expect(result.archive.chunks!.find((c) => c.name === "FN")).toBeDefined(); + }); + }); +}); diff --git a/tests/library/library-config.test.ts b/tests/library/library-config.test.ts new file mode 100644 index 0000000..449fcd7 --- /dev/null +++ b/tests/library/library-config.test.ts @@ -0,0 +1,287 @@ +/** + * Tests for the library.json loader and the merge step that bakes + * per-block documentation into a compiled .stlib archive. + * + * Strategy: write small library.json fixtures into temp directories + * (loadLibraryConfig is filesystem-bound) and run apply against + * synthetic minimal archives so the validator and matcher can be + * exercised without spinning up the full compile pipeline. + */ + +import { describe, it, expect, beforeEach, afterEach } from "vitest"; +import { mkdtempSync, rmSync, writeFileSync } from "fs"; +import { tmpdir } from "os"; +import { join } from "path"; +import { + loadLibraryConfig, + applyLibraryConfigDocumentation, + type LibraryConfig, +} from "../../src/library/library-config.js"; +import type { StlibArchive } from "../../src/library/library-manifest.js"; + +let tmp: string; + +beforeEach(() => { + tmp = mkdtempSync(join(tmpdir(), "strucpp-libcfg-")); +}); +afterEach(() => { + rmSync(tmp, { recursive: true, force: true }); +}); + +function writeJson(name: string, content: unknown) { + writeFileSync(join(tmp, name), JSON.stringify(content, null, 2), "utf-8"); +} + +/** Minimal synthetic archive used by apply tests. */ +function makeArchive(opts: { + fbs?: string[]; + fns?: Array<{ name: string; returnType: string }>; +}): StlibArchive { + return { + formatVersion: 1, + manifest: { + name: "test", + version: "0.0.0", + namespace: "ns", + functions: (opts.fns ?? []).map((f) => ({ + name: f.name, + returnType: f.returnType, + parameters: [], + })), + functionBlocks: (opts.fbs ?? []).map((name) => ({ + name, + inputs: [], + outputs: [], + inouts: [], + })), + types: [], + headers: [], + isBuiltin: false, + }, + headerCode: "", + cppCode: "", + dependencies: [], + }; +} + +describe("loadLibraryConfig", () => { + it("returns null when library.json is absent", () => { + expect(loadLibraryConfig(tmp)).toBeNull(); + }); + + it("loads a valid minimal config", () => { + writeJson("library.json", { + name: "my-lib", + version: "1.0.0", + namespace: "strucpp", + }); + const cfg = loadLibraryConfig(tmp); + expect(cfg).toEqual({ + name: "my-lib", + version: "1.0.0", + namespace: "strucpp", + }); + }); + + it("loads optional fields (description, isBuiltin, blocks, functions)", () => { + writeJson("library.json", { + name: "x", + version: "1", + namespace: "ns", + description: "Test", + isBuiltin: true, + blocks: { FB: { documentation: "doc" } }, + functions: { FN: { documentation: "fn-doc" } }, + }); + const cfg = loadLibraryConfig(tmp); + expect(cfg?.description).toBe("Test"); + expect(cfg?.isBuiltin).toBe(true); + expect(cfg?.blocks?.FB.documentation).toBe("doc"); + expect(cfg?.functions?.FN.documentation).toBe("fn-doc"); + }); + + it("loads globalConstants when supplied (e.g. OSCAT's STRING_LENGTH)", () => { + writeJson("library.json", { + name: "x", + version: "1", + namespace: "ns", + globalConstants: { STRING_LENGTH: 254, LIST_LENGTH: 254 }, + }); + const cfg = loadLibraryConfig(tmp); + expect(cfg?.globalConstants).toEqual({ STRING_LENGTH: 254, LIST_LENGTH: 254 }); + }); + + it("throws when globalConstants is an array instead of an object map", () => { + writeJson("library.json", { + name: "x", + version: "1", + namespace: "ns", + globalConstants: [254, 254], + }); + expect(() => loadLibraryConfig(tmp)).toThrow(/globalConstants/); + }); + + it("throws when a globalConstants value is non-numeric", () => { + writeJson("library.json", { + name: "x", + version: "1", + namespace: "ns", + globalConstants: { STRING_LENGTH: "254" }, + }); + expect(() => loadLibraryConfig(tmp)).toThrow(/STRING_LENGTH/); + }); + + it("throws when a globalConstants value is non-finite (NaN / Infinity)", () => { + writeJson("library.json", { + name: "x", + version: "1", + namespace: "ns", + // JSON can't carry NaN, but it can carry null. The validator + // rejects anything that's not a finite number, including null. + globalConstants: { BAD: null }, + }); + expect(() => loadLibraryConfig(tmp)).toThrow(/BAD/); + }); + + it("throws on malformed JSON", () => { + writeFileSync(join(tmp, "library.json"), "{ not json", "utf-8"); + expect(() => loadLibraryConfig(tmp)).toThrow(/invalid JSON/i); + }); + + it("throws when name is missing", () => { + writeJson("library.json", { version: "1", namespace: "ns" }); + expect(() => loadLibraryConfig(tmp)).toThrow(/"name"/); + }); + + it("throws when name is empty string", () => { + writeJson("library.json", { name: "", version: "1", namespace: "ns" }); + expect(() => loadLibraryConfig(tmp)).toThrow(/"name"/); + }); + + it("throws when version is non-string", () => { + writeJson("library.json", { name: "x", version: 1, namespace: "ns" }); + expect(() => loadLibraryConfig(tmp)).toThrow(/"version"/); + }); + + it("throws when namespace is missing", () => { + writeJson("library.json", { name: "x", version: "1" }); + expect(() => loadLibraryConfig(tmp)).toThrow(/"namespace"/); + }); + + it("throws when blocks is an array instead of object", () => { + writeJson("library.json", { + name: "x", + version: "1", + namespace: "ns", + blocks: [], + }); + expect(() => loadLibraryConfig(tmp)).toThrow(/blocks/); + }); + + it("throws when a block entry is missing documentation", () => { + writeJson("library.json", { + name: "x", + version: "1", + namespace: "ns", + blocks: { FB: {} }, + }); + expect(() => loadLibraryConfig(tmp)).toThrow(/documentation/); + }); + + it("throws when a block entry's documentation is non-string", () => { + writeJson("library.json", { + name: "x", + version: "1", + namespace: "ns", + blocks: { FB: { documentation: 123 } }, + }); + expect(() => loadLibraryConfig(tmp)).toThrow(/documentation/); + }); +}); + +describe("applyLibraryConfigDocumentation", () => { + it("merges block docs into matching FBs in place", () => { + const archive = makeArchive({ fbs: ["TON", "TOF"] }); + const config: LibraryConfig = { + name: "x", + version: "1", + namespace: "ns", + blocks: { + TON: { documentation: "on-delay" }, + TOF: { documentation: "off-delay" }, + }, + }; + const report = applyLibraryConfigDocumentation(archive, config); + expect(report.blocksDocumented).toBe(2); + expect(report.unknownBlockDocs).toEqual([]); + expect(archive.manifest.functionBlocks[0]?.documentation).toBe("on-delay"); + expect(archive.manifest.functionBlocks[1]?.documentation).toBe("off-delay"); + }); + + it("merges function docs into matching functions in place", () => { + const archive = makeArchive({ fns: [{ name: "ABS", returnType: "REAL" }] }); + const config: LibraryConfig = { + name: "x", + version: "1", + namespace: "ns", + functions: { ABS: { documentation: "absolute value" } }, + }; + const report = applyLibraryConfigDocumentation(archive, config); + expect(report.functionsDocumented).toBe(1); + expect(archive.manifest.functions[0]?.documentation).toBe("absolute value"); + }); + + it("reports unknown block names instead of silently dropping them", () => { + const archive = makeArchive({ fbs: ["TON"] }); + const config: LibraryConfig = { + name: "x", + version: "1", + namespace: "ns", + blocks: { + TON: { documentation: "ok" }, + TYPO_NAME: { documentation: "should fail" }, + }, + }; + const report = applyLibraryConfigDocumentation(archive, config); + expect(report.blocksDocumented).toBe(1); + expect(report.unknownBlockDocs).toEqual(["TYPO_NAME"]); + }); + + it("reports unknown function names", () => { + const archive = makeArchive({ fns: [] }); + const config: LibraryConfig = { + name: "x", + version: "1", + namespace: "ns", + functions: { GHOST: { documentation: "not in manifest" } }, + }; + const report = applyLibraryConfigDocumentation(archive, config); + expect(report.unknownFunctionDocs).toEqual(["GHOST"]); + }); + + it("matches names case-sensitively (FB names are uppercase by convention)", () => { + const archive = makeArchive({ fbs: ["TON"] }); + const config: LibraryConfig = { + name: "x", + version: "1", + namespace: "ns", + blocks: { ton: { documentation: "lowercase typo" } }, + }; + const report = applyLibraryConfigDocumentation(archive, config); + expect(report.unknownBlockDocs).toEqual(["ton"]); + expect(archive.manifest.functionBlocks[0]?.documentation).toBeUndefined(); + }); + + it("is a no-op when blocks/functions are absent from config", () => { + const archive = makeArchive({ fbs: ["TON"] }); + const config: LibraryConfig = { + name: "x", + version: "1", + namespace: "ns", + }; + const report = applyLibraryConfigDocumentation(archive, config); + expect(report.blocksDocumented).toBe(0); + expect(report.functionsDocumented).toBe(0); + expect(archive.manifest.functionBlocks[0]?.documentation).toBeUndefined(); + }); +}); diff --git a/tests/library/library-system.test.ts b/tests/library/library-system.test.ts index 8c50606..fb5aa5a 100644 --- a/tests/library/library-system.test.ts +++ b/tests/library/library-system.test.ts @@ -106,7 +106,7 @@ describe("Library System", () => { }); describe("compileStlib", () => { - it("should produce a valid StlibArchive with headerCode/cppCode populated", () => { + it("should produce a valid StlibArchive with chunks populated", () => { const result = compileStlib( [ { @@ -125,8 +125,7 @@ describe("Library System", () => { expect(result.success).toBe(true); expect(result.archive.formatVersion).toBe(1); expect(result.archive.manifest.name).toBe("math-lib"); - expect(result.archive.headerCode).toBeTruthy(); - expect(result.archive.cppCode).toBeTruthy(); + expect(result.archive.chunks.length).toBeGreaterThan(0); expect(result.archive.dependencies).toEqual([]); }); @@ -204,12 +203,14 @@ describe("Library System", () => { ); expect(result.success).toBe(true); - // Should NOT contain namespace wrapper or includes - expect(result.archive.headerCode).not.toContain("#pragma once"); - expect(result.archive.headerCode).not.toContain("#include"); - expect(result.archive.headerCode).not.toMatch(/^namespace\s/m); - // Should contain actual code - expect(result.archive.headerCode).toContain("MATHADD"); + // Chunks own each symbol's emit slice. Concat them and verify + // the resulting text is pure namespace-body content — no + // wrapper, no #include — but does contain the function. + const concatHeader = result.archive.chunks.map((c) => c.header).join("\n"); + expect(concatHeader).not.toContain("#pragma once"); + expect(concatHeader).not.toContain("#include"); + expect(concatHeader).not.toMatch(/^namespace\s/m); + expect(concatHeader).toContain("MATHADD"); }); }); @@ -371,16 +372,14 @@ describe("Library System", () => { headers: [], isBuiltin: false, }, - headerCode: "// header", - cppCode: "// cpp", + chunks: [], dependencies: [], }; const archive = loadStlibArchive(json); expect(archive.formatVersion).toBe(1); expect(archive.manifest.name).toBe("test-lib"); - expect(archive.headerCode).toBe("// header"); - expect(archive.cppCode).toBe("// cpp"); + expect(archive.chunks).toEqual([]); expect(archive.dependencies).toEqual([]); }); @@ -397,8 +396,7 @@ describe("Library System", () => { headers: [], isBuiltin: false, }, - headerCode: "", - cppCode: "", + chunks: [], dependencies: [], }), ).toThrow("'formatVersion' must be 1"); @@ -418,8 +416,7 @@ describe("Library System", () => { headers: [], isBuiltin: false, }, - headerCode: "", - cppCode: "", + chunks: [], dependencies: [], }), ).toThrow("'formatVersion' must be 1"); @@ -429,14 +426,13 @@ describe("Library System", () => { expect(() => loadStlibArchive({ formatVersion: 1, - headerCode: "", - cppCode: "", + chunks: [], dependencies: [], }), ).toThrow("'manifest' must be an object"); }); - it("should reject missing headerCode", () => { + it("should reject missing chunks", () => { expect(() => loadStlibArchive({ formatVersion: 1, @@ -450,30 +446,9 @@ describe("Library System", () => { headers: [], isBuiltin: false, }, - cppCode: "", dependencies: [], }), - ).toThrow("'headerCode' must be a string"); - }); - - it("should reject missing cppCode", () => { - expect(() => - loadStlibArchive({ - formatVersion: 1, - manifest: { - name: "lib", - version: "1.0.0", - namespace: "ns", - functions: [], - functionBlocks: [], - types: [], - headers: [], - isBuiltin: false, - }, - headerCode: "", - dependencies: [], - }), - ).toThrow("'cppCode' must be a string"); + ).toThrow("'chunks' must be an array"); }); it("should reject missing dependencies", () => { @@ -490,8 +465,7 @@ describe("Library System", () => { headers: [], isBuiltin: false, }, - headerCode: "", - cppCode: "", + chunks: [], }), ).toThrow("'dependencies' must be an array"); }); @@ -761,8 +735,7 @@ describe("Library System", () => { { name: "counter-lib", version: "1.0.0", namespace: "counter" }, ); expect(libResult.success).toBe(true); - expect(libResult.archive.headerCode).toBeTruthy(); - expect(libResult.archive.cppCode).toBeTruthy(); + expect(libResult.archive.chunks.length).toBeGreaterThan(0); // Compile user program that uses the library FB const mainSource = ` @@ -946,8 +919,15 @@ describe("Library System", () => { headers: [], isBuiltin: false, }, - headerCode: "// header code", - cppCode: "// cpp code", + chunks: [ + { + name: "MYFN", + kind: "function", + header: "// header code", + cpp: "// cpp code", + deps: [], + }, + ], dependencies: [], }), ); @@ -955,8 +935,8 @@ describe("Library System", () => { const archive = loadStlibFromFile(stlibPath); expect(archive.formatVersion).toBe(1); expect(archive.manifest.name).toBe("file-lib"); - expect(archive.headerCode).toBe("// header code"); - expect(archive.cppCode).toBe("// cpp code"); + expect(archive.chunks).toHaveLength(1); + expect(archive.chunks[0]!.name).toBe("MYFN"); }); it("should throw for nonexistent file", () => { @@ -1068,8 +1048,7 @@ describe("Library System", () => { headers: [], isBuiltin: false, }, - headerCode: "", - cppCode: "", + chunks: [], dependencies: [], }; const archive2 = { @@ -1084,8 +1063,7 @@ describe("Library System", () => { headers: [], isBuiltin: false, }, - headerCode: "", - cppCode: "", + chunks: [], dependencies: [], }; writeFileSync(join(dir, "lib-a.stlib"), JSON.stringify(archive1)); diff --git a/tests/library/std-fb-library.test.ts b/tests/library/std-fb-library.test.ts index 8643ba2..628013d 100644 --- a/tests/library/std-fb-library.test.ts +++ b/tests/library/std-fb-library.test.ts @@ -31,6 +31,7 @@ function getSource(fileName: string): string { const edgeDetST = getSource("edge_detection.st"); const bistableST = getSource("bistable.st"); +const semaST = getSource("sema.st"); const counterST = getSource("counter.st"); const timerST = getSource("timer.st"); @@ -126,6 +127,7 @@ describe("Standard FB Library", () => { [ { source: edgeDetST, fileName: "edge_detection.st" }, { source: bistableST, fileName: "bistable.st" }, + { source: semaST, fileName: "sema.st" }, { source: counterST, fileName: "counter.st" }, { source: timerST, fileName: "timer.st" }, ], @@ -138,8 +140,8 @@ describe("Standard FB Library", () => { expect(result.success).toBe(true); expect(result.errors).toHaveLength(0); - // 2 edge + 2 bistable + 15 counters + 3 timers = 22 - expect(result.manifest.functionBlocks).toHaveLength(22); + // 2 edge + 2 bistable + 1 sema + 15 counters + 3 timers = 23 + expect(result.manifest.functionBlocks).toHaveLength(23); expect(result.manifest.name).toBe("iec-standard-fb"); // Verify all expected FBs are present @@ -150,6 +152,8 @@ describe("Standard FB Library", () => { // Bistable expect(fbNames).toContain("SR"); expect(fbNames).toContain("RS"); + // Semaphore + expect(fbNames).toContain("SEMA"); // Counters (base) expect(fbNames).toContain("CTU"); expect(fbNames).toContain("CTD"); @@ -175,6 +179,7 @@ describe("Standard FB Library", () => { [ { source: edgeDetST, fileName: "edge_detection.st" }, { source: bistableST, fileName: "bistable.st" }, + { source: semaST, fileName: "sema.st" }, { source: counterST, fileName: "counter.st" }, { source: timerST, fileName: "timer.st" }, ], @@ -246,6 +251,19 @@ describe("Standard FB Library", () => { ); }); + it("should have correct IO for SEMA", () => { + const fb = findFB("SEMA"); + expect(fb).toBeDefined(); + const inputNames = fb!.inputs.map((i) => i.name); + expect(inputNames).toContain("CLAIM"); + expect(inputNames).toContain("RELEASE"); + expect(fb!.outputs).toEqual( + expect.arrayContaining([ + expect.objectContaining({ name: "BUSY", type: "BOOL" }), + ]), + ); + }); + it("should have correct IO for CTU", () => { const fb = findFB("CTU"); expect(fb).toBeDefined(); @@ -362,13 +380,48 @@ describe("Standard FB Library", () => { expect(stlibArchive.manifest.isBuiltin).toBe(true); }); - it("should contain all 22 standard FBs", () => { - expect(stlibArchive.manifest.functionBlocks).toHaveLength(22); + it("should contain all 23 standard FBs", () => { + // 23 = 2 bistables (SR/RS) + 1 SEMA + 2 edge detectors (R_TRIG/F_TRIG) + // + 15 counter variants (CTU/CTD/CTUD × 5 width variants) + 3 timers + // (TP/TON/TOF). Matches MatIEC's iec_std_FB.h verbatim. + expect(stlibArchive.manifest.functionBlocks).toHaveLength(23); }); - it("should have non-empty headerCode and cppCode", () => { - expect(stlibArchive.headerCode).toBeTruthy(); - expect(stlibArchive.cppCode).toBeTruthy(); + it("populates per-block documentation from library.json", () => { + // Block-level docs are merged from + // libs/sources/iec-standard-fb/library.json at build time. + // Every FB in the archive must carry a doc string; if a new FB + // is added without a corresponding library.json entry, the + // build script fails — this test guards against that loop being + // weakened in the future. + for (const fb of stlibArchive.manifest.functionBlocks) { + expect(fb.documentation, `${fb.name} should have documentation`).toMatch(/\S/); + } + }); + + it("TON / TOF / TP documentation matches the editor's prose", () => { + const byName = Object.fromEntries( + stlibArchive.manifest.functionBlocks.map((fb) => [fb.name, fb]), + ); + expect(byName.TON?.documentation).toBe( + "The on-delay timer can be used to delay setting an output true, for fixed period after an input becomes true.", + ); + expect(byName.TOF?.documentation).toBe( + "The off-delay timer can be used to delay setting an output false, for fixed period after input goes false.", + ); + expect(byName.TP?.documentation).toBe( + "The pulse timer can be used to generate output pulses of a given time duration.", + ); + }); + + it("should have one chunk per declared FB", () => { + expect(stlibArchive.chunks.length).toBeGreaterThan(0); + // Every chunk in the stdlib is a function block (no types, + // no inline globals, no free functions in iec-standard-fb). + for (const chunk of stlibArchive.chunks) { + expect(chunk.kind).toBe("functionBlock"); + expect(chunk.header.length).toBeGreaterThan(0); + } }); it("should have no functions (only FBs)", () => { @@ -636,9 +689,14 @@ describe("Standard FB Library", () => { }); it("should use pre-compiled stdlib (no runtime recompilation)", () => { - // Verify that the stdlib archive has pre-compiled C++ code - expect(stlibArchive.headerCode.length).toBeGreaterThan(100); - expect(stlibArchive.cppCode.length).toBeGreaterThan(100); + // Verify that the stdlib archive has pre-compiled chunks ready + // for per-symbol consumption. + expect(stlibArchive.chunks.length).toBeGreaterThan(0); + const totalHeaderBytes = stlibArchive.chunks.reduce( + (n, c) => n + c.header.length, + 0, + ); + expect(totalHeaderBytes).toBeGreaterThan(100); // Compile a simple program that uses stdlib FBs const source = ` @@ -707,6 +765,7 @@ describe("Standard FB Library", () => { [ { source: edgeDetST, fileName: "edge_detection.st" }, { source: bistableST, fileName: "bistable.st" }, + { source: semaST, fileName: "sema.st" }, { source: counterST, fileName: "counter.st" }, { source: timerST, fileName: "timer.st" }, ], diff --git a/tests/library/std-functions-library.test.ts b/tests/library/std-functions-library.test.ts new file mode 100644 index 0000000..f36ad7d --- /dev/null +++ b/tests/library/std-functions-library.test.ts @@ -0,0 +1,146 @@ +/** + * STruC++ IEC Standard Functions Library Tests + * + * Validates the synthesized `iec-std-functions.stlib` archive — pure- + * metadata library carrying every entry of the StdFunctionRegistry + * (ADD/SUB/MUL/MUX/SHL/CONCAT/...) so editor tooling can list, group, + * and type-check std functions through the same path it uses for + * compiled .stlib libraries. Pinned here so a registry change that + * forgets to flow through the synthesis script (or a synthesis script + * regression) surfaces as a test failure. + */ + +import { describe, it, expect } from "vitest"; +import { resolve } from "path"; +import { loadStlibFromFile } from "../../src/library/library-loader.js"; +import { StdFunctionRegistry } from "../../src/semantic/std-function-registry.js"; + +const LIBS_DIR = resolve(__dirname, "../../libs"); +const STLIB_PATH = resolve(LIBS_DIR, "iec-std-functions.stlib"); + +const archive = loadStlibFromFile(STLIB_PATH); +const fns = archive.manifest.functions; +const fnByName = new Map(fns.map((f) => [f.name, f])); + +describe("iec-std-functions.stlib synthesis", () => { + it("ships as a builtin metadata-only archive", () => { + expect(archive.manifest.name).toBe("iec-std-functions"); + expect(archive.manifest.namespace).toBe("strucpp"); + expect(archive.manifest.isBuiltin).toBe(true); + // No FBs / TYPEs — std functions are functions only. + expect(archive.manifest.functionBlocks).toHaveLength(0); + expect(archive.manifest.types).toHaveLength(0); + // No ST sources (intrinsics) and no codegen output (runtime + // implements them — the .stlib is pure metadata: manifest + + // empty chunks array). + expect(archive.sources).toBeUndefined(); + expect(archive.chunks).toEqual([]); + }); + + it("carries every function the StdFunctionRegistry registers", () => { + // The synthesis is just a 1:1 walk over registry.getAll() — if + // someone adds a function to the registry but forgets to rebuild + // the .stlib, this catches it. + const registry = new StdFunctionRegistry(); + const registryNames = new Set(registry.getAll().map((d) => d.name)); + const archiveNames = new Set(fns.map((f) => f.name)); + expect(archiveNames.size).toBe(registryNames.size); + for (const name of registryNames) { + expect(archiveNames.has(name), `archive missing ${name}`).toBe(true); + } + }); + + it("groups functions into the editor-facing IEC categories", () => { + // Spot-check: every function carries a category, and every + // expected display-name bucket has at least one entry. We don't + // pin exact counts here so a registry add doesn't ripple into + // brittle test maintenance. + for (const f of fns) { + expect( + f.category, + `${f.name} is missing a category`, + ).toBeTypeOf("string"); + } + const buckets = new Set(fns.map((f) => f.category!)); + expect(buckets).toContain("Numerical"); + expect(buckets).toContain("Arithmetic"); + expect(buckets).toContain("Selection"); + expect(buckets).toContain("Comparison"); + expect(buckets).toContain("Bitwise"); + expect(buckets).toContain("BitShift"); + expect(buckets).toContain("TypeConversion"); + expect(buckets).toContain("CharacterString"); + expect(buckets).toContain("Time"); + expect(buckets).toContain("System"); + }); + + it("ABS preserves its ANY_NUM generic on both ends", () => { + // ABS(IN: ANY_NUM) -> ANY_NUM. Tooling unifies identical generic + // names at instantiation, so both must surface verbatim. + const abs = fnByName.get("ABS")!; + expect(abs.returnType).toBe("ANY_NUM"); + expect(abs.parameters).toEqual([ + { name: "IN", type: "ANY_NUM", direction: "input" }, + ]); + expect(abs.variadic).toBeUndefined(); + }); + + it("ADD is variadic with minArgs=2", () => { + // Extensible IEC functions like ADD/MUL accept ≥ 2 operands; the + // .stlib `variadic.minArgs` carries that contract through to the + // editor (which renders a "+" pin to grow inputs past the + // declared parameter list). + const add = fnByName.get("ADD")!; + expect(add.returnType).toBe("ANY_NUM"); + expect(add.variadic).toEqual({ minArgs: 2 }); + expect(add.parameters.map((p) => p.name)).toEqual(["IN1", "IN2"]); + }); + + it("MUX has a fixed-type selector + ANY-typed inputs", () => { + // MUX(K: INT, IN0: ANY, IN1: ANY, …) — the selector is a concrete + // INT while the ANY pins unify across themselves and with the + // return type. variadic.minArgs counts the selector + IN0 + IN1 + // baseline. + const mux = fnByName.get("MUX")!; + expect(mux.returnType).toBe("ANY"); + expect(mux.variadic).toEqual({ minArgs: 3 }); + expect(mux.parameters[0]).toEqual({ + name: "K", + type: "INT", + direction: "input", + }); + expect(mux.parameters[1]).toEqual({ + name: "IN0", + type: "ANY", + direction: "input", + }); + expect(mux.parameters[2]).toEqual({ + name: "IN1", + type: "ANY", + direction: "input", + }); + }); + + it("SHL mixes a generic ANY_BIT input with a concrete INT shift count", () => { + // The shift count is always INT regardless of the operand width; + // pin it so a registry change that drops the specific-type + // constraint doesn't silently turn N into ANY_INT. + const shl = fnByName.get("SHL")!; + expect(shl.returnType).toBe("ANY_BIT"); + expect(shl.parameters).toEqual([ + { name: "IN", type: "ANY_BIT", direction: "input" }, + { name: "N", type: "INT", direction: "input" }, + ]); + expect(shl.variadic).toBeUndefined(); + }); + + it("functions are sorted alphabetically for diff stability", () => { + // The synthesis sorts the manifest array so `git diff` on + // libs/iec-std-functions.stlib stays small when the registry + // changes — an unsorted append elsewhere in the array would + // produce noisy reorder churn. + const names = fns.map((f) => f.name); + const sorted = [...names].sort((a, b) => a.localeCompare(b)); + expect(names).toEqual(sorted); + }); +}); diff --git a/tests/semantic/date-time-arithmetic.test.ts b/tests/semantic/date-time-arithmetic.test.ts new file mode 100644 index 0000000..c518567 --- /dev/null +++ b/tests/semantic/date-time-arithmetic.test.ts @@ -0,0 +1,148 @@ +/** + * IEC 61131-3 date/time arithmetic tests. + * + * Locks in the operator-result rules from §6.6.2.2 of the standard: + * - DT/DATE/TOD - DT/DATE/TOD = TIME (duration) + * - DT/DATE/TOD ± TIME = DT/DATE/TOD (instant offset) + * - TIME + DT/DATE/TOD = DT/DATE/TOD (commutative addition) + * + * Without these rules, the type checker would collapse `DT - DT` to DT + * and reject assignment to a TIME-typed local — breaking the RTC + * function block (which captures `OFFSET := PDT - CURRENT_TIME` between + * a preset and a wall-clock instant) along with any user code doing + * date arithmetic. + */ + +import { describe, it, expect } from "vitest"; +import { compile } from "../../src/index.js"; + +/** Compiles `body` inside a minimal PROGRAM and returns the result. */ +function compileBody(decls: string, body: string) { + return compile(` + PROGRAM main + VAR + ${decls} + END_VAR + ${body} + END_PROGRAM + `); +} + +describe("date/time arithmetic type rules", () => { + describe("instant - instant → TIME", () => { + it("DT - DT yields a value assignable to a TIME local", () => { + const result = compileBody( + `t1 : DT := DT#2026-01-01-00:00:00 ; + t2 : DT := DT#2026-01-01-00:00:00 ; + d : TIME ;`, + `d := t1 - t2 ;`, + ); + expect(result.errors).toEqual([]); + expect(result.success).toBe(true); + }); + + it("DATE - DATE yields a value assignable to a TIME local", () => { + const result = compileBody( + `d1 : DATE := D#2026-01-01 ; + d2 : DATE := D#2026-01-01 ; + span : TIME ;`, + `span := d1 - d2 ;`, + ); + expect(result.errors).toEqual([]); + expect(result.success).toBe(true); + }); + + it("TOD - TOD yields a value assignable to a TIME local", () => { + const result = compileBody( + `t1 : TOD := TOD#12:00:00 ; + t2 : TOD := TOD#11:00:00 ; + span : TIME ;`, + `span := t1 - t2 ;`, + ); + expect(result.errors).toEqual([]); + expect(result.success).toBe(true); + }); + }); + + describe("instant ± duration → instant", () => { + it("DT + TIME yields a DT", () => { + const result = compileBody( + `t : DT := DT#2026-01-01-00:00:00 ; + offset : TIME := T#1h ; + later : DT ;`, + `later := t + offset ;`, + ); + expect(result.errors).toEqual([]); + expect(result.success).toBe(true); + }); + + it("DT - TIME yields a DT", () => { + const result = compileBody( + `t : DT := DT#2026-01-01-00:00:00 ; + offset : TIME := T#30m ; + earlier : DT ;`, + `earlier := t - offset ;`, + ); + expect(result.errors).toEqual([]); + expect(result.success).toBe(true); + }); + + it("DATE - TIME yields a DATE", () => { + const result = compileBody( + `d : DATE := D#2026-01-01 ; + offset : TIME := T#1d ; + shifted : DATE ;`, + `shifted := d - offset ;`, + ); + expect(result.errors).toEqual([]); + expect(result.success).toBe(true); + }); + + it("TOD + TIME yields a TOD", () => { + const result = compileBody( + `t : TOD := TOD#12:00:00 ; + offset : TIME := T#5m ; + later : TOD ;`, + `later := t + offset ;`, + ); + expect(result.errors).toEqual([]); + expect(result.success).toBe(true); + }); + }); + + describe("commutative addition: duration + instant → instant", () => { + it("TIME + DT yields a DT", () => { + const result = compileBody( + `t : DT := DT#2026-01-01-00:00:00 ; + offset : TIME := T#1h ; + later : DT ;`, + `later := offset + t ;`, + ); + expect(result.errors).toEqual([]); + expect(result.success).toBe(true); + }); + }); + + describe("rules the standard does NOT permit", () => { + it("rejects assigning DT to a TIME variable directly (no implicit conversion)", () => { + const result = compileBody( + `t : DT := DT#2026-01-01-00:00:00 ; + d : TIME ;`, + `d := t ;`, + ); + expect(result.success).toBe(false); + expect(result.errors.length).toBeGreaterThan(0); + }); + + it("rejects assigning a DT - DT result to a DT (the difference is a TIME)", () => { + const result = compileBody( + `t1 : DT := DT#2026-01-01-00:00:00 ; + t2 : DT := DT#2026-01-01-00:00:00 ; + result : DT ;`, + `result := t1 - t2 ;`, + ); + expect(result.success).toBe(false); + expect(result.errors.length).toBeGreaterThan(0); + }); + }); +}); diff --git a/tests/semantic/iec-types-data.test.ts b/tests/semantic/iec-types-data.test.ts new file mode 100644 index 0000000..d107d9f --- /dev/null +++ b/tests/semantic/iec-types-data.test.ts @@ -0,0 +1,249 @@ +/** + * Tests for the canonical IEC base-type registry — single source of + * truth shipped to downstream tooling as `libs/iec-types.json`. + * + * The goals here are pin-style: + * + * 1. Every entry has the full required shape (no half-populated rows + * sneaking through review). + * 2. The on-disk JSON artefact stays in sync with the in-source TS + * module — they share build-time, but a forgotten `npm run build` + * would still be caught. + * 3. Cross-checks against other in-repo type sources: the ELEMENTARY_TYPES + * AST projection and the parser's elementary-name set both stay + * derived from this list. + */ + +import { describe, it, expect } from "vitest"; +import { readFileSync, existsSync } from "fs"; +import { resolve, dirname } from "path"; +import { fileURLToPath } from "url"; + +import { + IEC_BASE_TYPES, + isBaseTypeName, + lookupBaseType, + type IECTypeMetadata, +} from "../../src/semantic/iec-types-data.js"; +import { ELEMENTARY_TYPES } from "../../src/semantic/type-utils.js"; +import { isElementaryType } from "../../src/semantic/type-registry.js"; + +const __filename = fileURLToPath(import.meta.url); +const projectRoot = resolve(dirname(__filename), "../.."); + +describe("IEC base-type registry", () => { + describe("entry shape", () => { + it("ships at least every IEC 61131-3 elementary type", () => { + const names = IEC_BASE_TYPES.map((t) => t.name); + // Sanity checks across categories — full set is pinned by the + // schema test below; this just guards against catastrophic loss + // (e.g. someone wiping out all bit-string types in a refactor). + expect(names).toContain("BOOL"); + expect(names).toContain("INT"); + expect(names).toContain("REAL"); + expect(names).toContain("TIME"); + expect(names).toContain("DT"); + expect(names).toContain("STRING"); + expect(names).toContain("WSTRING"); + }); + + it.each(IEC_BASE_TYPES.map((t) => [t.name, t]))( + "%s has all required fields populated", + (_name, t: IECTypeMetadata) => { + expect(t.name).toMatch(/^[A-Z][A-Z0-9_]*$/); + expect(t.aliases).toBeInstanceOf(Array); + expect(typeof t.byteSize).toBe("number"); + expect(t.byteSize).toBeGreaterThanOrEqual(0); + expect(typeof t.bits).toBe("number"); + expect(t.bits).toBeGreaterThanOrEqual(0); + expect(["boolean", "object"]).toContain(typeof t.signed); // bool or null + expect(t.cppType).toMatch(/^[A-Za-z_][A-Za-z0-9_<>]*$/); + expect(t.wireFormat).toBeTruthy(); + expect(t.xml.elementName).toBeTruthy(); + expect(typeof t.xml.plcopenStandard).toBe("boolean"); + }, + ); + + it("relates `bits` to `byteSize` correctly (bits == byteSize*8 except BOOL=1, strings=0)", () => { + // BOOL is 1 logical bit but stored as 1 byte; STRING/WSTRING + // are variable-width (both fields 0). Everything else must + // satisfy bits == byteSize * 8 — a typo in either field would + // surface here. + for (const t of IEC_BASE_TYPES) { + if (t.name === "BOOL") { + expect(t.bits).toBe(1); + expect(t.byteSize).toBe(1); + } else if (t.byteSize === 0) { + expect(t.bits).toBe(0); + } else { + expect(t.bits).toBe(t.byteSize * 8); + } + } + }); + + it("declares unique canonical names (no duplicates)", () => { + const names = IEC_BASE_TYPES.map((t) => t.name); + expect(new Set(names).size).toBe(names.length); + }); + + it("declares aliases that don't collide with other canonical names", () => { + const canonical = new Set(IEC_BASE_TYPES.map((t) => t.name)); + for (const t of IEC_BASE_TYPES) { + for (const alias of t.aliases) { + expect(canonical).not.toContain(alias); + } + } + }); + + it("uses an even byte size for every fixed-width numeric type", () => { + // Catches typos like `byteSize: 3` for a 32-bit field. STRING/WSTRING + // are variable-width so 0 is allowed; everything else must be a power + // of 2 between 1 and 8. + const allowed = new Set([0, 1, 2, 4, 8]); + for (const t of IEC_BASE_TYPES) { + expect(allowed).toContain(t.byteSize); + } + }); + + it("matches the runtime iec_types.hpp sizeof for fixed-width numerics", () => { + // Ground-truth byte widths from iec_types.hpp typedefs. If the + // runtime ever changes width (e.g. SINT becoming 16-bit, which + // would be wrong but possible in a typo), this guards the + // metadata against silently drifting from the actual wire shape. + const expected: Record = { + BOOL: 1, + BYTE: 1, + SINT: 1, + USINT: 1, + WORD: 2, + INT: 2, + UINT: 2, + DWORD: 4, + DINT: 4, + UDINT: 4, + REAL: 4, + LWORD: 8, + LINT: 8, + ULINT: 8, + LREAL: 8, + TIME: 8, + DATE: 8, + TOD: 8, + DT: 8, + }; + for (const [name, bytes] of Object.entries(expected)) { + const t = lookupBaseType(name); + expect(t, `missing entry for ${name}`).toBeDefined(); + expect(t!.byteSize, `${name} byte size`).toBe(bytes); + } + }); + }); + + describe("PLCopen TC6 XML mapping", () => { + it("uses lowercase element names only for parameterised string types", () => { + // PLCopen TC6 0201 ships and + // lowercase; every other elementaryTypes member is uppercase. A + // future addition that breaks this convention is almost certainly + // a bug — surface it. + for (const t of IEC_BASE_TYPES) { + const isStringy = t.wireFormat === "len8-utf8" || t.wireFormat === "len8-utf16le"; + if (isStringy) { + expect(t.xml.elementName).toBe(t.xml.elementName.toLowerCase()); + } else if (t.xml.plcopenStandard) { + expect(t.xml.elementName).toBe(t.xml.elementName.toUpperCase()); + } + } + }); + }); + + describe("lookup helpers", () => { + it("resolves a canonical name to its metadata entry", () => { + const t = lookupBaseType("INT"); + expect(t?.name).toBe("INT"); + expect(t?.byteSize).toBe(2); + }); + + it("resolves an alias to the same metadata entry as its canonical name", () => { + const tod = lookupBaseType("TOD"); + const alias = lookupBaseType("TIME_OF_DAY"); + expect(alias).toBe(tod); + }); + + it("matches case-insensitively", () => { + expect(lookupBaseType("bool")?.name).toBe("BOOL"); + expect(lookupBaseType("Int")?.name).toBe("INT"); + }); + + it("returns undefined for non-elementary names", () => { + expect(lookupBaseType("MyStruct")).toBeUndefined(); + expect(lookupBaseType("")).toBeUndefined(); + }); + + it("isBaseTypeName accepts canonical names and aliases", () => { + expect(isBaseTypeName("BOOL")).toBe(true); + expect(isBaseTypeName("DATE_AND_TIME")).toBe(true); // alias for DT + expect(isBaseTypeName("MyStruct")).toBe(false); + }); + }); + + describe("cross-source sync", () => { + it("type-registry isElementaryType agrees with the canonical registry", () => { + // type-registry.ts now delegates to isBaseTypeName; this pins the + // contract so a future refactor that re-introduces a duplicate + // hardcoded list breaks loudly. + for (const t of IEC_BASE_TYPES) { + expect(isElementaryType(t.name)).toBe(true); + for (const alias of t.aliases) { + expect(isElementaryType(alias)).toBe(true); + } + } + expect(isElementaryType("MyStruct")).toBe(false); + }); + + it("type-utils ELEMENTARY_TYPES AST map is derived from the canonical registry", () => { + // Every canonical name and every alias must round-trip through + // the AST projection with sizeBits == metadata.bits. + for (const t of IEC_BASE_TYPES) { + const entry = ELEMENTARY_TYPES[t.name]; + expect(entry?.name).toBe(t.name); + expect(entry?.sizeBits).toBe(t.bits); + for (const alias of t.aliases) { + const aliasEntry = ELEMENTARY_TYPES[alias]; + expect(aliasEntry?.name).toBe(alias); + expect(aliasEntry?.sizeBits).toBe(t.bits); + } + } + }); + }); + + describe("libs/iec-types.json artefact", () => { + const jsonPath = resolve(projectRoot, "libs/iec-types.json"); + + it("exists (run `npm run build` if this fails)", () => { + expect(existsSync(jsonPath)).toBe(true); + }); + + it("matches the in-source IEC_BASE_TYPES exactly", () => { + // Both source and artefact are committed-or-built together; a + // failure here means someone edited iec-types-data.ts but + // skipped the rebuild. globalSetup runs `npm run build` so this + // should be self-healing under CI, but still pin the assertion. + const onDisk = JSON.parse(readFileSync(jsonPath, "utf-8")) as { + elementaryTypes: IECTypeMetadata[]; + }; + // Spread to drop the readonly modifier so deep-equal compares + // structurally instead of by readonly-ness. + expect(onDisk.elementaryTypes).toEqual( + IEC_BASE_TYPES.map((t) => ({ ...t, aliases: [...t.aliases] })), + ); + }); + + it("declares a schemaVersion (parsable as a number)", () => { + const onDisk = JSON.parse(readFileSync(jsonPath, "utf-8")) as { + schemaVersion: number; + }; + expect(typeof onDisk.schemaVersion).toBe("number"); + expect(onDisk.schemaVersion).toBeGreaterThanOrEqual(1); + }); + }); +}); diff --git a/vscode-extension/esbuild.mjs b/vscode-extension/esbuild.mjs index 1b2bdd2..f48e7d1 100644 --- a/vscode-extension/esbuild.mjs +++ b/vscode-extension/esbuild.mjs @@ -33,12 +33,11 @@ await esbuild.build({ outfile: "./out/server.js", }); -// Copy runtime files and bundled libraries for .vsix packaging +// Copy runtime files for .vsix packaging. const copies = [ { src: path.resolve(__dirname, "..", "src", "runtime", "include"), dest: path.resolve(__dirname, "runtime", "include") }, - { src: path.resolve(__dirname, "..", "src", "runtime", "repl"), dest: path.resolve(__dirname, "runtime", "repl") }, - { src: path.resolve(__dirname, "..", "src", "runtime", "test"), dest: path.resolve(__dirname, "runtime", "test") }, - { src: path.resolve(__dirname, "..", "libs"), dest: path.resolve(__dirname, "bundled-libs") }, + { src: path.resolve(__dirname, "..", "src", "runtime", "repl"), dest: path.resolve(__dirname, "runtime", "repl") }, + { src: path.resolve(__dirname, "..", "src", "runtime", "test"), dest: path.resolve(__dirname, "runtime", "test") }, ]; for (const { src, dest } of copies) { @@ -50,4 +49,36 @@ for (const { src, dest } of copies) { } } +// Sync the compiled library archives into bundled-libs/. We copy ONLY +// the .stlib build artefacts — not the libs/ directory recursively — so +// libs/sources/ (the canonical .st + library.json source-of-truth on +// disk) doesn't end up bloating every .vsix. The .stlib archives must +// already exist; running `npm run build` from the repo root regenerates +// them via scripts/rebuild-libs.mjs. +const libsDir = path.resolve(__dirname, "..", "libs"); +const bundledLibsDir = path.resolve(__dirname, "bundled-libs"); +fs.mkdirSync(bundledLibsDir, { recursive: true }); +let stlibCount = 0; +try { + for (const entry of fs.readdirSync(libsDir, { withFileTypes: true })) { + if (!entry.isFile() || !entry.name.endsWith(".stlib")) continue; + fs.copyFileSync( + path.join(libsDir, entry.name), + path.join(bundledLibsDir, entry.name), + ); + stlibCount++; + } +} catch (err) { + console.warn(`Skipped copying .stlib files: ${err instanceof Error ? err.message : String(err)}`); +} +if (stlibCount === 0) { + console.warn( + "No .stlib archives found in libs/ — run `npm run build` from the " + + "repo root before bundling the extension. The .vsix will ship " + + "without bundled libraries.", + ); +} else { + console.log(`Copied ${stlibCount} .stlib archive(s) → bundled-libs/`); +} + console.log("Bundled client and server.");