@microtronics/studio-cli 0.4.1 → 0.5.1

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.
@@ -0,0 +1,883 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.AutoDDEGenerator = void 0;
27
+ exports.generateAutoIncFromMap = generateAutoIncFromMap;
28
+ exports.generateAutoUplinkIncFromMap = generateAutoUplinkIncFromMap;
29
+ exports.generateMainDDEIncFromMap = generateMainDDEIncFromMap;
30
+ const semver = __importStar(require("semver"));
31
+ const coreDefinitions_1 = require("../coreDefinitions");
32
+ const DeviceProfiles_1 = require("../../DeviceProfiles");
33
+ const helper_1 = require("../../helper");
34
+ var ContainerType = coreDefinitions_1.DDE_Core.ContainerType;
35
+ var TransferDirection = coreDefinitions_1.DDE_Core.TransferDirection;
36
+ var regexRelation = coreDefinitions_1.DDE_Core.regexRelation;
37
+ var CONFIG_CONTAINER = coreDefinitions_1.DDE_Core.CONFIG_CONTAINER;
38
+ var CONTAINER_DEF_DLO_CID_BASE = coreDefinitions_1.DDE_Core.CONTAINER_DEF_DLO_CID_BASE;
39
+ var CONTAINER_DEFS = coreDefinitions_1.DDE_Core.CONTAINER_DEFS;
40
+ var fieldTypeDefinitions = coreDefinitions_1.DDE_Core.fieldTypeDefinitions;
41
+ /** get effective field type for pawn access (may be overriden or skipped using attribute dlorw=...)
42
+ * @return {*} | 'skip' | null - null=error occured
43
+ */
44
+ function getPawnTypeDefinition(field) {
45
+ const tdef = fieldTypeDefinitions[field.type]; // just a shorthand
46
+ // supplement default values
47
+ if (!tdef.pwn.rwp) {
48
+ tdef.pwn.rwp = '%n';
49
+ }
50
+ if (!tdef.pwn.htype) {
51
+ tdef.pwn.htype = tdef.pwn.rwfunc;
52
+ }
53
+ // regular pawn access
54
+ return tdef.pwn;
55
+ }
56
+ // eslint-disable-next-line sonarjs/cognitive-complexity
57
+ function generateAutoIncFromMap(ddeMap, globalDefines, manifest) {
58
+ const _pwn = []; // sample code output for pawn
59
+ const pwn = _pwn.push.bind(_pwn);
60
+ function pwn_section(s) {
61
+ pwn(`\n// === ${s} ===\n`);
62
+ }
63
+ /**
64
+ * generate PROJECT META definitions
65
+ */
66
+ pwn_section('PROJECT META');
67
+ const isNumeric = (v) => {
68
+ return !Array.isArray(v) && v - parseFloat(v) + 1 >= 0;
69
+ };
70
+ function addDefinition(name, value, noString = false) {
71
+ let quotes = isNumeric(value) ? '' : '"';
72
+ if (noString) {
73
+ quotes = '';
74
+ }
75
+ pwn(`#define ${name} ${quotes}${value}${quotes}`);
76
+ }
77
+ const { dpid, registry } = manifest;
78
+ const { auto_inc } = DeviceProfiles_1.DeviceProfiles[dpid];
79
+ addDefinition(`APM_DPID`, `${dpid}`);
80
+ addDefinition(`APM_DPID_${dpid}`, `1`);
81
+ addDefinition(`APM_DPID_${dpid.toUpperCase()}`, `1`);
82
+ addDefinition(`APM_ID`, registry?.id || ''); //
83
+ addDefinition(`APM_VERSION`, `${semver.coerce(manifest.version)?.major}`); // 1,
84
+ addDefinition(`APM_NAME`, `${manifest.name}`); // "project X",
85
+ addDefinition(`APM_AUTHOR`, `${manifest.publisher}`);
86
+ for (const [name, value] of Object.entries(auto_inc)) {
87
+ // quote all non-numeric values
88
+ if (!isNumeric(value)) {
89
+ addDefinition(name, `"${value}"`);
90
+ }
91
+ else {
92
+ addDefinition(name, `${value}`);
93
+ }
94
+ }
95
+ /**
96
+ * generate global dlo defines if there are any
97
+ */
98
+ pwn_section('GLOBAL DEFINES - parsed from /dlo/main.ini');
99
+ for (const [define, value] of Object.entries(globalDefines)) {
100
+ const valueIsDefine = Object.hasOwn(globalDefines, value);
101
+ addDefinition(define, `${value}`, valueIsDefine);
102
+ }
103
+ /**
104
+ * generate DDE-CORE definitions
105
+ */
106
+ let sz_max = 0; // maximum byte size over all configX and histdataX
107
+ const cx_szs = Array(10).fill(0); // configX byte size
108
+ let cx_isupm = 0; // configX upward - bitmask
109
+ let cx_isvolatilem = 0; // configX dlo-volatile - bitmask
110
+ let cx_isdnm = 0; // configX downward - bitmask
111
+ let cx_isvlm = 0; // configX variable length - bitmask
112
+ const cx_isrdef = 0; // configX variable length - bitmask
113
+ const hx_szs = Array(10).fill(0); // histdataX byte size
114
+ let hx_isvlm = 0; // histdataX variable length - bitmask
115
+ let aloha_varlen = undefined;
116
+ for (const [containerName, containerDefinition] of Object.entries(ddeMap.containers)) {
117
+ if (containerDefinition.containerType === ContainerType.cx &&
118
+ containerDefinition.transferDirection !== TransferDirection.backendOnly) {
119
+ const cx = parseInt(containerName.substring(6));
120
+ const cmsk = 1 << cx;
121
+ cx_szs[cx] = containerDefinition.size;
122
+ cx_isupm |= [
123
+ TransferDirection.both,
124
+ TransferDirection.none,
125
+ TransferDirection.deviceOnly,
126
+ TransferDirection.up,
127
+ TransferDirection.upPlus
128
+ ].includes(containerDefinition.transferDirection)
129
+ ? cmsk
130
+ : 0;
131
+ cx_isvolatilem |= containerDefinition.volatile ? cmsk : 0;
132
+ cx_isdnm |= [
133
+ TransferDirection.both,
134
+ TransferDirection.none,
135
+ TransferDirection.deviceOnly,
136
+ TransferDirection.down,
137
+ TransferDirection.downPlus
138
+ ].includes(containerDefinition.transferDirection)
139
+ ? cmsk
140
+ : 0;
141
+ cx_isvlm |= [TransferDirection.bothPlus, TransferDirection.upPlus, TransferDirection.downPlus].includes(containerDefinition.transferDirection)
142
+ ? cmsk
143
+ : 0;
144
+ // cx_isrdef |= cont.rdef ? 1 << cx : 0; //validation for down/down+ is don in the dde
145
+ sz_max = Math.max(sz_max, containerDefinition.size);
146
+ }
147
+ else if (containerDefinition.containerType === ContainerType.hx) {
148
+ const hx = parseInt(containerName.substring(8));
149
+ hx_szs[hx] = containerDefinition.size;
150
+ hx_isvlm |= [TransferDirection.upPlus].includes(containerDefinition.transferDirection) ? 1 << hx : 0;
151
+ sz_max = Math.max(sz_max, containerDefinition.size);
152
+ }
153
+ else if (containerDefinition.containerType === ContainerType.aloha) {
154
+ aloha_varlen = [TransferDirection.upPlus].includes(containerDefinition.transferDirection);
155
+ sz_max = Math.max(sz_max, containerDefinition.size);
156
+ }
157
+ }
158
+ pwn_section('DDE CORE');
159
+ pwn(`#define _DDE_BUF_BYTES (${sz_max}+10)`); // todo rem +10 ??? round to next multiple of 4 ???
160
+ pwn('');
161
+ pwn('// c0\tc1\tc2\tc3\tc4\tc5\tc6\tc7\tc8\tc9');
162
+ pwn(`stock _DDE_CONFIGS_size[] =[ ${cx_szs.join(',\t')}];`);
163
+ pwn(`#define _DDE_CONFIGS_upm 0b${cx_isupm.toString(2)} // ..is tolerant when reading back container with under-length`);
164
+ pwn(`#define _DDE_CONFIGS_volatilem 0b${cx_isvolatilem.toString(2)} // inits container as volatile`);
165
+ pwn(`#define _DDE_CONFIGS_downm 0b${cx_isdnm.toString(2)} // reading the container expects strict length`);
166
+ pwn(`#define _DDE_CONFIGS_varlenm 0b${cx_isvlm.toString(2)} // allow partial write (dde_wxxx)`);
167
+ pwn(`#define _DDE_CONFIGS_rdef 0b${cx_isrdef.toString(2)} // ..apply defaults reading a container with under-length`);
168
+ pwn('');
169
+ pwn('// h0\th1\th2\th3\th4\th5\th6\th7\th8\th9');
170
+ pwn(`stock _DDE_HISTS_size[] =[ ${hx_szs.join(',\t')}];`);
171
+ pwn(`#define _DDE_HISTS_varlenm 0b${hx_isvlm.toString(2)} // allow partial write (dde_wxxx)`);
172
+ //see #RS-279 for more information about the _DDE_HISTS_maxsize
173
+ const szs = [...hx_szs];
174
+ if (Object.hasOwn(ddeMap, 'applog')) {
175
+ szs.push(125);
176
+ }
177
+ if (Object.hasOwn(ddeMap, 'alerts')) {
178
+ szs.push(13);
179
+ }
180
+ pwn(`#define _DDE_HISTS_maxsize ${Math.max(...szs)}`);
181
+ pwn('');
182
+ if (aloha_varlen !== undefined) {
183
+ pwn(`#define _DDE_ALOHA_varlen ${aloha_varlen ? 1 : 0}`);
184
+ pwn('');
185
+ }
186
+ // generate
187
+ // #define DDE_xxx_id
188
+ // #define DDE_xxx_sz
189
+ // #define DDE_xxx_idx
190
+ for (const [containerName, containerDefinition] of Object.entries(ddeMap.containers)) {
191
+ //special handling for applog container is handled afterwards
192
+ if (containerDefinition.containerType === 'applog') {
193
+ continue;
194
+ }
195
+ pwn_section(`${containerDefinition.title.toUpperCase()} - ${containerDefinition.transferDirection} via #${containerName}`);
196
+ const cid_base = CONTAINER_DEF_DLO_CID_BASE(containerDefinition.containerType, containerDefinition.transferDirection);
197
+ if (!cid_base) {
198
+ pwn(`// ... container not available in DLO`);
199
+ continue;
200
+ }
201
+ const preAlias = `DDE_${containerDefinition.containerType === ContainerType.aloha ? ContainerType.aloha : containerDefinition.title}`;
202
+ const CDEF = CONTAINER_DEFS[containerName];
203
+ pwn(`// ${preAlias}_id - container identifier required for ${preAlias}_read/_write operations`);
204
+ pwn(`#define ${preAlias}_id (${cid_base}+${CDEF.cnum || 0})`);
205
+ pwn(`// ${preAlias}_sz - [byte] container total size`);
206
+ pwn(`#define ${preAlias}_sz ${containerDefinition.size}`);
207
+ if (CDEF.cnum !== undefined) {
208
+ pwn(`// ${preAlias}_idx - 0+ container index number`);
209
+ pwn(`#define ${preAlias}_idx ${CDEF.cnum}`);
210
+ }
211
+ }
212
+ // setup results
213
+ return _pwn.join('\n');
214
+ }
215
+ class AutoDDEGenerator {
216
+ ddeMap;
217
+ context;
218
+ globalVariables = [];
219
+ pawnGlobalSource = [];
220
+ pawnHelperSource = [];
221
+ timeSeriesSource = [];
222
+ readWriteSource = [];
223
+ definesSource = [];
224
+ defaultDefinesSource = [];
225
+ knownDefines = [];
226
+ pawnIndent = 0;
227
+ sourceType;
228
+ constructor(ddeMap, context) {
229
+ this.ddeMap = ddeMap;
230
+ this.context = context;
231
+ this.sourceType = 'pawnSource';
232
+ }
233
+ pawn(a, b) {
234
+ if (b && a === '<') {
235
+ this.pawnIndent--;
236
+ }
237
+ const sourceToPush = {
238
+ pawnSource: this.pawnGlobalSource,
239
+ globalVariables: this.globalVariables,
240
+ timeseries: this.timeSeriesSource,
241
+ readWrite: this.readWriteSource,
242
+ defines: this.definesSource,
243
+ defaultDefines: this.defaultDefinesSource
244
+ }[this.sourceType];
245
+ sourceToPush.push('\t'.repeat(this.pawnIndent) + (b || a));
246
+ if (b && a === '>') {
247
+ this.pawnIndent++;
248
+ }
249
+ }
250
+ generate() {
251
+ for (const [containerName, containerDefinition] of Object.entries(this.ddeMap.containers)) {
252
+ // check if the given library uses this container
253
+ if (this.context && !containerDefinition.libraries.includes(this.context)) {
254
+ continue;
255
+ }
256
+ const containerIdBase = CONTAINER_DEF_DLO_CID_BASE(containerDefinition.containerType, containerDefinition.transferDirection);
257
+ //container is not available in dlo or has any fields
258
+ if (!containerIdBase || !containerDefinition.fields) {
259
+ continue;
260
+ }
261
+ // only generate the apps rw functions if the app has defined fields
262
+ if (!this.context && !coreDefinitions_1.DDE_Core.hasContainerAppFields(containerDefinition)) {
263
+ continue;
264
+ }
265
+ const CONTDEF = CONTAINER_DEFS[containerName];
266
+ if (CONTDEF.ctype !== ContainerType.cx && this.context) {
267
+ continue;
268
+ }
269
+ this.generateGlobalVarsForContainer(containerDefinition);
270
+ this.generateReadWriteFunctions(containerDefinition);
271
+ }
272
+ this.mergeSourceTypes();
273
+ return { globals: this.pawnGlobalSource, helper: this.pawnHelperSource };
274
+ }
275
+ createGlobalVar(variableName, field) {
276
+ this.sourceType = 'globalVariables';
277
+ const varName = field ? this.variableNameForPawnDefinition(variableName, field) : variableName;
278
+ if (field) {
279
+ const comment = this.generateCommentForField(field);
280
+ if (comment) {
281
+ if (Array.isArray(comment)) {
282
+ this.pawn('/**');
283
+ comment.forEach(line => {
284
+ this.pawn(` * ${line}`);
285
+ });
286
+ this.pawn(' */');
287
+ }
288
+ else {
289
+ this.pawn(`// ${comment}`);
290
+ }
291
+ }
292
+ }
293
+ this.pawn(`stock ${varName};`);
294
+ }
295
+ insertSection(title) {
296
+ this.pawn('');
297
+ this.pawn('// =============================================================================');
298
+ this.pawn(`// ${title}`);
299
+ this.pawn('// =============================================================================');
300
+ this.pawn('');
301
+ }
302
+ mergeSourceTypes() {
303
+ this.sourceType = 'pawnSource';
304
+ if (this.definesSource.length) {
305
+ this.insertSection('Defines');
306
+ this.pawnGlobalSource.push(...this.definesSource);
307
+ }
308
+ if (this.defaultDefinesSource.length) {
309
+ this.insertSection('Field defaults');
310
+ this.pawnGlobalSource.push(...this.defaultDefinesSource);
311
+ }
312
+ if (this.globalVariables.length) {
313
+ this.insertSection('Global Variables');
314
+ this.pawnGlobalSource.push(...this.globalVariables);
315
+ }
316
+ if (this.readWriteSource.length) {
317
+ this.insertSection('Internal read/write calls');
318
+ this.pawnHelperSource.push(...this.readWriteSource);
319
+ }
320
+ this.pawn('');
321
+ }
322
+ generateGlobalVarsForContainer(containerDefinition) {
323
+ // this.globalVariables.push('// === Global variables ===');
324
+ this.sourceType = 'globalVariables';
325
+ this.pawn('');
326
+ this.pawn(`// Container '${containerDefinition.title.replace('_', ' ')}'`);
327
+ this.pawn('');
328
+ const pre = `DDE_${containerDefinition.title}`;
329
+ // defines for arrays
330
+ for (const arrayInfo of Object.values(containerDefinition.arrays)) {
331
+ if (this.context !== arrayInfo.library) {
332
+ continue;
333
+ }
334
+ const arrayDimension = `${pre}_${arrayInfo.name}_dim`;
335
+ this.sourceType = 'defines';
336
+ this.pawn(`#define ${arrayDimension} ${arrayInfo.length}`);
337
+ if (arrayInfo.fields) {
338
+ const fakeDDEContainer = {
339
+ ...containerDefinition
340
+ };
341
+ fakeDDEContainer.fields = [];
342
+ arrayInfo.fields.forEach(field => {
343
+ fakeDDEContainer.fields.push({
344
+ arrayRef: null,
345
+ shadowRef: null,
346
+ byteOffset: 0,
347
+ byteSize: field.byteSize,
348
+ id: field.name,
349
+ library: arrayInfo.library,
350
+ name: field.name,
351
+ type: field.type,
352
+ title: null,
353
+ index: 0
354
+ });
355
+ });
356
+ const arrayStructure = `${pre}_${arrayInfo.name}_def`;
357
+ this.generateTypeDefinitions(fakeDDEContainer, arrayStructure);
358
+ this.createGlobalVar(`${pre}_${arrayInfo.name}[${arrayDimension}][${arrayStructure}]`);
359
+ }
360
+ else {
361
+ this.createGlobalVar(`${pre}_${arrayInfo.name}[${arrayDimension}]`);
362
+ }
363
+ }
364
+ for (const field of containerDefinition.fields) {
365
+ if (field.type === 'shadow' || field.shadowRef || field.library !== this.context) {
366
+ continue;
367
+ }
368
+ // generate defines for array fields
369
+ if (field.arrayRef !== null) {
370
+ const ref = containerDefinition.arrays[field.arrayRef.name];
371
+ let defineName = `${pre}_${field.arrayRef.name}`;
372
+ // this is a structured array, add the field name to the define
373
+ if (ref.fields?.length) {
374
+ defineName += `_${field.name.split('.')[1]}`;
375
+ }
376
+ this.createDefaultDefineForField(defineName, field);
377
+ continue;
378
+ }
379
+ const variableName = this.generateFieldVariableName(pre, field);
380
+ this.createDefaultDefineForField(variableName, field);
381
+ this.createGlobalVar(`${variableName}`, field);
382
+ }
383
+ }
384
+ generateCommentForField(field) {
385
+ const fieldComment = [`@type ${field.type}`];
386
+ if (field.description) {
387
+ fieldComment.unshift(field.description);
388
+ }
389
+ if (field.defaultValue !== undefined) {
390
+ const { value, reason } = this.parseFieldDefault(field);
391
+ fieldComment.push(`@default ${value} ${reason || ''}`);
392
+ }
393
+ return fieldComment;
394
+ }
395
+ generateFieldVariableName(pre, field) {
396
+ const fieldVariableName = `${pre}_${field.name}`;
397
+ const isBlob = Object.hasOwn(fieldTypeDefinitions, field.type) && fieldTypeDefinitions[field.type].isBlob;
398
+ const dim = field.byteSize;
399
+ if (dim && isBlob) {
400
+ const loopVar = 'i';
401
+ this.sourceType = 'defines';
402
+ this.pawn(`#define ${pre}_${field.name}_dim ${dim}`);
403
+ this.pawn(`#define ${pre}_${field.name}_iter() for(new ${loopVar}=0;${loopVar}<${dim};${loopVar}++)`);
404
+ }
405
+ this.sourceType = 'globalVariables';
406
+ return fieldVariableName;
407
+ }
408
+ // generate type declarations
409
+ // eslint-disable-next-line sonarjs/cognitive-complexity
410
+ generateTypeDefinitions(containerDefinition, base) {
411
+ this.sourceType = 'defines';
412
+ const xfields = containerDefinition.fields;
413
+ if (!xfields) {
414
+ return;
415
+ }
416
+ const knownArrays = [];
417
+ this.pawn('>', `#define ${base} [`);
418
+ for (const field of xfields) {
419
+ if (field.type === 'shadow' || field.shadowRef) {
420
+ continue;
421
+ }
422
+ // validate context of field
423
+ if (field.library !== this.context) {
424
+ continue;
425
+ }
426
+ // avoid creating multiple definitions if the field is part of an array
427
+ const arrayRef = field.arrayRef;
428
+ if (arrayRef) {
429
+ const arrayInfo = containerDefinition.arrays[arrayRef.name];
430
+ if (!knownArrays.includes(arrayRef.name) && !arrayInfo.fields) {
431
+ knownArrays.push(arrayRef.name);
432
+ }
433
+ else {
434
+ continue;
435
+ }
436
+ }
437
+ const fieldName = field.arrayRef ? field.arrayRef.name : field.name;
438
+ const fld_dim = field.arrayRef ? `[${base}_${fieldName}_dim]` : '';
439
+ // let comment = fld.xfields ? `${base}_${fld.name}` : fld.type; // original DDE field type as comment
440
+ let fld_def = '';
441
+ if (field.type === 'struct') {
442
+ fld_def = '// .' + fieldName + fld_dim; // comment out if it's a struct field
443
+ }
444
+ else {
445
+ const tdef_pwn = getPawnTypeDefinition(field);
446
+ if (!tdef_pwn) {
447
+ continue;
448
+ } // error - do nothing
449
+ if (tdef_pwn === 'skip') {
450
+ fld_def = `// skipped - .${fieldName}${fld_dim}`; // '.xyz[5]'
451
+ }
452
+ else {
453
+ fld_def += tdef_pwn.rwp.replace('%n', `.${fieldName}${fld_dim}`).replace('%l', field.byteSize);
454
+ }
455
+ }
456
+ fld_def += ',';
457
+ // add library comment if the field comes from an library
458
+ if (field.library) {
459
+ fld_def += `\t // declared by ${field.library} library`;
460
+ }
461
+ this.pawn(fld_def);
462
+ }
463
+ this.pawn('<', ']');
464
+ }
465
+ variableNameForPawnDefinition(variableName, field) {
466
+ // variable name based on the pawn definitions
467
+ const pawnTypeDefinition = getPawnTypeDefinition(field);
468
+ if (pawnTypeDefinition && pawnTypeDefinition !== 'skip') {
469
+ return pawnTypeDefinition.rwp.replace('%n', `${variableName}`).replace('%l', field.byteSize);
470
+ }
471
+ return variableName;
472
+ }
473
+ createDefaultDefineForField(variableName, field) {
474
+ this.sourceType = 'defaultDefines';
475
+ if (field.scale !== undefined) {
476
+ this.addDefine(this.variableNameForPawnDefinition(`${variableName}_scale`, field), field.scale);
477
+ }
478
+ if (field.offset !== undefined) {
479
+ this.addDefine(this.variableNameForPawnDefinition(`${variableName}_offset`, field), field.offset);
480
+ }
481
+ if (field.defaultValue !== undefined) {
482
+ const { value, reason } = this.parseFieldDefault(field);
483
+ const defineName = `${variableName}_default`;
484
+ field.defaultDloDefine = defineName;
485
+ this.addDefine(defineName, value, reason);
486
+ }
487
+ }
488
+ /**
489
+ * Add given variable as define to the dlo source
490
+ * @param name of define
491
+ * @param value of define
492
+ * @param reason comment for define
493
+ * @private
494
+ */
495
+ addDefine(name, value, reason) {
496
+ const containerRelation = regexRelation.exec(`${value}`);
497
+ if (containerRelation) {
498
+ return;
499
+ }
500
+ if (!this.knownDefines.includes(name)) {
501
+ if (reason) {
502
+ this.pawn(`// ${reason}`);
503
+ }
504
+ this.pawn(`#define ${name} ${value}`);
505
+ this.knownDefines.push(name);
506
+ }
507
+ }
508
+ generateReadWriteFunctions(containerDefinition) {
509
+ const containerName = containerDefinition.name;
510
+ const CONTDEF = CONTAINER_DEFS[containerName];
511
+ const pre = `DDE_${containerDefinition.containerType === ContainerType.aloha ? ContainerType.aloha : containerDefinition.title}`;
512
+ // ---
513
+ // add write method - but for UP_ward containers only
514
+ // ---
515
+ if ([
516
+ TransferDirection.both,
517
+ TransferDirection.bothPlus,
518
+ TransferDirection.none,
519
+ TransferDirection.deviceOnly,
520
+ TransferDirection.up,
521
+ TransferDirection.upPlus
522
+ ].includes(containerDefinition.transferDirection)) {
523
+ this.generateWriteMethod(pre, containerDefinition);
524
+ }
525
+ // ---
526
+ // add read method - but for CONFIG0-9 containers only
527
+ // ---
528
+ if (CONTDEF.ctype === ContainerType.cx) {
529
+ this.generateReadMethod(pre, containerDefinition);
530
+ }
531
+ }
532
+ generateWriteMethod(pre, containerDefinition) {
533
+ this.sourceType = 'readWrite';
534
+ const containerID = `DDE_${containerDefinition.title}_id`;
535
+ const isTimeseriesOrAloha = [ContainerType.hx, ContainerType.aloha].includes(containerDefinition.containerType);
536
+ const isTimeseriesContainer = containerDefinition.containerType === ContainerType.hx;
537
+ const isAlohaContainer = containerDefinition.containerType === ContainerType.aloha;
538
+ const funcWrite = `_${pre}_write`;
539
+ this.pawn('>', `stock ${funcWrite}(${isTimeseriesContainer ? 'const stamp=0' : ''}) {`);
540
+ // only aloha and time series write directly to the container
541
+ if (isTimeseriesOrAloha) {
542
+ this.pawn(`dde_wbegin(DDE_${isAlohaContainer ? ContainerType.aloha : containerDefinition.title}_id);`); // " dde_wbegin( DDE_status_id);"
543
+ }
544
+ this.generateRWFunctionBody(pre, containerDefinition, 'dde_w');
545
+ // only aloha and time series write directly to the container
546
+ if (isTimeseriesOrAloha) {
547
+ this.pawn(`return dde_wend(${isTimeseriesContainer ? 'stamp' : ''});`); // " dde_wend();"
548
+ }
549
+ this.pawn('<', '}');
550
+ this.pawn('');
551
+ // flush function
552
+ this.sourceType = 'globalVariables';
553
+ const funcFlush = `${pre}_transfer`;
554
+ const funcPersist = `${pre}_persist`;
555
+ const funcArgs = this.functionArgumentsForDdeWrite(isTimeseriesContainer, isTimeseriesOrAloha);
556
+ this.pawn('>', `${this.context ? 'stock ' : ''}${funcFlush}(${funcArgs}) {`);
557
+ if (isTimeseriesOrAloha) {
558
+ this.pawn(`${funcWrite}(${isAlohaContainer ? '' : 'stamp'});`);
559
+ }
560
+ else {
561
+ const containerNumber = containerDefinition.name.slice(-1);
562
+ this.pawn(`dde_flush(${containerNumber}, immediate);`);
563
+ }
564
+ this.pawn('<', '}');
565
+ this.pawn('');
566
+ if (containerDefinition.volatile) {
567
+ // generate persist function declaration
568
+ this.pawn('>', `stock ${funcPersist}() {`);
569
+ this.pawn(`return rM2M_CfgFlush(${containerID});`);
570
+ this.pawn('<', '}');
571
+ }
572
+ }
573
+ /**
574
+ * if it's a timeseries container the argument is `const stamp=0`
575
+ * if it's a configuration container the argument is `bool:immediate=false`
576
+ * @param isTimeseriesContainer
577
+ * @param isTimeseriesOrAloha
578
+ * @private
579
+ */
580
+ functionArgumentsForDdeWrite(isTimeseriesContainer, isTimeseriesOrAloha) {
581
+ return isTimeseriesContainer ? 'const stamp=0' : isTimeseriesOrAloha ? '' : 'bool:immediate=false';
582
+ }
583
+ generateReadMethod(pre, containerDefinition) {
584
+ this.sourceType = 'readWrite';
585
+ // const containerID = `${pre}_id`;
586
+ // todo implement as "hidden" function
587
+ const funcRead = `_${pre}_read`;
588
+ this.pawn('>', `stock ${funcRead}() {`);
589
+ this.generateRWFunctionBody(pre, containerDefinition, 'dde_r');
590
+ this.pawn('<', '}');
591
+ this.pawn('');
592
+ }
593
+ generateRWFunctionBody(pre, containerDefinition, ddeFunc) {
594
+ const xfields = containerDefinition.fields;
595
+ for (const fld of xfields) {
596
+ // validate context of field
597
+ if (fld.type === 'shadow' || fld.shadowRef || fld.library !== this.context) {
598
+ continue;
599
+ }
600
+ // assert(!fld.xfields);
601
+ const tdef_pwn = getPawnTypeDefinition(fld); // pawn access methods to use
602
+ if (!tdef_pwn || tdef_pwn === 'skip') {
603
+ continue;
604
+ }
605
+ // set the byte offset for the next field
606
+ this.pawn(`_dde_idx = ${fld.byteOffset};`);
607
+ let s = ''; // resulting pawn line e.g. " dde_wu32( o.live_trg);"
608
+ s += ddeFunc;
609
+ s += tdef_pwn.rwfunc;
610
+ const fieldName = `${pre}_${fld.name}`;
611
+ s += `(${fieldName}`;
612
+ if (tdef_pwn.rwlen) {
613
+ s += `, ${fld.byteSize}`;
614
+ } // add byte/cellcount on strings & buffers
615
+ // add the default field value to the read function only
616
+ if (fld.defaultDloDefine !== undefined && ddeFunc === 'dde_r') {
617
+ s += `, ${fld.defaultDloDefine}`;
618
+ }
619
+ this.pawn(s + `);`);
620
+ }
621
+ }
622
+ parseFieldDefault(field) {
623
+ const typeDefinitions = getPawnTypeDefinition(field);
624
+ let defaultValue = field.defaultValue;
625
+ function buildReturnObject(value, reason) {
626
+ return { value, reason };
627
+ }
628
+ //modify the default value based on the string type. Either " or '';
629
+ switch (field.type) {
630
+ case 'astring':
631
+ case 'nstring':
632
+ case 'cstring': {
633
+ return buildReturnObject(`"${defaultValue}"`);
634
+ }
635
+ case 'wstring': {
636
+ return buildReturnObject(`''${defaultValue}''`);
637
+ }
638
+ case 'ustring': {
639
+ return buildReturnObject(`/* default not supported: ${defaultValue} */`);
640
+ }
641
+ case 'binary': {
642
+ // convert hex value to byte array equivalent...
643
+ const splitted = defaultValue.substring(2).match(/.{1,2}/g) || [];
644
+ const byteArray = `{ 0x${splitted.join(', 0x')} }`;
645
+ return buildReturnObject(byteArray);
646
+ }
647
+ }
648
+ if (defaultValue === 'NaN') {
649
+ const dataType = typeDefinitions.rwfunc;
650
+ return buildReturnObject(`${dataType}_NaN`.toUpperCase());
651
+ }
652
+ const scaledDefault = this.parseFieldScaleOffset(field);
653
+ if (scaledDefault) {
654
+ return buildReturnObject(scaledDefault.calculated, scaledDefault.reason);
655
+ }
656
+ // add missing fractionDigits to float types
657
+ if (defaultValue !== undefined &&
658
+ !regexRelation.exec(`${defaultValue}`) &&
659
+ field.type.startsWith('float') &&
660
+ defaultValue % 1 === 0) {
661
+ defaultValue = defaultValue.toFixed(field.decimalPlaces || 1);
662
+ }
663
+ return buildReturnObject(`${defaultValue}`);
664
+ }
665
+ /**
666
+ * Try to calculate the default value based on scale and offset
667
+ * @param field
668
+ * @private
669
+ */
670
+ parseFieldScaleOffset(field) {
671
+ const defaultValue = field.defaultValue;
672
+ // validate if any of the given fields has a relation to another container
673
+ const isAnyRelation = !!regexRelation.exec(`${field.offset}`) ||
674
+ !!regexRelation.exec(`${field.scale}`) ||
675
+ !!regexRelation.exec(`${field.defaultValue}`);
676
+ // scale || offset is set
677
+ if (!isAnyRelation && (field.offset !== undefined || field.scale !== undefined)) {
678
+ const offset = field.offset !== undefined ? Number(field.offset) : 0;
679
+ const scale = field.scale !== undefined ? Number(field.scale) : 1;
680
+ // calculate the original value without scale and offset
681
+ let calculated = (Number(defaultValue) - offset) / scale;
682
+ let reason = `(defaultValue - offset) / scale -> (${defaultValue} - ${offset}) / ${scale}`;
683
+ // field type is no float - round to integer
684
+ if (!field.type.startsWith('float')) {
685
+ calculated = Math.round(calculated);
686
+ reason = `Rounded value of: ${reason}`;
687
+ }
688
+ else if (calculated % 1 === 0) {
689
+ calculated = calculated.toFixed(1);
690
+ }
691
+ return { calculated, reason };
692
+ }
693
+ return null;
694
+ }
695
+ }
696
+ exports.AutoDDEGenerator = AutoDDEGenerator;
697
+ // eslint-disable-next-line sonarjs/cognitive-complexity
698
+ function generateAutoUplinkIncFromMap(ddeMap,
699
+ /**
700
+ * The names of the included libraries
701
+ */
702
+ includedLibNames) {
703
+ const _pwn = [];
704
+ const pwn = _pwn.push.bind(_pwn);
705
+ // collect containers to apply/restore23
706
+ const containerApply = [];
707
+ const containerRestore = [];
708
+ function buildUplinkApplyCall(applyName) {
709
+ const funcName = `onUplinkApply_${applyName}()`;
710
+ return `${funcName};`;
711
+ }
712
+ function buildLibraryRestoreApplyCall(cont, restoreApply) {
713
+ cont.libraries.forEach(libraryName => {
714
+ const hashedLib = helper_1.Helper.generateHashForLibraryName(libraryName);
715
+ pwn(`\t#ifdef _${hashedLib}${restoreApply}_${cont.title}`);
716
+ pwn(`\t\t_${hashedLib}${restoreApply}_${cont.title}();\t// ${libraryName}`);
717
+ pwn('\t#endif');
718
+ });
719
+ }
720
+ //generate onUplinkEvent dispatcher
721
+ pwn(`stock _onUplinkEvent(ev, param) {`);
722
+ // insert library calls...
723
+ includedLibNames.forEach(libraryName => {
724
+ const hashedName = helper_1.Helper.generateHashForLibraryName(libraryName);
725
+ const funcName = `_${hashedName}UplinkEvent`;
726
+ pwn(`\t#ifdef ${funcName}`);
727
+ pwn(`\t\t${funcName}(ev, param);`);
728
+ pwn(`\t#endif`);
729
+ });
730
+ pwn(`\tonUplinkEvent(ev, param);`);
731
+ pwn(`}`);
732
+ for (const [containerName, containerDefinition] of Object.entries(ddeMap.containers)) {
733
+ const CONTDEF = CONTAINER_DEFS[containerName];
734
+ if (CONTDEF.ctype !== ContainerType.cx) {
735
+ continue;
736
+ }
737
+ if ([TransferDirection.up, TransferDirection.upPlus, TransferDirection.deviceOnly].includes(containerDefinition.transferDirection)) {
738
+ containerRestore.push(containerDefinition);
739
+ }
740
+ if ([TransferDirection.bothPlus, TransferDirection.both, TransferDirection.downPlus, TransferDirection.down].includes(containerDefinition.transferDirection)) {
741
+ containerApply.push(containerDefinition);
742
+ }
743
+ }
744
+ if (containerRestore.length) {
745
+ pwn('');
746
+ }
747
+ // generate restore code
748
+ for (const cont of containerRestore) {
749
+ cont.knownNames.forEach((libAlias) => {
750
+ pwn(`forward onUplinkRestore_${libAlias}();`);
751
+ });
752
+ pwn('');
753
+ pwn(`stock restoreUplink${cont.name}() {`);
754
+ pwn(`\t_DDE_${cont.name}_read();`);
755
+ buildLibraryRestoreApplyCall(cont, 'Restore');
756
+ if (coreDefinitions_1.DDE_Core.hasContainerAppFields(cont)) {
757
+ pwn(`\tonUplinkRestore_${cont.title}();`);
758
+ }
759
+ pwn(`}`);
760
+ }
761
+ pwn(`#pragma warning push`);
762
+ pwn(`stock _onUplinkRestore(cfgId) {`);
763
+ if (containerRestore.length) {
764
+ pwn(`\tswitch(cfgId) {`);
765
+ for (const cont of containerRestore) {
766
+ pwn(`\t\tcase DDE_${cont.title}_id: restoreUplink${cont.name}(); // ${cont.name}`);
767
+ }
768
+ pwn(`\t}`);
769
+ }
770
+ else {
771
+ pwn(`\t#pragma warning disable 203`);
772
+ pwn(`\t// no containers to restore`);
773
+ }
774
+ pwn(`}`);
775
+ pwn(`#pragma warning pop`);
776
+ if (containerApply.length) {
777
+ pwn('');
778
+ }
779
+ // generate apply code
780
+ for (const cont of containerApply) {
781
+ cont.knownNames.forEach((libAlias) => {
782
+ pwn(`forward onUplinkApply_${libAlias}();`);
783
+ });
784
+ pwn('');
785
+ pwn(`stock applyUplink${cont.name}() {`);
786
+ pwn(`\t_DDE_${cont.name}_read();`);
787
+ buildLibraryRestoreApplyCall(cont, 'Apply');
788
+ if (coreDefinitions_1.DDE_Core.hasContainerAppFields(cont)) {
789
+ pwn(`\t${buildUplinkApplyCall(cont.title)}`);
790
+ }
791
+ pwn(`\treturn(OK);`);
792
+ pwn(`}`);
793
+ }
794
+ pwn(`#pragma warning push`);
795
+ pwn(`stock _onUplinkApply(cfgId) {`);
796
+ if (containerApply.length) {
797
+ pwn(`\tswitch(cfgId) {`);
798
+ for (const cont of containerApply) {
799
+ pwn(`\t\tcase DDE_${cont.title}_id: return applyUplink${cont.name}(); // ${cont.name}`);
800
+ }
801
+ pwn(`\t}`);
802
+ pwn(`\treturn ERROR;`);
803
+ }
804
+ else {
805
+ pwn(`\t#pragma warning disable 203`);
806
+ pwn(`\t// no containers to apply`);
807
+ pwn(`\treturn OK;`);
808
+ }
809
+ pwn(`}`);
810
+ pwn(`#pragma warning pop`);
811
+ return _pwn.join('\n');
812
+ }
813
+ const ALL_CONFIG_WRITE_NAMES = CONFIG_CONTAINER.map(containerName => `_DDE_${containerName}_write`);
814
+ function generateMainDDEIncFromMap(ddeMap) {
815
+ const _pawnSource = [];
816
+ const pawnSource = _pawnSource.push.bind(_pawnSource);
817
+ const dummyWriteFunctions = [...ALL_CONFIG_WRITE_NAMES];
818
+ for (const [containerName, containerDefinition] of Object.entries(ddeMap.containers)) {
819
+ const cid_base = CONTAINER_DEF_DLO_CID_BASE(containerDefinition.containerType, containerDefinition.transferDirection);
820
+ const CONTDEF = CONTAINER_DEFS[containerName];
821
+ if (!cid_base || !containerDefinition.fields || CONTDEF.ctype !== ContainerType.cx) {
822
+ //container is not available in dlo
823
+ continue;
824
+ }
825
+ const pre = `DDE_${containerDefinition.name}`;
826
+ const containerID = `DDE_${containerDefinition.title}_id`;
827
+ // ---
828
+ // add write method - but for configuration UP_ward containers only
829
+ // ---
830
+ if ([
831
+ TransferDirection.both,
832
+ TransferDirection.bothPlus,
833
+ TransferDirection.none,
834
+ TransferDirection.deviceOnly,
835
+ TransferDirection.up,
836
+ TransferDirection.upPlus
837
+ ].includes(containerDefinition.transferDirection)) {
838
+ const funcWrite = `_${pre}_write`;
839
+ // pawnSource(`#define ${funcWrite}_def 01`);
840
+ pawnSource(`stock ${funcWrite}() {`);
841
+ pawnSource(`\tdde_wbegin(${containerID});`);
842
+ generateMainDDEFunctionBody(pawnSource, containerDefinition, 'write');
843
+ pawnSource(`\treturn dde_wend();`);
844
+ pawnSource(`}`);
845
+ // remove from dummy array
846
+ dummyWriteFunctions.splice(dummyWriteFunctions.indexOf(funcWrite), 1);
847
+ }
848
+ // ---
849
+ // add read method - but for CONFIG0-9 containers only
850
+ // ---
851
+ if (CONTDEF.ctype === ContainerType.cx) {
852
+ const funcRead = `_${pre}_read`;
853
+ pawnSource(`stock ${funcRead}() {`);
854
+ pawnSource(`\tif (dde_rbegin(${containerID})) return ERROR;`);
855
+ generateMainDDEFunctionBody(pawnSource, containerDefinition, 'read');
856
+ pawnSource(`\tdde_rend();`);
857
+ pawnSource('\treturn OK;');
858
+ pawnSource(`}`);
859
+ }
860
+ }
861
+ if (dummyWriteFunctions.length) {
862
+ pawnSource('');
863
+ pawnSource(`// Dummy functions needed by the dde library`);
864
+ for (const dummyFunc of dummyWriteFunctions) {
865
+ pawnSource(`stock ${dummyFunc}() { return OK; }`);
866
+ }
867
+ }
868
+ return _pawnSource.join('\n');
869
+ }
870
+ function generateMainDDEFunctionBody(pawnSource, containerDefinition, readWrite) {
871
+ containerDefinition.libraries.forEach(libraryName => {
872
+ const libraryHash = helper_1.Helper.generateHashForLibraryName(libraryName);
873
+ pawnSource(`\t#ifdef __${libraryHash}${containerDefinition.title}_${readWrite}`);
874
+ pawnSource(`\t\t__${libraryHash}${containerDefinition.title}_${readWrite}();`);
875
+ pawnSource(`\t#endif`);
876
+ });
877
+ if (coreDefinitions_1.DDE_Core.hasContainerAppFields(containerDefinition)) {
878
+ pawnSource(`\t#ifdef _DDE_${containerDefinition.title}_${readWrite}`);
879
+ pawnSource(`\t\t_DDE_${containerDefinition.title}_${readWrite}();`);
880
+ pawnSource(`\t#endif`);
881
+ }
882
+ }
883
+ //# sourceMappingURL=dlo.js.map