@tsplc/compiler 0.2.9 → 0.2.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/backends/codesys/emit.ts +24 -41
- package/backends/codesys/global-names.ts +49 -0
- package/backends/codesys/plan.ts +4 -89
- package/backends/codesys/task-access.ts +125 -0
- package/dist/cli.js +50 -48
- package/dist/cli.js.map +5 -5
- package/dist/codesys.js +360 -307
- package/dist/codesys.js.map +9 -8
- package/dist/index.js +23 -7
- package/dist/index.js.map +4 -4
- package/dist/ir.js +52 -2
- package/dist/ir.js.map +4 -4
- package/ir/declarations.ts +12 -5
- package/ir/model.ts +40 -1
- package/package.json +6 -6
- package/project/plant.ts +22 -9
- package/project/server.ts +43 -13
- package/src/frontend/async.ts +9 -4
- package/src/frontend/typescript.ts +21 -7
- package/types/globals.d.ts +6 -0
- package/types/index.d.ts +37 -1
package/ir/declarations.ts
CHANGED
|
@@ -111,11 +111,18 @@ export class ModuleDeclarations {
|
|
|
111
111
|
block.locals.length ||
|
|
112
112
|
!matches(block.inputs, expected.inputs) ||
|
|
113
113
|
!matches(block.outputs, expected.outputs) ||
|
|
114
|
-
block.outputs.some((
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
114
|
+
block.outputs.some(({ initial }) => {
|
|
115
|
+
switch (initial?.kind) {
|
|
116
|
+
case "bool":
|
|
117
|
+
return initial.value !== false;
|
|
118
|
+
case "duration":
|
|
119
|
+
return initial.nanoseconds !== "0";
|
|
120
|
+
case "integer":
|
|
121
|
+
return initial.value !== "0";
|
|
122
|
+
default:
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
})
|
|
119
126
|
)
|
|
120
127
|
reject("Invalid canonical standard block definition.", block.span);
|
|
121
128
|
}
|
package/ir/model.ts
CHANGED
|
@@ -158,7 +158,7 @@ export interface PlcFunction {
|
|
|
158
158
|
export type MathHelper = "min" | "max" | "clamp";
|
|
159
159
|
|
|
160
160
|
// Native vendor blocks under their TypeScript names. Ports are [name, native name, type];
|
|
161
|
-
// every output starts
|
|
161
|
+
// every output starts at its type's default, matching the vendor library blocks.
|
|
162
162
|
const timer = (input: string, output: string) =>
|
|
163
163
|
({
|
|
164
164
|
inputs: [
|
|
@@ -184,6 +184,45 @@ export const standardBlocks = {
|
|
|
184
184
|
inputs: [["signal", "CLK", "BOOL"]],
|
|
185
185
|
outputs: [["fell", "Q", "BOOL"]],
|
|
186
186
|
},
|
|
187
|
+
UpCounter: {
|
|
188
|
+
native: "CTU",
|
|
189
|
+
inputs: [
|
|
190
|
+
["countUp", "CU", "BOOL"],
|
|
191
|
+
["reset", "RESET", "BOOL"],
|
|
192
|
+
["preset", "PV", "WORD"],
|
|
193
|
+
],
|
|
194
|
+
outputs: [
|
|
195
|
+
["reachedPreset", "Q", "BOOL"],
|
|
196
|
+
["value", "CV", "WORD"],
|
|
197
|
+
],
|
|
198
|
+
},
|
|
199
|
+
DownCounter: {
|
|
200
|
+
native: "CTD",
|
|
201
|
+
inputs: [
|
|
202
|
+
["countDown", "CD", "BOOL"],
|
|
203
|
+
["load", "LOAD", "BOOL"],
|
|
204
|
+
["preset", "PV", "WORD"],
|
|
205
|
+
],
|
|
206
|
+
outputs: [
|
|
207
|
+
["atZero", "Q", "BOOL"],
|
|
208
|
+
["value", "CV", "WORD"],
|
|
209
|
+
],
|
|
210
|
+
},
|
|
211
|
+
UpDownCounter: {
|
|
212
|
+
native: "CTUD",
|
|
213
|
+
inputs: [
|
|
214
|
+
["countUp", "CU", "BOOL"],
|
|
215
|
+
["countDown", "CD", "BOOL"],
|
|
216
|
+
["reset", "RESET", "BOOL"],
|
|
217
|
+
["load", "LOAD", "BOOL"],
|
|
218
|
+
["preset", "PV", "WORD"],
|
|
219
|
+
],
|
|
220
|
+
outputs: [
|
|
221
|
+
["reachedPreset", "QU", "BOOL"],
|
|
222
|
+
["atZero", "QD", "BOOL"],
|
|
223
|
+
["value", "CV", "WORD"],
|
|
224
|
+
],
|
|
225
|
+
},
|
|
187
226
|
Blinker: {
|
|
188
227
|
native: "Util.BLINK",
|
|
189
228
|
inputs: [
|
package/package.json
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"url": "git+https://github.com/livingforjesus/tsplc.git",
|
|
18
18
|
"directory": "packages/compiler"
|
|
19
19
|
},
|
|
20
|
-
"version": "0.2.
|
|
20
|
+
"version": "0.2.11",
|
|
21
21
|
"type": "module",
|
|
22
22
|
"exports": {
|
|
23
23
|
".": {
|
|
@@ -90,14 +90,14 @@
|
|
|
90
90
|
"bun": ">=1.4.3"
|
|
91
91
|
},
|
|
92
92
|
"dependencies": {
|
|
93
|
-
"@tsplc/agent": "0.2.
|
|
94
|
-
"@tsplc/build": "0.2.
|
|
95
|
-
"@tsplc/config": "0.2.
|
|
96
|
-
"@tsplc/typegen": "0.2.
|
|
93
|
+
"@tsplc/agent": "0.2.11",
|
|
94
|
+
"@tsplc/build": "0.2.11",
|
|
95
|
+
"@tsplc/config": "0.2.11",
|
|
96
|
+
"@tsplc/typegen": "0.2.11",
|
|
97
97
|
"typescript": "6.0.3",
|
|
98
98
|
"zod": "4.3.6",
|
|
99
99
|
"@types/bun": "1.4.2",
|
|
100
|
-
"@tsplc/server": "0.2.
|
|
100
|
+
"@tsplc/server": "0.2.11"
|
|
101
101
|
},
|
|
102
102
|
"bin": {
|
|
103
103
|
"tsplc": "./dist/cli.js"
|
package/project/plant.ts
CHANGED
|
@@ -14,7 +14,7 @@ import { hasErrors } from "@tsplc/compiler/ir";
|
|
|
14
14
|
import { generateProject } from "@tsplc/typegen";
|
|
15
15
|
import { z } from "zod";
|
|
16
16
|
import { buildProject, projectTargets } from "./project.ts";
|
|
17
|
-
import {
|
|
17
|
+
import { bundleServer } from "./server.ts";
|
|
18
18
|
|
|
19
19
|
export const plantCommands = new Set([
|
|
20
20
|
"deploy",
|
|
@@ -107,6 +107,15 @@ const askCredentials = async (): Promise<Credentials> => ({
|
|
|
107
107
|
|
|
108
108
|
const progress = (message: string) => console.log(` ${message}`);
|
|
109
109
|
|
|
110
|
+
/** Prints progress with the minutes and seconds since it was made, so the slow steps show. */
|
|
111
|
+
const timedProgress = () => {
|
|
112
|
+
const start = Date.now();
|
|
113
|
+
return (message: string) => {
|
|
114
|
+
const seconds = Math.round((Date.now() - start) / 1000);
|
|
115
|
+
progress(`${Math.floor(seconds / 60)}:${String(seconds % 60).padStart(2, "0")} ${message}`);
|
|
116
|
+
};
|
|
117
|
+
};
|
|
118
|
+
|
|
110
119
|
const connect = () => {
|
|
111
120
|
const environment = z
|
|
112
121
|
.object({
|
|
@@ -168,7 +177,7 @@ const contractVariables = async (config: LoadedConfig["config"], root: string) =
|
|
|
168
177
|
});
|
|
169
178
|
};
|
|
170
179
|
|
|
171
|
-
/** Compiles the production program and its server into the files `tsplc deploy` uploads. */
|
|
180
|
+
/** Compiles the production program and bundles its server into the files `tsplc deploy` uploads. */
|
|
172
181
|
const prepareRelease = async (file: string, loaded: LoadedConfig, flags: PlantFlags) => {
|
|
173
182
|
const { config, root } = loaded;
|
|
174
183
|
if (!config.compiler) throw new Error("tsplc deploy deploys tsPLC programs; configure compiler.");
|
|
@@ -194,17 +203,17 @@ const prepareRelease = async (file: string, loaded: LoadedConfig, flags: PlantFl
|
|
|
194
203
|
{ path: "template.project", content: Bun.file(settings.template) },
|
|
195
204
|
...libraries.map((library) => ({ path: library.release, content: Bun.file(library.path) })),
|
|
196
205
|
];
|
|
197
|
-
// Plain TypeScript programs emit their generated modules under `.tsplc/`.
|
|
198
|
-
for await (const source of new Bun.Glob("
|
|
206
|
+
// The agent compiles only the ST. Plain TypeScript programs emit their generated modules under `.tsplc/`.
|
|
207
|
+
for await (const source of new Bun.Glob("**/*.st").scan({ cwd: settings.sourceDir, dot: true }))
|
|
199
208
|
files.push({
|
|
200
209
|
path: `st/${portable(source)}`,
|
|
201
210
|
content: Bun.file(resolve(settings.sourceDir, source)),
|
|
202
211
|
});
|
|
203
212
|
let server: string | undefined;
|
|
204
213
|
if (config.server?.runtime) {
|
|
205
|
-
const
|
|
206
|
-
server = `server/${basename(
|
|
207
|
-
files.push({ path: server, content: Bun.file(
|
|
214
|
+
const script = await bundleServer(config, root);
|
|
215
|
+
server = `server/${basename(script)}`;
|
|
216
|
+
files.push({ path: server, content: Bun.file(script) });
|
|
208
217
|
}
|
|
209
218
|
const manifest: ReleaseManifest = {
|
|
210
219
|
// Paths are relative to the release; the agent supplies the output and controller settings.
|
|
@@ -239,8 +248,10 @@ const deploy = async (
|
|
|
239
248
|
if (status.login) throw new Error("A login is open; log out before deploying: tsplc logout");
|
|
240
249
|
const target = !status.target || flags.select ? await selectTarget(agent) : status.target;
|
|
241
250
|
console.log(`Building the release for ${target.host}…`);
|
|
251
|
+
const building = timedProgress();
|
|
242
252
|
const { release, diagnostics } = await prepareRelease(file, loaded, flags);
|
|
243
253
|
if (!release) return { diagnostics };
|
|
254
|
+
building("Built");
|
|
244
255
|
if (
|
|
245
256
|
flags.download &&
|
|
246
257
|
!(await confirm(
|
|
@@ -258,8 +269,10 @@ const deploy = async (
|
|
|
258
269
|
console.log(
|
|
259
270
|
release.manifest.server ? "Deploying the server and the program…" : "Deploying the program…",
|
|
260
271
|
);
|
|
272
|
+
const deploying = timedProgress();
|
|
273
|
+
deploying("Uploading");
|
|
261
274
|
try {
|
|
262
|
-
return await agent.deploy(release, settings,
|
|
275
|
+
return await agent.deploy(release, settings, deploying);
|
|
263
276
|
} catch (error) {
|
|
264
277
|
if (
|
|
265
278
|
!(error instanceof AgentOperationError && error.downloadRequired) ||
|
|
@@ -269,7 +282,7 @@ const deploy = async (
|
|
|
269
282
|
))
|
|
270
283
|
)
|
|
271
284
|
throw error;
|
|
272
|
-
return agent.deploy(release, { ...settings, download: true },
|
|
285
|
+
return agent.deploy(release, { ...settings, download: true }, timedProgress());
|
|
273
286
|
}
|
|
274
287
|
};
|
|
275
288
|
|
package/project/server.ts
CHANGED
|
@@ -18,20 +18,11 @@ const kebabCase = (name: string) =>
|
|
|
18
18
|
.replace(/^-|-$/g, "")
|
|
19
19
|
.toLowerCase();
|
|
20
20
|
|
|
21
|
-
/**
|
|
22
|
-
|
|
23
|
-
const
|
|
24
|
-
if (!
|
|
25
|
-
const runtime = settings.runtime;
|
|
21
|
+
/** The host entry, type-checked as it will be built. */
|
|
22
|
+
const checkedServerEntry = (config: ResolvedTsplcConfig, root: string) => {
|
|
23
|
+
const runtime = config.server?.runtime;
|
|
24
|
+
if (!runtime) throw new Error("Configure server.runtime to build the server.");
|
|
26
25
|
const entry = resolveServerModule(root, runtime.entry);
|
|
27
|
-
const windows = runtime.target
|
|
28
|
-
? runtime.target.includes("windows")
|
|
29
|
-
: process.platform === "win32";
|
|
30
|
-
const outFile = resolve(
|
|
31
|
-
root,
|
|
32
|
-
"build/server",
|
|
33
|
-
`${kebabCase(config.name)}-services${windows ? ".exe" : ""}`,
|
|
34
|
-
);
|
|
35
26
|
const tsconfig = ts.findConfigFile(dirname(entry), ts.sys.fileExists);
|
|
36
27
|
if (!tsconfig) throw new Error("Server entry requires a tsconfig.json.");
|
|
37
28
|
const read = ts.readConfigFile(tsconfig, ts.sys.readFile);
|
|
@@ -51,6 +42,45 @@ export const buildServer = async (config: ResolvedTsplcConfig, root: string) =>
|
|
|
51
42
|
getNewLine: () => "\n",
|
|
52
43
|
}),
|
|
53
44
|
);
|
|
45
|
+
return { entry, runtime };
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Bundles the host entry, which starts its own listener, into one minified script,
|
|
50
|
+
* `build/server/<name>-services.js`, which the plant agent runs on its own Bun. It is a few MB
|
|
51
|
+
* where an executable, which embeds Bun, is over 100, and deployments upload it.
|
|
52
|
+
*/
|
|
53
|
+
export const bundleServer = async (config: ResolvedTsplcConfig, root: string) => {
|
|
54
|
+
const { entry } = checkedServerEntry(config, root);
|
|
55
|
+
const outFile = resolve(root, "build/server", `${kebabCase(config.name)}-services.js`);
|
|
56
|
+
const result = await Bun.build({
|
|
57
|
+
entrypoints: [entry],
|
|
58
|
+
target: "bun",
|
|
59
|
+
minify: true,
|
|
60
|
+
env: "disable",
|
|
61
|
+
});
|
|
62
|
+
if (!result.success) throw new AggregateError(result.logs, "Server bundle build failed.");
|
|
63
|
+
const [script, ...assets] = result.outputs;
|
|
64
|
+
if (!script || assets.length)
|
|
65
|
+
throw new Error(
|
|
66
|
+
`The server bundle needs files beside its script (${assets.map(({ path }) => path).join(", ")}), which deployments don't carry.`,
|
|
67
|
+
);
|
|
68
|
+
await mkdir(dirname(outFile), { recursive: true });
|
|
69
|
+
await Bun.write(outFile, script);
|
|
70
|
+
return outFile;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
/** Compiles the host entry, which starts its own listener, into `build/server/<name>-services`. */
|
|
74
|
+
export const buildServer = async (config: ResolvedTsplcConfig, root: string) => {
|
|
75
|
+
const { entry, runtime } = checkedServerEntry(config, root);
|
|
76
|
+
const windows = runtime.target
|
|
77
|
+
? runtime.target.includes("windows")
|
|
78
|
+
: process.platform === "win32";
|
|
79
|
+
const outFile = resolve(
|
|
80
|
+
root,
|
|
81
|
+
"build/server",
|
|
82
|
+
`${kebabCase(config.name)}-services${windows ? ".exe" : ""}`,
|
|
83
|
+
);
|
|
54
84
|
await mkdir(dirname(outFile), { recursive: true });
|
|
55
85
|
// Compile beside the output so dependency resolution starts from the owning project.
|
|
56
86
|
const staging = await mkdtemp(join(dirname(outFile), ".tsplc-server-"));
|
package/src/frontend/async.ts
CHANGED
|
@@ -932,17 +932,22 @@ protected execute(input:{}):void {}
|
|
|
932
932
|
const milliseconds =
|
|
933
933
|
Number(interval.arguments[0]!.text) *
|
|
934
934
|
(official(interval.expression, "seconds") ? 1000 : 1);
|
|
935
|
+
const taskPriority = Number(priority.text);
|
|
935
936
|
if (
|
|
936
937
|
!Number.isSafeInteger(milliseconds) ||
|
|
937
938
|
milliseconds <= 0 ||
|
|
938
939
|
milliseconds > 4294967295 ||
|
|
939
|
-
Number(
|
|
940
|
-
|
|
940
|
+
!Number.isInteger(taskPriority) ||
|
|
941
|
+
taskPriority < 1 ||
|
|
942
|
+
taskPriority > 31
|
|
941
943
|
)
|
|
942
|
-
fail(
|
|
944
|
+
fail(
|
|
945
|
+
init,
|
|
946
|
+
"Background interval must be positive and priority must be an integer in 1..31.",
|
|
947
|
+
);
|
|
943
948
|
const schedule = {
|
|
944
949
|
intervalNanoseconds: String(BigInt(milliseconds) * 1000000n),
|
|
945
|
-
priority:
|
|
950
|
+
priority: taskPriority,
|
|
946
951
|
mailbox: dec.name.text,
|
|
947
952
|
worker,
|
|
948
953
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { runtimeSources } from "./module-graph.ts";
|
|
2
2
|
import ts from "typescript";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
|
-
import { mkdirSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { mkdirSync, realpathSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { dirname, join, relative, resolve } from "node:path";
|
|
6
6
|
import {
|
|
7
7
|
instancedBlock,
|
|
@@ -202,6 +202,24 @@ export const typeCheckOnly: ts.CompilerOptions = {
|
|
|
202
202
|
tsBuildInfoFile: undefined,
|
|
203
203
|
};
|
|
204
204
|
|
|
205
|
+
const sdkFor = (project: string, options: ts.CompilerOptions): string => {
|
|
206
|
+
const name = "@tsplc/compiler/globals";
|
|
207
|
+
const resolveSdk = (from: string) => createRequire(from).resolve(name).replaceAll("\\", "/");
|
|
208
|
+
try {
|
|
209
|
+
const installed = resolveSdk(project);
|
|
210
|
+
const resolved = ts.resolveModuleName(name, project, options, ts.sys).resolvedModule;
|
|
211
|
+
// TypeScript may preserve a workspace symlink. A path alias may only stand in
|
|
212
|
+
// for the SDK if it resolves to the same installed declaration.
|
|
213
|
+
if (resolved && realpathSync(resolved.resolvedFileName) === realpathSync(installed))
|
|
214
|
+
return resolved.resolvedFileName;
|
|
215
|
+
return installed;
|
|
216
|
+
} catch (cause) {
|
|
217
|
+
if (!(cause instanceof Error) || !("code" in cause) || cause.code !== "MODULE_NOT_FOUND")
|
|
218
|
+
throw cause;
|
|
219
|
+
return resolveSdk(import.meta.url);
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
|
|
205
223
|
export function analyze(options: FrontendOptions): FrontendResult {
|
|
206
224
|
const filename = resolve(options.tsconfig);
|
|
207
225
|
const config = ts.readConfigFile(filename, ts.sys.readFile);
|
|
@@ -214,11 +232,6 @@ export function analyze(options: FrontendOptions): FrontendResult {
|
|
|
214
232
|
filename,
|
|
215
233
|
);
|
|
216
234
|
if (parsed.errors.length) return { diagnostics: parsed.errors.map(tsDiagnostic) };
|
|
217
|
-
// TypeScript stores SourceFile paths with forward slashes on every host.
|
|
218
|
-
// Normalize require.resolve once so canonical SDK identity also works on Windows.
|
|
219
|
-
const sdk = createRequire(import.meta.url)
|
|
220
|
-
.resolve("@tsplc/compiler/globals")
|
|
221
|
-
.replaceAll("\\", "/");
|
|
222
235
|
const programFiles = Object.values(options.programs).map((entry) =>
|
|
223
236
|
resolve(dirname(filename), entry.module),
|
|
224
237
|
);
|
|
@@ -229,7 +242,6 @@ export function analyze(options: FrontendOptions): FrontendResult {
|
|
|
229
242
|
(file) => /\.d\.[cm]?ts$/.test(file) && file.startsWith(`${dirname(filename)}/`),
|
|
230
243
|
);
|
|
231
244
|
const projectFiles = scope === "project" ? parsed.fileNames : ambient;
|
|
232
|
-
const rootNames = [...new Set([...projectFiles, ...programFiles, sdk])];
|
|
233
245
|
const compilerOptions: ts.CompilerOptions = {
|
|
234
246
|
...parsed.options,
|
|
235
247
|
...typeCheckOnly,
|
|
@@ -251,6 +263,8 @@ export function analyze(options: FrontendOptions): FrontendResult {
|
|
|
251
263
|
// Nothing is emitted, and a service client's router type imports modules outside these (TS6059).
|
|
252
264
|
delete compilerOptions.rootDir;
|
|
253
265
|
delete compilerOptions.outDir;
|
|
266
|
+
const sdk = sdkFor(filename, compilerOptions);
|
|
267
|
+
const rootNames = [...new Set([...projectFiles, ...programFiles, sdk])];
|
|
254
268
|
let program = ts.createProgram(rootNames, compilerOptions);
|
|
255
269
|
const plcFiles = (program: ts.Program) => {
|
|
256
270
|
const files = new Set(runtimeSources(program));
|
package/types/globals.d.ts
CHANGED
|
@@ -24,6 +24,12 @@ declare global {
|
|
|
24
24
|
const RisingEdge: typeof import("./index").RisingEdge;
|
|
25
25
|
type FallingEdge = import("./index").FallingEdge;
|
|
26
26
|
const FallingEdge: typeof import("./index").FallingEdge;
|
|
27
|
+
type UpCounter = import("./index").UpCounter;
|
|
28
|
+
const UpCounter: typeof import("./index").UpCounter;
|
|
29
|
+
type DownCounter = import("./index").DownCounter;
|
|
30
|
+
const DownCounter: typeof import("./index").DownCounter;
|
|
31
|
+
type UpDownCounter = import("./index").UpDownCounter;
|
|
32
|
+
const UpDownCounter: typeof import("./index").UpDownCounter;
|
|
27
33
|
const ref: typeof import("./index").ref;
|
|
28
34
|
const retain: typeof import("./index").retain;
|
|
29
35
|
const ms: typeof import("./index").ms;
|
package/types/index.d.ts
CHANGED
|
@@ -68,7 +68,7 @@ export declare abstract class FunctionBlock<I, O = Record<never, never>> {
|
|
|
68
68
|
protected abstract execute(input: I): keyof O extends never ? void : O;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
/**
|
|
71
|
+
/** Starts on, then alternates `onTime` and `offTime`. Keeps its last `on` when disabled. CODESYS Util.BLINK. */
|
|
72
72
|
export declare class Blinker extends FunctionBlock<
|
|
73
73
|
{ enabled: BOOL; offTime: TIME; onTime: TIME },
|
|
74
74
|
{ on: BOOL }
|
|
@@ -109,3 +109,39 @@ export declare class RisingEdge extends FunctionBlock<{ signal: BOOL }, { rose:
|
|
|
109
109
|
export declare class FallingEdge extends FunctionBlock<{ signal: BOOL }, { fell: BOOL }> {
|
|
110
110
|
protected execute(input: { signal: BOOL }): { fell: BOOL };
|
|
111
111
|
}
|
|
112
|
+
|
|
113
|
+
/** Counts rising `countUp` edges. `reset` clears `value`. `reachedPreset` indicates `value >= preset`. CODESYS CTU. */
|
|
114
|
+
export declare class UpCounter extends FunctionBlock<
|
|
115
|
+
{ countUp: BOOL; reset: BOOL; preset: WORD },
|
|
116
|
+
{ reachedPreset: BOOL; value: WORD }
|
|
117
|
+
> {
|
|
118
|
+
protected execute(input: { countUp: BOOL; reset: BOOL; preset: WORD }): {
|
|
119
|
+
reachedPreset: BOOL;
|
|
120
|
+
value: WORD;
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Counts down on rising `countDown` edges. `load` sets `value` to `preset`. `atZero` indicates `value = 0`. CODESYS CTD. */
|
|
125
|
+
export declare class DownCounter extends FunctionBlock<
|
|
126
|
+
{ countDown: BOOL; load: BOOL; preset: WORD },
|
|
127
|
+
{ atZero: BOOL; value: WORD }
|
|
128
|
+
> {
|
|
129
|
+
protected execute(input: { countDown: BOOL; load: BOOL; preset: WORD }): {
|
|
130
|
+
atZero: BOOL;
|
|
131
|
+
value: WORD;
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** Counts rising edges in either direction. `reset` clears `value`, and `load` sets `value` to `preset`. CODESYS CTUD. */
|
|
136
|
+
export declare class UpDownCounter extends FunctionBlock<
|
|
137
|
+
{ countUp: BOOL; countDown: BOOL; reset: BOOL; load: BOOL; preset: WORD },
|
|
138
|
+
{ reachedPreset: BOOL; atZero: BOOL; value: WORD }
|
|
139
|
+
> {
|
|
140
|
+
protected execute(input: {
|
|
141
|
+
countUp: BOOL;
|
|
142
|
+
countDown: BOOL;
|
|
143
|
+
reset: BOOL;
|
|
144
|
+
load: BOOL;
|
|
145
|
+
preset: WORD;
|
|
146
|
+
}): { reachedPreset: BOOL; atZero: BOOL; value: WORD };
|
|
147
|
+
}
|