nodalis-compiler 1.0.12 → 1.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.0.13] - 2025-12-17
|
|
9
|
+
|
|
10
|
+
- Added cross-compilation for the CPPCompiler. Added more detail to the README for compilers.
|
|
11
|
+
|
|
8
12
|
## [1.0.12] - 2025-12-16
|
|
9
13
|
|
|
10
14
|
- Fixed issue with copying support files for CPP and JS compilers.
|
package/README.md
CHANGED
|
@@ -105,6 +105,64 @@ await app.compile({
|
|
|
105
105
|
|
|
106
106
|
---
|
|
107
107
|
|
|
108
|
+
## 🧠 Compiler Specifics
|
|
109
|
+
|
|
110
|
+
### CPPCompiler
|
|
111
|
+
|
|
112
|
+
`CPPCompiler` translates IEC Ladder Diagram (`.iec`) and Structured Text (`.st`, `.iec`) sources into ANSI C++ output. Depending on the requested output type it either produces compilable sources or invokes the toolchain to emit an executable.
|
|
113
|
+
|
|
114
|
+
#### Dependencies
|
|
115
|
+
|
|
116
|
+
- Uses a default cross-compiler profile tuned for macOS-style Clang/LLVM toolchains when no overrides are provided.
|
|
117
|
+
- Supply a `toolchain.json` file beside your source to describe a custom toolchain. Example:
|
|
118
|
+
|
|
119
|
+
```json
|
|
120
|
+
{
|
|
121
|
+
"linux-arm": "arm-linux-gnueabi-g++",
|
|
122
|
+
"linux-arm64": "aarch64-linux-gnu-g++",
|
|
123
|
+
"linux-x64": "x86_64-linux-gnu-g++",
|
|
124
|
+
"macos-arm64": "clang++",
|
|
125
|
+
"macos-x64": "clang++",
|
|
126
|
+
"windows-x64": "x86_64-w64-mingw32-g++",
|
|
127
|
+
"windows-arm64": "/opt/llvm-mingw/bin/aarch64-w64-mingw32-g++"
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
- Without an explicit file Nodalis falls back to the default compiler for the host OS (`clang++` on macOS, `g++` on Linux, and `cl.exe` or MinGW-w64 `g++` on Windows).
|
|
132
|
+
- Common cross-compiler sources: Homebrew packages (`brew install armmbed/formulae/arm-none-eabi-gcc`) and osxcross for macOS targeting, MinGW-w64/MSYS2 or Visual Studio Build Tools for Windows, and distro packages such as `gcc-arm-linux-gnueabihf` or `x86_64-w64-mingw32-g++` on Linux.
|
|
133
|
+
|
|
134
|
+
#### Variations
|
|
135
|
+
|
|
136
|
+
- Windows builds exclude the OPC/UA client and server components to keep dependencies minimal.
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## 🟦 JSCompiler
|
|
141
|
+
|
|
142
|
+
`JSCompiler` transpiles LD (`.iec`) and ST (`.st`, `.iec`) programs into JavaScript for either **Node.js** or **jint** targets.
|
|
143
|
+
|
|
144
|
+
- Node.js target: emits a Node module in the output directory and installs the needed npm dependencies.
|
|
145
|
+
- jint target: generates a .NET 8 project embedding jint that cross-compiles to Windows, macOS, and Linux for `arm64`, `arm`, and `x64` architectures.
|
|
146
|
+
|
|
147
|
+
### Dependencies
|
|
148
|
+
|
|
149
|
+
- Node.js target requires `node` and `npm` to be available on the host.
|
|
150
|
+
- jint target requires the .NET SDK (8.0+).
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## 🗒 SkipCompiler
|
|
155
|
+
|
|
156
|
+
`SkipCompiler` converts Skipper Sheet (`.skip`) files into three possible targets:
|
|
157
|
+
|
|
158
|
+
- `xml`: produces MTI device-ready XML definitions.
|
|
159
|
+
- `iec`: emits IEC ladder logic mirroring the sheet.
|
|
160
|
+
- `st`: emits Structured Text representing the sheet logic.
|
|
161
|
+
|
|
162
|
+
Choose the desired format via the CLI `--target`/`--outputType` flags.
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
108
166
|
## 🗂 Project Structure
|
|
109
167
|
|
|
110
168
|
| File | Description |
|
package/package.json
CHANGED
|
@@ -28,6 +28,18 @@ import { dirname } from 'node:path';
|
|
|
28
28
|
const __filename = fileURLToPath(import.meta.url);
|
|
29
29
|
const __dirname = dirname(__filename);
|
|
30
30
|
|
|
31
|
+
const DEFAULT_TOOLCHAIN = {
|
|
32
|
+
"linux-arm": "arm-linux-gnueabi-g++",
|
|
33
|
+
"linux-arm64": "aarch64-linux-gnu-g++",
|
|
34
|
+
"linux-x64": "x86_64-linux-gnu-g++",
|
|
35
|
+
"macos-arm64": "clang++",
|
|
36
|
+
"macos-x64": "clang++",
|
|
37
|
+
"windows-x64": "x86_64-w64-mingw32-g++",
|
|
38
|
+
"windows-arm64": "/opt/llvm-mingw/bin/aarch64-w64-mingw32-g++"
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
let ToolChain = { ...DEFAULT_TOOLCHAIN };
|
|
42
|
+
|
|
31
43
|
export class CPPCompiler extends Compiler {
|
|
32
44
|
constructor(options) {
|
|
33
45
|
super(options);
|
|
@@ -43,7 +55,7 @@ export class CPPCompiler extends Compiler {
|
|
|
43
55
|
}
|
|
44
56
|
|
|
45
57
|
get supportedTargetDevices() {
|
|
46
|
-
return ['linux', 'macos', 'windows'];
|
|
58
|
+
return ['linux-arm', "linux-arm64", "linux-x64", 'macos-x64', "macos-arm64", 'windows-x64', "windows-arm64"];
|
|
47
59
|
}
|
|
48
60
|
|
|
49
61
|
get supportedProtocols() {
|
|
@@ -56,6 +68,25 @@ export class CPPCompiler extends Compiler {
|
|
|
56
68
|
|
|
57
69
|
async compile() {
|
|
58
70
|
const { sourcePath, outputPath, target, outputType, resourceName } = this.options;
|
|
71
|
+
|
|
72
|
+
ToolChain = { ...DEFAULT_TOOLCHAIN };
|
|
73
|
+
const sourceDir = fs.lstatSync(sourcePath).isDirectory() ? sourcePath : path.dirname(sourcePath);
|
|
74
|
+
const toolchainConfigPath = path.join(sourceDir, "toolchain.json");
|
|
75
|
+
if (fs.existsSync(toolchainConfigPath)) {
|
|
76
|
+
try {
|
|
77
|
+
const customToolchain = JSON.parse(fs.readFileSync(toolchainConfigPath, "utf-8"));
|
|
78
|
+
if (typeof customToolchain !== "object" || customToolchain === null) {
|
|
79
|
+
throw new Error("The toolchain configuration must be a JSON object.");
|
|
80
|
+
}
|
|
81
|
+
ToolChain = { ...ToolChain, ...customToolchain };
|
|
82
|
+
} catch (err) {
|
|
83
|
+
throw new Error(`Failed to load toolchain configuration from ${toolchainConfigPath}: ${err.message}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
fs.writeFileSync(toolchainConfigPath, JSON.stringify(ToolChain, null, 4));
|
|
88
|
+
}
|
|
89
|
+
|
|
59
90
|
var sourceCode = fs.readFileSync(sourcePath, 'utf-8');
|
|
60
91
|
const filename = path.basename(sourcePath, path.extname(sourcePath));
|
|
61
92
|
const cppFile = path.join(outputPath, `${filename}.cpp`);
|
|
@@ -201,77 +232,247 @@ int main() {
|
|
|
201
232
|
'nodalis.cpp',
|
|
202
233
|
'modbus.h',
|
|
203
234
|
'modbus.cpp',
|
|
204
|
-
"json.hpp"
|
|
205
|
-
"opcua.h",
|
|
206
|
-
"opcua.cpp",
|
|
207
|
-
"open62541.h",
|
|
208
|
-
"open62541.c"
|
|
235
|
+
"json.hpp"
|
|
209
236
|
];
|
|
210
237
|
|
|
238
|
+
if (!target.includes("windows")) {
|
|
239
|
+
coreFiles.push(...["opcua.h",
|
|
240
|
+
"opcua.cpp", "open62541.h",
|
|
241
|
+
"open62541.c"]);
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
coreFiles.push(...["opcua.h",
|
|
245
|
+
"opcua.cpp"]);
|
|
246
|
+
}
|
|
247
|
+
|
|
211
248
|
const coreDir = path.resolve(__dirname + '/support/generic');
|
|
212
249
|
for (const file of coreFiles) {
|
|
213
|
-
fs.copyFileSync(path.join(coreDir, file), path.join(outputPath, file));
|
|
250
|
+
fs.copyFileSync(path.join(target.includes("windows") && file.includes("opc") ? coreDir + "/windows/" : coreDir, file), path.join(outputPath, file));
|
|
214
251
|
}
|
|
215
252
|
|
|
216
253
|
const pathTo = name => path.join(outputPath, name);
|
|
254
|
+
const targetInfo = this.resolveTarget(target);
|
|
217
255
|
|
|
218
256
|
if (outputType === 'executable') {
|
|
219
|
-
|
|
220
|
-
const
|
|
257
|
+
const requestedTarget = target ?? `${targetInfo.os}-${targetInfo.arch}`;
|
|
258
|
+
const hostOs = this.getHostOS();
|
|
259
|
+
const hostArch = this.getHostArch();
|
|
260
|
+
// if (targetInfo.os !== hostOs || targetInfo.arch !== hostArch) {
|
|
261
|
+
// throw new Error(`Cross-compiling to ${requestedTarget} is not supported from a ${hostOs}-${hostArch} host.`);
|
|
262
|
+
// }
|
|
221
263
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
try {
|
|
228
|
-
execSync('g++ --version', { stdio: 'ignore' });
|
|
229
|
-
compiler = 'g++';
|
|
230
|
-
} catch {
|
|
231
|
-
try {
|
|
232
|
-
execSync('cl.exe /?', { stdio: 'ignore' });
|
|
233
|
-
compiler = 'cl.exe';
|
|
234
|
-
} catch {
|
|
235
|
-
throw new Error('No C++ compiler found (clang++, g++, or cl.exe)');
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
264
|
+
const compiler = this.detectCompiler(hostOs, hostArch, targetInfo.os, targetInfo.arch);
|
|
265
|
+
const cCompiler = this.getCCompilerBinary(compiler);
|
|
266
|
+
const archFlags = this.getArchFlags(targetInfo.os, targetInfo.arch, compiler);
|
|
267
|
+
const formatFlags = (flags = []) => (flags.length ? `${flags.join(' ')} ` : '');
|
|
268
|
+
const isWindowsTarget = targetInfo.os === 'windows';
|
|
239
269
|
|
|
240
270
|
// Step 2: Compile open62541.c with C compiler
|
|
241
|
-
const cCompiler = compiler === 'cl.exe' ? 'cl.exe' : compiler.replace('++', '');
|
|
242
271
|
const open62541c = pathTo('open62541.c');
|
|
243
272
|
const open62541o = pathTo('open62541.o');
|
|
244
273
|
|
|
245
|
-
let cCompileCmd;
|
|
246
|
-
if (compiler === 'cl.exe') {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
}
|
|
250
|
-
|
|
274
|
+
let cCompileCmd = "";
|
|
275
|
+
// if (compiler === 'cl.exe') {
|
|
276
|
+
// // Compile C file with cl
|
|
277
|
+
// const cFlagSegment = formatFlags(archFlags.c);
|
|
278
|
+
// cCompileCmd = `cl.exe ${cFlagSegment}/c /TC "${open62541c}" /Fo"${pathTo('open62541.obj')}"`;
|
|
279
|
+
// } else {
|
|
280
|
+
if (!isWindowsTarget) {
|
|
281
|
+
const cFlagSegment = formatFlags(archFlags.c);
|
|
282
|
+
|
|
283
|
+
cCompileCmd = `${cCompiler} ${cFlagSegment}-std=c11 -D_DEFAULT_SOURCE -D_BSD_SOURCE -c "${open62541c}" -o "${open62541o}"`;
|
|
251
284
|
|
|
252
285
|
}
|
|
253
286
|
|
|
254
|
-
execSync(cCompileCmd, { stdio: 'inherit' });
|
|
287
|
+
if (cCompileCmd !== "") execSync(cCompileCmd, { stdio: 'inherit' });
|
|
255
288
|
|
|
256
289
|
// Step 3: Compile C++ files with C++ compiler and link object
|
|
257
290
|
let exeFile = path.join(outputPath, filename);
|
|
258
|
-
if (
|
|
291
|
+
if (isWindowsTarget && !exeFile.endsWith('.exe')) {
|
|
259
292
|
exeFile += '.exe';
|
|
260
293
|
}
|
|
261
294
|
|
|
262
295
|
let cppCompileCmd;
|
|
296
|
+
const inputs = [
|
|
297
|
+
`"${cppFile}"`,
|
|
298
|
+
`"${pathTo('nodalis.cpp')}"`,
|
|
299
|
+
`"${pathTo('modbus.cpp')}"`,
|
|
300
|
+
`"${pathTo('opcua.cpp')}"`
|
|
301
|
+
];
|
|
302
|
+
|
|
303
|
+
if (!isWindowsTarget) inputs.push(`"${open62541o}"`);
|
|
304
|
+
|
|
263
305
|
if (compiler === 'cl.exe') {
|
|
264
|
-
|
|
265
|
-
|
|
306
|
+
const cppFlagSegment = formatFlags(archFlags.cpp);
|
|
307
|
+
cppCompileCmd = `cl.exe ${cppFlagSegment}/EHsc /std:c++17 /Fe:"${exeFile}" ` +
|
|
308
|
+
`"${cppFile}" "${pathTo('nodalis.cpp')}" "${pathTo('modbus.cpp')}" "${pathTo('opcua.cpp')}"`; //"${pathTo('open62541.obj')}"`;
|
|
266
309
|
} else {
|
|
267
|
-
|
|
268
|
-
|
|
310
|
+
const cppFlagSegment = formatFlags(archFlags.cpp);
|
|
311
|
+
cppCompileCmd = `${compiler} ${cppFlagSegment}-std=c++17 -o "${exeFile}" ${inputs.join(' ')} ${archFlags.linker}`;
|
|
269
312
|
}
|
|
270
313
|
|
|
271
314
|
execSync(cppCompileCmd, { stdio: 'inherit' });
|
|
272
315
|
}
|
|
273
316
|
}
|
|
274
317
|
|
|
318
|
+
resolveTarget(target) {
|
|
319
|
+
if (!target || typeof target !== 'string') {
|
|
320
|
+
throw new Error('You must provide a valid target (e.g., linux-x64, macos-arm64).');
|
|
321
|
+
}
|
|
322
|
+
const [osPart, archPart] = target.split('-');
|
|
323
|
+
if (!osPart || !archPart) {
|
|
324
|
+
throw new Error(`Invalid target format: ${target}. Expected <os>-<arch>.`);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const normalizedOs = this.normalizeOs(osPart);
|
|
328
|
+
const normalizedArch = this.normalizeArch(archPart);
|
|
329
|
+
if (!normalizedOs || !normalizedArch) {
|
|
330
|
+
throw new Error(`Unsupported target: ${target}.`);
|
|
331
|
+
}
|
|
332
|
+
return { os: normalizedOs, arch: normalizedArch };
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
normalizeOs(osPart) {
|
|
336
|
+
const map = {
|
|
337
|
+
linux: 'linux',
|
|
338
|
+
macos: 'macos',
|
|
339
|
+
darwin: 'macos',
|
|
340
|
+
windows: 'windows',
|
|
341
|
+
win32: 'windows'
|
|
342
|
+
};
|
|
343
|
+
return map[osPart.toLowerCase()];
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
normalizeArch(archPart) {
|
|
347
|
+
const map = {
|
|
348
|
+
x64: 'x64',
|
|
349
|
+
amd64: 'x64',
|
|
350
|
+
arm64: 'arm64',
|
|
351
|
+
aarch64: 'arm64',
|
|
352
|
+
arm: 'arm'
|
|
353
|
+
};
|
|
354
|
+
return map[archPart.toLowerCase()];
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
getHostOS() {
|
|
358
|
+
const platform = os.platform();
|
|
359
|
+
if (platform === 'win32') return 'windows';
|
|
360
|
+
if (platform === 'darwin') return 'macos';
|
|
361
|
+
if (platform === 'linux') return 'linux';
|
|
362
|
+
throw new Error(`Unsupported host platform: ${platform}`);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
getHostArch() {
|
|
366
|
+
const arch = os.arch();
|
|
367
|
+
if (arch === 'x64') return 'x64';
|
|
368
|
+
if (arch === 'arm64') return 'arm64';
|
|
369
|
+
if (arch.startsWith('arm')) return 'arm';
|
|
370
|
+
throw new Error(`Unsupported host architecture: ${arch}`);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
detectCompiler(hostOs, hostArch, targetOs, targetArch) {
|
|
374
|
+
const hostDefaults = {
|
|
375
|
+
linux: "g++",
|
|
376
|
+
macos: "clang++",
|
|
377
|
+
windows: "cl.exe"
|
|
378
|
+
};
|
|
379
|
+
const hostKey = `${hostOs}-${hostArch}`;
|
|
380
|
+
const targetKey = `${targetOs}-${targetArch}`;
|
|
381
|
+
|
|
382
|
+
const ensureCompilerAvailable = (compilerName, message) => {
|
|
383
|
+
const versionCommand = compilerName === "cl.exe" ? compilerName : `${compilerName} --version`;
|
|
384
|
+
try {
|
|
385
|
+
execSync(versionCommand, { stdio: "ignore" });
|
|
386
|
+
} catch {
|
|
387
|
+
throw new Error(message);
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
if (targetKey === hostKey) {
|
|
392
|
+
const defaultCompiler = hostDefaults[hostOs];
|
|
393
|
+
if (!defaultCompiler) {
|
|
394
|
+
throw new Error(`No default compiler configured for host platform ${hostOs}.`);
|
|
395
|
+
}
|
|
396
|
+
ensureCompilerAvailable(
|
|
397
|
+
defaultCompiler,
|
|
398
|
+
`The default compiler "${defaultCompiler}" is not available. Install it using your package manager (e.g., brew install ${defaultCompiler} or apt install ${defaultCompiler}).
|
|
399
|
+
You can also create a file called "toolchain.json" in your source directory which will supply the path to the gnu c compiler for each platform. See the README file for more details.`
|
|
400
|
+
);
|
|
401
|
+
return defaultCompiler;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
const configuredCompiler = ToolChain[targetKey];
|
|
405
|
+
if (!configuredCompiler) {
|
|
406
|
+
throw new Error(`No cross-compiler is configured for target ${targetKey}. Add it to toolchain.json or update the ToolChain defaults.`);
|
|
407
|
+
}
|
|
408
|
+
ensureCompilerAvailable(
|
|
409
|
+
configuredCompiler,
|
|
410
|
+
`Cross-compiler "${configuredCompiler}" for target ${targetKey} is not available. Install it via your package manager (e.g., brew install ${configuredCompiler} or apt install ${configuredCompiler}).
|
|
411
|
+
You can also create a file called "toolchain.json" in your source directory which will supply the path to the gnu c compiler for each platform. See the README file for more details.`
|
|
412
|
+
);
|
|
413
|
+
return configuredCompiler;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
getCCompilerBinary(cppCompiler) {
|
|
417
|
+
if (cppCompiler === 'cl.exe') {
|
|
418
|
+
return 'cl.exe';
|
|
419
|
+
}
|
|
420
|
+
if (cppCompiler.includes('clang')) {
|
|
421
|
+
return cppCompiler.replace('++', '');
|
|
422
|
+
}
|
|
423
|
+
if (cppCompiler.includes('g++')) {
|
|
424
|
+
return cppCompiler.replace('++', 'cc');
|
|
425
|
+
}
|
|
426
|
+
return 'cc';
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
getArchFlags(osType, arch, compiler) {
|
|
432
|
+
if (compiler === 'cl.exe') {
|
|
433
|
+
return { c: [], cpp: [] };
|
|
434
|
+
}
|
|
435
|
+
let flags = { //default flags are for macos clang
|
|
436
|
+
'linux-x64': [],
|
|
437
|
+
'linux-arm64': [],
|
|
438
|
+
'linux-arm': [],
|
|
439
|
+
'macos-x64': ['-arch', 'x86_64'],
|
|
440
|
+
'macos-arm64': ['-arch', 'arm64'],
|
|
441
|
+
'windows-x64': [],
|
|
442
|
+
'windows-arm64': []
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
let linker = {
|
|
446
|
+
"windows-x64": " -lws2_32 -lcrypt32 -lwsock32 -lole32",
|
|
447
|
+
"windows-arm64": " -lws2_32 -lcrypt32 -lwsock32 -lole32",
|
|
448
|
+
"linux-x64": "",
|
|
449
|
+
"linux-arm64": "",
|
|
450
|
+
"linux-arm": "",
|
|
451
|
+
"macos-x64": "",
|
|
452
|
+
"macos-arm64": "",
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (!compiler.includes("clang")) {
|
|
456
|
+
flags = {
|
|
457
|
+
'linux-x64': ["-D_POSIX_C_SOURCE=200809L -D_GNU_SOURCE -pthread"],
|
|
458
|
+
'linux-arm64': ["-D_POSIX_C_SOURCE=200809L -D_GNU_SOURCE -pthread"],
|
|
459
|
+
'linux-arm': ["-D_POSIX_C_SOURCE=200809L -D_GNU_SOURCE -pthread"],
|
|
460
|
+
'windows-x64': ["-DUA_ARCHITECTURE_WIN32 -D_POSIX_C_SOURCE=200809L -D_GNU_SOURCE"],
|
|
461
|
+
'windows-arm64': ["-DUA_ARCHITECTURE_WIN32 -D_POSIX_C_SOURCE=200809L -D_GNU_SOURCE"]
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
const key = `${osType}-${arch}`;
|
|
466
|
+
|
|
467
|
+
const resolved = flags[key];
|
|
468
|
+
if (!resolved) {
|
|
469
|
+
throw new Error(`Architecture flags are not defined for ${key}.`);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
return { c: resolved, cpp: resolved, linker: linker[key] };
|
|
473
|
+
}
|
|
275
474
|
}
|
|
276
475
|
|
|
476
|
+
|
|
477
|
+
|
|
277
478
|
export default CPPCompiler;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#include "opcua.h"
|
|
2
|
+
#include <iostream>
|
|
3
|
+
|
|
4
|
+
OPCUAClient::OPCUAClient()
|
|
5
|
+
: IOClient("opcua"), endpointUrl("opc.tcp://localhost:4840") {
|
|
6
|
+
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
OPCUAClient::~OPCUAClient() {
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
void OPCUAClient::connect() {
|
|
13
|
+
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
// Implement required IOClient methods
|
|
18
|
+
|
|
19
|
+
bool OPCUAClient::readBit(const std::string& remote, int& result) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
bool OPCUAClient::writeBit(const std::string& remote, int value) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
bool OPCUAClient::readByte(const std::string& remote, uint8_t& result) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
bool OPCUAClient::writeByte(const std::string& remote, uint8_t value) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
bool OPCUAClient::readWord(const std::string& remote, uint16_t& result) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
bool OPCUAClient::writeWord(const std::string& remote, uint16_t value) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
bool OPCUAClient::readDWord(const std::string& remote, uint32_t& result) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
bool OPCUAClient::writeDWord(const std::string& remote, uint32_t value) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
OPCUAServer::OPCUAServer() {
|
|
53
|
+
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
OPCUAServer::~OPCUAServer() {
|
|
57
|
+
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
void OPCUAServer::start() {
|
|
61
|
+
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
void OPCUAServer::stop() {
|
|
65
|
+
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
void OPCUAServer::run() {
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
void OPCUAServer::mapVariable(std::string varname, std::string addr){
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include "nodalis.h"
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class OPCUAClient : public IOClient {
|
|
6
|
+
public:
|
|
7
|
+
OPCUAClient();
|
|
8
|
+
~OPCUAClient();
|
|
9
|
+
|
|
10
|
+
protected:
|
|
11
|
+
void connect() override;
|
|
12
|
+
|
|
13
|
+
bool readBit(const std::string& remote, int& result) override;
|
|
14
|
+
bool writeBit(const std::string& remote, int value) override;
|
|
15
|
+
bool readByte(const std::string& remote, uint8_t& result) override;
|
|
16
|
+
bool writeByte(const std::string& remote, uint8_t value) override;
|
|
17
|
+
bool readWord(const std::string& remote, uint16_t& result) override;
|
|
18
|
+
bool writeWord(const std::string& remote, uint16_t value) override;
|
|
19
|
+
bool readDWord(const std::string& remote, uint32_t& result) override;
|
|
20
|
+
bool writeDWord(const std::string& remote, uint32_t value) override;
|
|
21
|
+
|
|
22
|
+
private:
|
|
23
|
+
|
|
24
|
+
std::string endpointUrl;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
class OPCUAServer {
|
|
28
|
+
public:
|
|
29
|
+
OPCUAServer();
|
|
30
|
+
~OPCUAServer();
|
|
31
|
+
|
|
32
|
+
void start();
|
|
33
|
+
void stop();
|
|
34
|
+
void mapVariable(std::string varname, std::string addr);
|
|
35
|
+
|
|
36
|
+
private:
|
|
37
|
+
void run();
|
|
38
|
+
|
|
39
|
+
};
|