@synapticon/motion-master-client 2.3.0-beta.0 → 6.0.0-alpha.100

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.
Files changed (72) hide show
  1. package/LICENSE +21 -0
  2. package/dist/api-error.d.ts +25 -0
  3. package/dist/api-error.js +52 -0
  4. package/dist/client.d.ts +20 -0
  5. package/dist/client.js +37 -0
  6. package/dist/constants.d.ts +2 -0
  7. package/dist/constants.js +8 -0
  8. package/dist/eni.d.ts +197 -0
  9. package/dist/eni.js +61 -0
  10. package/dist/generated/Api.d.ts +1886 -0
  11. package/dist/generated/Api.js +1293 -0
  12. package/dist/generated/data-contracts.d.ts +2282 -0
  13. package/dist/generated/data-contracts.js +12 -0
  14. package/dist/generated/http-client.d.ts +60 -0
  15. package/dist/generated/http-client.js +171 -0
  16. package/dist/hex.d.ts +2 -0
  17. package/dist/hex.js +20 -0
  18. package/dist/index.d.ts +13 -7
  19. package/dist/index.js +20 -22
  20. package/dist/lan.d.ts +4 -0
  21. package/dist/lan.js +59 -0
  22. package/dist/mmpd.d.ts +53 -0
  23. package/dist/mmpd.js +322 -0
  24. package/dist/sdo.d.ts +17 -0
  25. package/dist/sdo.js +219 -0
  26. package/dist/web-socket-connection.d.ts +70 -0
  27. package/dist/web-socket-connection.js +237 -0
  28. package/dist/wire-time.d.ts +2 -0
  29. package/dist/wire-time.js +18 -0
  30. package/package.json +29 -35
  31. package/.vscode/launch.json +0 -23
  32. package/README.md +0 -118
  33. package/box.config.json +0 -7
  34. package/dist/index.d.ts.map +0 -1
  35. package/dist/index.js.map +0 -1
  36. package/dist/motion-master-client-web-socket-connection.d.ts +0 -43
  37. package/dist/motion-master-client-web-socket-connection.d.ts.map +0 -1
  38. package/dist/motion-master-client-web-socket-connection.js +0 -91
  39. package/dist/motion-master-client-web-socket-connection.js.map +0 -1
  40. package/dist/motion-master-client.d.ts +0 -105
  41. package/dist/motion-master-client.d.ts.map +0 -1
  42. package/dist/motion-master-client.js +0 -348
  43. package/dist/motion-master-client.js.map +0 -1
  44. package/dist/motion-master-notification-subscribe-data.d.ts +0 -8
  45. package/dist/motion-master-notification-subscribe-data.d.ts.map +0 -1
  46. package/dist/motion-master-notification-subscribe-data.js +0 -3
  47. package/dist/motion-master-notification-subscribe-data.js.map +0 -1
  48. package/dist/motion-master-notification-web-socket-connection.d.ts +0 -56
  49. package/dist/motion-master-notification-web-socket-connection.d.ts.map +0 -1
  50. package/dist/motion-master-notification-web-socket-connection.js +0 -115
  51. package/dist/motion-master-notification-web-socket-connection.js.map +0 -1
  52. package/dist/motion-master-notification.d.ts +0 -31
  53. package/dist/motion-master-notification.d.ts.map +0 -1
  54. package/dist/motion-master-notification.js +0 -44
  55. package/dist/motion-master-notification.js.map +0 -1
  56. package/dist/util.d.ts +0 -16
  57. package/dist/util.d.ts.map +0 -1
  58. package/dist/util.js +0 -24
  59. package/dist/util.js.map +0 -1
  60. package/licenses.format.json +0 -4
  61. package/motion-master-client.config.json +0 -7
  62. package/smm_data_dic.json +0 -1213
  63. package/src/index.ts +0 -7
  64. package/src/motion-master-client-web-socket-connection.ts +0 -104
  65. package/src/motion-master-client.ts +0 -468
  66. package/src/motion-master-notification-subscribe-data.ts +0 -7
  67. package/src/motion-master-notification-web-socket-connection.ts +0 -143
  68. package/src/motion-master-notification.ts +0 -51
  69. package/src/util.ts +0 -22
  70. package/test.sh +0 -122
  71. package/tsconfig.json +0 -63
  72. package/tslint.json +0 -118
@@ -0,0 +1,2282 @@
1
+ type UtilRequiredKeys<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
2
+ /** A CiA402 drive's control snapshot — its state machine, control words, and mode. */
3
+ export interface Cia402Status {
4
+ /**
5
+ * Decoded CiA402 state-machine state (from the statusword, 0x6041).
6
+ * @example "OperationEnabled"
7
+ */
8
+ state: "NotReadyToSwitchOn" | "SwitchOnDisabled" | "ReadyToSwitchOn" | "SwitchedOn" | "OperationEnabled" | "QuickStopActive" | "FaultReactionActive" | "Fault";
9
+ /**
10
+ * Raw statusword (0x6041), 0–65535.
11
+ * @example 4663
12
+ */
13
+ statusword: number;
14
+ /**
15
+ * Last-commanded controlword (0x6040), 0–65535.
16
+ * @example 15
17
+ */
18
+ controlword: number;
19
+ /**
20
+ * Active operation mode (display object 0x6061), as an INTEGER8 value.
21
+ * @example 9
22
+ */
23
+ modeOfOperation: number;
24
+ /**
25
+ * Human-readable name of the active operation mode.
26
+ * @example "CyclicSyncVelocity"
27
+ */
28
+ modeName: string;
29
+ /**
30
+ * Target position (0x607A), INTEGER32, in the drive's own position units. The drive acts on it in the position modes (PP, CSP) only, but it is reported in every mode. Read from the process image while the device exchanges, else over SDO. `null` when the drive has no such object or the read failed.
31
+ * @example 100000
32
+ */
33
+ targetPosition: number | null;
34
+ /**
35
+ * Target velocity (0x60FF), INTEGER32, in the drive's own velocity units. The drive acts on it in the velocity modes (PV, CSV) only, but it is reported in every mode. Read from the process image while the device exchanges, else over SDO. `null` when the drive has no such object or the read failed.
36
+ * @example 250000
37
+ */
38
+ targetVelocity: number | null;
39
+ /**
40
+ * Target torque (0x6071), INTEGER16 widened to INTEGER32, in per mille of rated torque. The drive acts on it in the torque modes (PT, CST) only, but it is reported in every mode. Read from the process image while the device exchanges, else over SDO. `null` when the drive has no such object or the read failed.
41
+ * @example -100
42
+ */
43
+ targetTorque: number | null;
44
+ /**
45
+ * Position actual value (0x6064), INTEGER32, in the drive's own position units. Read from the process image while the device exchanges, else over SDO. `null` when the drive has no such object or the read failed.
46
+ * @example 99874
47
+ */
48
+ actualPosition: number | null;
49
+ /**
50
+ * Velocity actual value (0x606C), INTEGER32, in the drive's own velocity units. Read from the process image while the device exchanges, else over SDO. `null` when the drive has no such object or the read failed.
51
+ * @example 249000
52
+ */
53
+ actualVelocity: number | null;
54
+ /**
55
+ * Torque actual value (0x6077), INTEGER16 widened to INTEGER32, in per mille of rated torque. Read from the process image while the device exchanges, else over SDO. `null` when the drive has no such object or the read failed.
56
+ * @example -150
57
+ */
58
+ actualTorque: number | null;
59
+ /**
60
+ * The drive's own short description of its last fault, read from the vendor object that holds one. A SOMANET drive keeps it in 0x203F:01 and reports an empty string while there is no fault. `null` when the drive has no such object or the read failed.
61
+ * @example "CyclicHb"
62
+ */
63
+ errorDescription: string | null;
64
+ }
65
+ /** Every operation mode a device has, with what its "Supported drive modes" field (0x6502) says about each. */
66
+ export interface OperationModes {
67
+ /**
68
+ * Object 0x6502 verbatim, as an UNSIGNED32.
69
+ * @example 197549
70
+ */
71
+ supportedDriveModes: number;
72
+ /**
73
+ * The set bits of 0x6502 from bit 16 upwards, reported as bit numbers and nothing more. The profile leaves their meaning entirely to the vendor, so nothing here can decode them — a SOMANET drive sets bits 16 and 17 and publishes no definition for either.
74
+ * @example [16,17]
75
+ */
76
+ manufacturerBits: number[];
77
+ /** Every mode, ascending by value — manufacturer modes first, then standard. */
78
+ modes: OperationMode[];
79
+ }
80
+ /** One operation mode of one device. */
81
+ export interface OperationMode {
82
+ /**
83
+ * The value written to 0x6060 / read from 0x6061. Negative for a vendor mode.
84
+ * @example -2
85
+ */
86
+ value: number;
87
+ /**
88
+ * PascalCase identifier, matching the modeName of GET /api/devices/{n}/cia402.
89
+ * @example "Diagnostics"
90
+ */
91
+ name: string;
92
+ /**
93
+ * The profile's or the vendor's own wording, for a user-facing list.
94
+ * @example "Diagnostics mode"
95
+ */
96
+ label: string;
97
+ /**
98
+ * Whether CiA402 or the vendor defines this mode.
99
+ * @example "manufacturer"
100
+ */
101
+ kind: "standard" | "manufacturer";
102
+ /**
103
+ * The bit of 0x6502 that advertises this mode. Null for every manufacturer mode, and for NoMode, which is always legal and so has no bit.
104
+ * @example 7
105
+ */
106
+ bit: number | null;
107
+ /**
108
+ * The profile's short form (pp, vl, pv, tq, hm, ip, csp, csv, cst, cstca).
109
+ * @example "csp"
110
+ */
111
+ abbreviation: string | null;
112
+ /**
113
+ * Whether the drive advertises this mode. Null for every manufacturer mode — 0x6502 has no bit a master could read for one — which means "the drive does not say", not "no".
114
+ * @example true
115
+ */
116
+ supported: boolean | null;
117
+ /**
118
+ * Present and true only for a mode the vendor's firmware marks deprecated.
119
+ * @example true
120
+ */
121
+ deprecated?: boolean;
122
+ }
123
+ /** Point-in-time health of the real-time game loop. Times are nanoseconds; rates are hertz. All fields are diagnostic (relaxed reads), not synchronised. */
124
+ export interface GameLoopHealth {
125
+ /**
126
+ * Configured target cycle period, in microseconds
127
+ * @format int64
128
+ * @example 1000
129
+ */
130
+ periodUs: number;
131
+ /**
132
+ * Target cycle rate (1e6 / periodUs), in hertz
133
+ * @format double
134
+ * @example 1000
135
+ */
136
+ targetHz: number;
137
+ /**
138
+ * Cumulative average rate since the loop started (executedCycles / uptime), in hertz; 0 before the loop starts. Below targetHz means the host cannot sustain the configured period.
139
+ * @format double
140
+ * @example 999.56
141
+ */
142
+ achievedHz: number;
143
+ /**
144
+ * Loop iterations actually executed since start
145
+ * @format int64
146
+ * @example 2023
147
+ */
148
+ executedCycles: number;
149
+ /**
150
+ * Cycles skipped to catch up after overruns/stalls since start. A rising value means the loop is not meeting its period.
151
+ * @format int64
152
+ * @example 0
153
+ */
154
+ skippedCycles: number;
155
+ /**
156
+ * Task-execution time of the most recent cycle, in nanoseconds
157
+ * @format int64
158
+ * @example 104
159
+ */
160
+ lastExecNs: number;
161
+ /**
162
+ * Worst task-execution time since start, in nanoseconds
163
+ * @format int64
164
+ * @example 4009
165
+ */
166
+ maxExecNs: number;
167
+ /**
168
+ * Mean task-execution time since start, in nanoseconds
169
+ * @format int64
170
+ * @example 338
171
+ */
172
+ avgExecNs: number;
173
+ /**
174
+ * Whether SCHED_FIFO real-time priority was acquired (false on Windows, which never attempts it, and on Linux/macOS when the privilege is missing).
175
+ * @example false
176
+ */
177
+ schedFifo: boolean;
178
+ /**
179
+ * Whether mlockall succeeded to pin memory (Linux only; false elsewhere or when the privilege is missing).
180
+ * @example false
181
+ */
182
+ memLocked: boolean;
183
+ /**
184
+ * Core the real-time thread was configured to pin to (gameLoop.cpuAffinity), or -1 when unpinned. Pointing this at an isolcpus core is what gives the RT thread a core to itself; only that thread is pinned, so the HTTP, WebSocket and monitoring threads stay on the remaining cores.
185
+ * @example -1
186
+ */
187
+ cpuAffinity: number;
188
+ /**
189
+ * Whether the pin took. Always false when cpuAffinity is -1 (nothing was asked for); false while cpuAffinity is >= 0 means the request failed and the thread is running unpinned.
190
+ * @example false
191
+ */
192
+ cpuPinned: boolean;
193
+ /**
194
+ * Server wall-clock timestamp (epoch microseconds) when sampled
195
+ * @format int64
196
+ * @example 1783968687738680
197
+ */
198
+ timestampUs: number;
199
+ }
200
+ /** The user cache's location on disk plus every file it holds. */
201
+ export interface UserCacheListing {
202
+ /**
203
+ * Absolute path of the cache directory on the server's filesystem. Platform-dependent (and overridable via the `userCache.directory` config key), so it is reported rather than assumed — show it to the user so they can find the files themselves.
204
+ * @example "/home/user/.cache/motion-master"
205
+ */
206
+ root: string;
207
+ files: UserCacheFile[];
208
+ }
209
+ /** One file in the user cache. */
210
+ export interface UserCacheFile {
211
+ /**
212
+ * Path relative to the cache root, always with `/` separators. Use it verbatim in the download/upload/delete endpoints.
213
+ * @example "configs/machine-a.json"
214
+ */
215
+ path: string;
216
+ /**
217
+ * File size in bytes.
218
+ * @example 20480
219
+ */
220
+ size: number;
221
+ /**
222
+ * Last-write time, in milliseconds since the Unix epoch.
223
+ * @example 1783968687738
224
+ */
225
+ modifiedMs: number;
226
+ /**
227
+ * Whether `DELETE` will accept this path. False for a file the running server holds open — today only its own log file, `logs/motion-master.log`. Deleting such a file cannot do what it appears to (Windows refuses; Linux and macOS unlink it while the server keeps writing to it, reclaiming nothing), so the request is refused with `409 Conflict` and a client should not offer the action. Rotated copies are closed and remain deletable, which is how the space is reclaimed.
228
+ * @example true
229
+ */
230
+ deletable: boolean;
231
+ }
232
+ /** Summary of one on-disk parameter-cache file (its identity, size, and count). */
233
+ export interface ParameterCacheEntry {
234
+ /**
235
+ * Opaque key addressing this cache file in the download/delete endpoints ("<vendor>-<product>-<revision>"). Use it verbatim — do not construct it client-side.
236
+ * @example "000022d2-00000201-0000000a"
237
+ */
238
+ id: string;
239
+ /**
240
+ * EtherCAT vendor ID (0x22D2 = Synapticon).
241
+ * @example 8914
242
+ */
243
+ vendorId: number;
244
+ /**
245
+ * Product code.
246
+ * @example 513
247
+ */
248
+ productCode: number;
249
+ /**
250
+ * Revision number.
251
+ * @example 10
252
+ */
253
+ revisionNumber: number;
254
+ /**
255
+ * Number of cached parameter definitions in the file.
256
+ * @example 312
257
+ */
258
+ parameterCount: number;
259
+ /**
260
+ * File size on disk, in bytes.
261
+ * @example 48213
262
+ */
263
+ sizeBytes: number;
264
+ }
265
+ /** A device's process-data (sync-manager) watchdog configuration, decoded from the watchdog divider (0x0400) and process-data watchdog time (0x0420) ESC registers. */
266
+ export interface ProcessDataWatchdog {
267
+ /**
268
+ * 1-based position of the device on the fieldbus.
269
+ * @example 1
270
+ */
271
+ slavePosition: number;
272
+ /**
273
+ * False when the time register (ticks) is 0, i.e. the watchdog is disabled.
274
+ * @example true
275
+ */
276
+ enabled: boolean;
277
+ /**
278
+ * Live status register (0x0440 bit 0): true = the watchdog is counting, false = expired or disabled. Meaningful only when enabled; it counts down only while process data flows.
279
+ * @example true
280
+ */
281
+ running: boolean;
282
+ /**
283
+ * Configured timeout in nanoseconds: ticks × 40 ns × (divider + 2).
284
+ * @example 100000000
285
+ */
286
+ timeoutNs: number;
287
+ /**
288
+ * The same timeout in milliseconds (convenience for display/editing).
289
+ * @format double
290
+ * @example 100
291
+ */
292
+ timeoutMs: number;
293
+ /**
294
+ * Raw watchdog divider register (0x0400); shared with the PDI watchdog.
295
+ * @example 2498
296
+ */
297
+ divider: number;
298
+ /**
299
+ * Raw process-data watchdog time register (0x0420), in watchdog ticks.
300
+ * @example 1000
301
+ */
302
+ ticks: number;
303
+ }
304
+ /** A monitoring's configuration plus its per-parameter source classification. */
305
+ export interface Monitoring {
306
+ /** @example "left-leg" */
307
+ topic: string;
308
+ /**
309
+ * Present only when a label was supplied at creation.
310
+ * @example "Left Leg"
311
+ */
312
+ name?: string;
313
+ /**
314
+ * Flush cadence in milliseconds (5–2000).
315
+ * @example 20
316
+ */
317
+ interval: number;
318
+ /** The sampled objects, in the positional order of each WebSocket sample row. */
319
+ parameters: {
320
+ /** @example 1 */
321
+ devicePosition: number;
322
+ /** @example 24676 */
323
+ index: number;
324
+ /** @example 0 */
325
+ subindex: number;
326
+ /**
327
+ * How the value is sourced — `pdo` (decoded from the live process image) or `sdo` (polled in the background and read from cache).
328
+ * @example "pdo"
329
+ */
330
+ source: "pdo" | "sdo";
331
+ }[];
332
+ }
333
+ /** One mapping entry to write. Packs to the 32-bit CoE word index<<16 | subindex<<8 | bitLength. */
334
+ export interface PdoMappingRequestEntry {
335
+ /**
336
+ * CoE object index; 0 marks an alignment-padding gap (no bound object)
337
+ * @min 0
338
+ * @max 65535
339
+ * @example 24640
340
+ */
341
+ index: number;
342
+ /**
343
+ * CoE object subindex
344
+ * @min 0
345
+ * @max 255
346
+ * @example 0
347
+ */
348
+ subindex: number;
349
+ /**
350
+ * Width of the entry in bits
351
+ * @min 0
352
+ * @max 255
353
+ * @example 16
354
+ */
355
+ bitLength: number;
356
+ }
357
+ /** One PDO mapping object to write and its ordered entries. */
358
+ export interface PdoMappingRequestObject {
359
+ /**
360
+ * Mapping-object index (0x16xx RxPDO for outputs, 0x1Axx TxPDO for inputs)
361
+ * @min 0
362
+ * @max 65535
363
+ * @example 5632
364
+ */
365
+ pdoIndex: number;
366
+ entries: PdoMappingRequestEntry[];
367
+ }
368
+ /** A device's desired PDO configuration to write. `outputs` are RxPDO objects (master→slave, assigned to 0x1C12); `inputs` are TxPDO objects (slave→master, assigned to 0x1C13). Vector order is the sync-manager assignment order. Both keys are required; an empty array clears that direction. */
369
+ export interface PdoMappingRequest {
370
+ outputs: PdoMappingRequestObject[];
371
+ inputs: PdoMappingRequestObject[];
372
+ }
373
+ /** One entry of a mapping object, as read back from the device. */
374
+ export interface PdoMappingEntry {
375
+ /**
376
+ * CoE object index; 0 marks an alignment-padding gap
377
+ * @example 24640
378
+ */
379
+ index: number;
380
+ /**
381
+ * CoE object subindex
382
+ * @example 0
383
+ */
384
+ subindex: number;
385
+ /**
386
+ * Width of the entry in bits
387
+ * @example 16
388
+ */
389
+ bitLength: number;
390
+ /**
391
+ * Bit offset from the start of this direction's window (derived by the device)
392
+ * @example 0
393
+ */
394
+ bitOffset: number;
395
+ }
396
+ /** One mapping object as read back, with its ordered entries (offsets included). */
397
+ export interface PdoMappingObject {
398
+ /**
399
+ * Mapping-object index (0x16xx RxPDO for outputs, 0x1Axx TxPDO for inputs)
400
+ * @example 5632
401
+ */
402
+ pdoIndex: number;
403
+ entries: PdoMappingEntry[];
404
+ }
405
+ /** A device's PDO mapping grouped by mapping object — the read/write-back shape. `outputs` are RxPDO objects (0x1C12), `inputs` are TxPDO objects (0x1C13), each in sync-manager assignment order with its entries and derived bit offsets. */
406
+ export interface PdoMapping {
407
+ /** RxPDO objects (master→slave), in assignment order */
408
+ outputs: PdoMappingObject[];
409
+ /** TxPDO objects (slave→master), in assignment order */
410
+ inputs: PdoMappingObject[];
411
+ }
412
+ export interface ProcessImageObject {
413
+ /**
414
+ * 1-based bus position of the owning device
415
+ * @example 1
416
+ */
417
+ slavePosition: number;
418
+ /**
419
+ * CoE object index
420
+ * @example 24640
421
+ */
422
+ index: number;
423
+ /**
424
+ * CoE object subindex
425
+ * @example 0
426
+ */
427
+ subindex: number;
428
+ /**
429
+ * Object name resolved from the device's parameter map; empty when the object dictionary has not been enumerated for that device
430
+ * @example "Target position"
431
+ */
432
+ name: string;
433
+ /**
434
+ * Absolute bit offset within the direction's image
435
+ * @example 32
436
+ */
437
+ bitOffset: number;
438
+ /**
439
+ * Width of the value in bits
440
+ * @example 32
441
+ */
442
+ bitLength: number;
443
+ }
444
+ /** One step of a procedure. `id` is stable across runs, so a client keys its label and its value formatting off it. A step never reports cancellation: cancelling stops the procedure, leaving the step it was on `running` and the rest `idle`, which records how far it got. */
445
+ export interface ProgressStep {
446
+ /**
447
+ * Stable identifier of the step within its procedure.
448
+ * @example "command"
449
+ */
450
+ id: string;
451
+ /** @example "succeeded" */
452
+ status: "idle" | "running" | "succeeded" | "failed";
453
+ /**
454
+ * What the step produced, if anything — shape is per procedure. Absent when the step produced nothing. For `os-command` it is an object with `status`, `data`, `errorCode` when the drive sent one, and `fsBuffer` when the request asked to read bulk data. For `read-object-dictionary` it is an object with `byteCount` and `values`, one entry per object with its `index`, `subindex` and `value`.
455
+ * @example {"status":1,"data":[1,2,3,4,5,6]}
456
+ */
457
+ value?: any;
458
+ /** Why the step failed. Absent unless it did. */
459
+ error?: string;
460
+ }
461
+ /** The complete state of a procedure on one device — an accumulating snapshot rather than an event, which is what makes polling lossless. */
462
+ export interface ProcedureSnapshot {
463
+ /**
464
+ * The one field a polling loop checks. `cancelled` is distinct from `failed` on purpose: "I stopped it" and "the drive could not do it" are different outcomes.
465
+ * @example "succeeded"
466
+ */
467
+ status: "idle" | "running" | "succeeded" | "failed" | "cancelled";
468
+ /**
469
+ * How many runs have been accepted on this device since the last scan or reset; a rejected start does not count. Doubles as a generation counter — with no run id, a changed `runCount` is how a poller can tell one run from the next.
470
+ * @example 3
471
+ */
472
+ runCount: number;
473
+ /**
474
+ * Epoch milliseconds the run began. Absent when never run.
475
+ * @format int64
476
+ * @example 1735821000123
477
+ */
478
+ startedAt?: number;
479
+ /**
480
+ * Epoch milliseconds the run ended. Absent while running.
481
+ * @format int64
482
+ * @example 1735821042456
483
+ */
484
+ finishedAt?: number;
485
+ /** The procedure's ordered steps, always the full template. */
486
+ steps: ProgressStep[];
487
+ /** Why the run failed when no step captured it — a failure belonging to no step, such as the device not being the kind the procedure needs. Absent otherwise. */
488
+ error?: string;
489
+ }
490
+ /** One file stored on a device, as its file list reports it. */
491
+ export interface DeviceFile {
492
+ /**
493
+ * Filename as FoE addresses it.
494
+ * @example "hr_data0.bin"
495
+ */
496
+ name: string;
497
+ /**
498
+ * Size the device reported. Absent when it reported the name without one — the size is what the listing claims, not what a read returned.
499
+ * @example 8032
500
+ */
501
+ byteCount?: number;
502
+ }
503
+ /** One high resolution data recording, read back from a drive's files and decoded. */
504
+ export interface HrdRecording {
505
+ /**
506
+ * Which layout the files were decoded as — echoes the request.
507
+ * @example "encoder-raw"
508
+ */
509
+ data: "encoder-raw" | "system-identification";
510
+ /** The files it was read from, in order. A recording that came back shorter than expected can be told from one that was never made by what is listed here. */
511
+ files: DeviceFile[];
512
+ /**
513
+ * Total bytes read across those files.
514
+ * @example 20000
515
+ */
516
+ byteCount: number;
517
+ /**
518
+ * Bytes past the last whole sample. The drive allocates its files in fixed-size blocks, so this is the last block's padding rather than data that failed to decode.
519
+ * @example 0
520
+ */
521
+ trailingBytes: number;
522
+ /**
523
+ * How many samples were decoded.
524
+ * @example 5000
525
+ */
526
+ sampleCount: number;
527
+ /**
528
+ * What each value of a row is, in order. For `encoder-raw`: `raw` (the 32-bit word the encoder reported), `masterCount` (its low 14 bits) and `noniusCount` (the next 14) — the raw word is kept because the firmware specification describes only bits 0-27 and says nothing about the top four. For `system-identification`: `velocityRpm` (converted out of the file's Q15 fixed point) and `torquePermil` (per mille of rated torque).
529
+ * @example ["raw","masterCount","noniusCount"]
530
+ */
531
+ columns: string[];
532
+ /**
533
+ * One row per sample, positional in the order `columns` gives — a full recording is up to ten thousand rows, so the names travel once beside them rather than on every row.
534
+ * @example [[4661,4661,0],[4662,4662,0]]
535
+ */
536
+ samples: number[][];
537
+ }
538
+ /** One encoder configuration record, 0x2110 for encoder 1 or 0x2112 for encoder 2. */
539
+ export interface EncoderConfiguration {
540
+ /**
541
+ * The ordinal the controller fields refer to; 1 is 0x2110, 2 is 0x2112.
542
+ * @example 1
543
+ */
544
+ encoder: 1 | 2;
545
+ /**
546
+ * The port the encoder is wired to (:01), 0 for none.
547
+ * @example 1
548
+ */
549
+ sensorPort: number;
550
+ /**
551
+ * The kind of encoder (:02). `unknown` for a value this version does not name.
552
+ * @example "biss"
553
+ */
554
+ type: "none" | "hallSensor" | "incremental" | "nikonAFormat" | "biss" | "internal" | "ssi" | "sinCosModule" | "unknown";
555
+ /**
556
+ * Counts per revolution (:03). One revolution of this encoder in position counts.
557
+ * @example 262144
558
+ */
559
+ resolution: number;
560
+ /**
561
+ * Whether the counting direction is inverted (:05).
562
+ * @example false
563
+ */
564
+ inverted: boolean;
565
+ /**
566
+ * Bits of the turn counter in the encoder's frame (:0A).
567
+ * @example 0
568
+ */
569
+ multiturnBits: number;
570
+ /**
571
+ * Bits of the position within one turn in the encoder's frame (:0C).
572
+ * @example 18
573
+ */
574
+ singleturnBits: number;
575
+ }
576
+ /** Both encoder records of a SOMANET drive and which of them each controller uses. The three controller fields hold an ordinal of the `encoders` list, or `null` when the controller names no encoder. */
577
+ export interface Encoders {
578
+ encoders: EncoderConfiguration[];
579
+ /**
580
+ * The encoder position control uses (0x2012:09).
581
+ * @example 1
582
+ */
583
+ position: 1 | 2 | null;
584
+ /**
585
+ * The encoder velocity control uses (0x2011:05).
586
+ * @example 1
587
+ */
588
+ velocity: 1 | 2 | null;
589
+ /**
590
+ * The encoder commutation uses (0x2010:0C).
591
+ * @example 1
592
+ */
593
+ commutation: 1 | 2 | null;
594
+ }
595
+ /** A drive's brake configuration and current state — the parts of object 0x2004 that decide what commanding the brake will actually do. Returned by every brake endpoint, so the outcome of a release or engage arrives in the same shape as a plain read. */
596
+ export interface BrakeState {
597
+ /**
598
+ * Brake state (0x2004:07). A brake is spring-engaged, so `engaged` is also its powered-off state.
599
+ * @example "engaged"
600
+ */
601
+ status: "notConfigured" | "engaged" | "disengaged";
602
+ /**
603
+ * How the brake is driven (0x2004:04). `manualOutputVoltage` means the firmware does not drive it — the brake is a raw output voltage (0x2004:10) instead.
604
+ * @example "clutch"
605
+ */
606
+ releaseStrategy: "manualOutputVoltage" | "clutch" | "pin";
607
+ /**
608
+ * How long the pull voltage is applied to release the brake (0x2004:03). The firmware blocks motion, and motion-related OS commands, until this expires.
609
+ * @example 120
610
+ */
611
+ pullTimeMs: number;
612
+ /**
613
+ * Voltage that disengages the brake, in millivolts (0x2004:01).
614
+ * @example 24000
615
+ */
616
+ pullVoltageMv: number;
617
+ /**
618
+ * Lower voltage that keeps it disengaged once released, in millivolts (0x2004:02).
619
+ * @example 12000
620
+ */
621
+ holdVoltageMv: number;
622
+ /**
623
+ * Whether commanding the brake does anything at all — false for `manualOutputVoltage`. Derived from the release strategy and served so a client need not encode that rule.
624
+ * @example true
625
+ */
626
+ softwareControllable: boolean;
627
+ /**
628
+ * Whether releasing this brake turns the motor. True only for a pin brake, whose release raises current progressively to lift the load off the pin.
629
+ * @example false
630
+ */
631
+ releaseMovesShaft: boolean;
632
+ }
633
+ /** What a procedure *is*, independent of any run — everything needed to render a control for it. The text is served rather than held per client, because the house rule that every action carries a description and its caveats means it has to exist somewhere, and duplicating it in each client is how it goes stale. */
634
+ export interface ProcedureDescriptor {
635
+ /**
636
+ * Identifier: the `procedureName` path segment, and the key its snapshot is retained under.
637
+ * @example "os-command"
638
+ */
639
+ name: string;
640
+ /**
641
+ * Short human-readable name.
642
+ * @example "OS command"
643
+ */
644
+ title: string;
645
+ /** What the procedure does. */
646
+ description: string;
647
+ /** What a user must know before running it. May be empty. */
648
+ caveats: string[];
649
+ /**
650
+ * True if running it can move the shaft.
651
+ * @example true
652
+ */
653
+ movesMotor: boolean;
654
+ /**
655
+ * True if the drive must be enabled before it will run.
656
+ * @example false
657
+ */
658
+ requiresEnabled: boolean;
659
+ /** What the request body may carry, in the order a client should present it. Empty for a procedure that takes none, which is most of them — a procedure's timings are properties of the command it issues rather than a caller's choice. */
660
+ parameters: ProcedureParameter[];
661
+ /**
662
+ * The ordered step ids the procedure reports against — bare ids, because a template's per-step status is always idle and says nothing. Live status for the same ids is in the snapshot's `steps`.
663
+ * @example ["command"]
664
+ */
665
+ steps: string[];
666
+ }
667
+ /** One choice of an `enum` parameter. */
668
+ export interface ParameterOption {
669
+ /**
670
+ * What the request body carries when this option is chosen.
671
+ * @example 1
672
+ */
673
+ value: any;
674
+ /**
675
+ * What the user picks.
676
+ * @example "Encoder 1"
677
+ */
678
+ title: string;
679
+ }
680
+ /** One named parameter a procedure accepts — enough to render a field for it and to know what to put in. Descriptive rather than authoritative: the server validates every request whatever a client sends, and this is what lets a client build a sensible form and catch a mistake before the request goes out. The three type-specific fields are absent where they do not apply. */
681
+ export interface ProcedureParameter {
682
+ /**
683
+ * The key in the request body.
684
+ * @example "registerAddress"
685
+ */
686
+ name: string;
687
+ /**
688
+ * Short label.
689
+ * @example "Register address"
690
+ */
691
+ title: string;
692
+ /** What it does and what a sensible value is. */
693
+ description: string;
694
+ /**
695
+ * Which kind of control to render. `file` carries a whole file as a base64 string, so a client renders a file picker and encodes what it reads; `stringArray` is an editable list of free-text values.
696
+ * @example "integer"
697
+ */
698
+ type: "integer" | "boolean" | "enum" | "byteArray" | "string" | "stringArray" | "file";
699
+ /**
700
+ * Whether a request must carry it — true exactly when there is no `defaultValue`. Reported rather than left to be derived, so a client need not know the rule.
701
+ * @example true
702
+ */
703
+ required: boolean;
704
+ /**
705
+ * What an omitting request gets. Absent when the parameter is required.
706
+ * @example 1
707
+ */
708
+ defaultValue?: any;
709
+ /**
710
+ * `integer` only: smallest accepted value.
711
+ * @example 0
712
+ */
713
+ minValue?: number;
714
+ /**
715
+ * `integer` only: largest accepted value.
716
+ * @example 255
717
+ */
718
+ maxValue?: number;
719
+ /**
720
+ * `byteArray` only: the exact number of bytes.
721
+ * @example 8
722
+ */
723
+ length?: number;
724
+ /** `enum` only: the values that may be chosen. */
725
+ options?: ParameterOption[];
726
+ }
727
+ /** A SOMANET firmware package filename broken into its fields. The four decoded-descriptor properties are absent — not null — when the full firmware descriptor is not the numeric kind, which the naming specification explicitly allows. */
728
+ export interface FirmwarePackageName {
729
+ /**
730
+ * The format description; always `package` for a firmware bundle.
731
+ * @example "package"
732
+ */
733
+ description: string;
734
+ /**
735
+ * Human-readable hardware name.
736
+ * @example "SOMANET-Circulo-7"
737
+ */
738
+ hardwareName: string;
739
+ /**
740
+ * The hardware this package is built for, verbatim — the string a compatibility check compares.
741
+ * @example "8500-04-2332"
742
+ */
743
+ fullFirmwareDescriptor: string;
744
+ /**
745
+ * Firmware or software name.
746
+ * @example "motion-drive"
747
+ */
748
+ softwareName: string;
749
+ /**
750
+ * The firmware or software version, including the leading `v`. Not to be confused with `firmwareVersion`, which is the *hardware* revision inside the descriptor.
751
+ * @example "v5.6.10"
752
+ */
753
+ softwareVersion: string;
754
+ /**
755
+ * Firmware id from the descriptor — the hardware product.
756
+ * @example "8500"
757
+ */
758
+ firmwareId?: string;
759
+ /**
760
+ * Hardware revision from the descriptor. A string, so a leading zero survives: `04` read as a number and printed back would be `4`, and `8500-4` matches no package.
761
+ * @example "04"
762
+ */
763
+ firmwareVersion?: string;
764
+ /**
765
+ * Firmware encryption key id from the descriptor. A string because real packages carry non-numeric ones, e.g. `A`.
766
+ * @example "2332"
767
+ */
768
+ keyId?: string;
769
+ /**
770
+ * Fieldbus protocol character from the descriptor, hexadecimal. `1` is EtherCAT.
771
+ * @example "1"
772
+ */
773
+ fieldbusProtocol?: string;
774
+ /**
775
+ * `firmwareId` and `firmwareVersion` joined — the descriptor without the key or fieldbus. Useful for saying *how* a package missed: a matching build descriptor with a different key means right hardware, wrong encryption key.
776
+ * @example "8500-04"
777
+ */
778
+ buildDescriptor?: string;
779
+ }
780
+ /** One item making up a device or assembly. Carries no function beyond recording what has a serial number, so every property can legitimately be empty. */
781
+ export interface HardwareComponent {
782
+ /** @example "Com EtherCAT" */
783
+ name: string;
784
+ /** @example "A.2" */
785
+ version: string;
786
+ /** @example "1000-02-0005739-1815" */
787
+ serialNumber: string;
788
+ }
789
+ /** A device or an assembly. The two are one shape — the specification lists their fields in a single table and they differ only in that `keyId` and `macAddress` are device-only. */
790
+ export interface HardwareProduct {
791
+ /**
792
+ * Human-readable description of the hardware.
793
+ * @example "SOMANET Servo Node 400 EtherCAT"
794
+ */
795
+ name: string;
796
+ /**
797
+ * Names the product's picture. Empty when the file carries none.
798
+ * @example "9501-xx"
799
+ */
800
+ imageId: string;
801
+ /**
802
+ * The `firmwareId` — identifies the hardware product.
803
+ * @example "9501"
804
+ */
805
+ id: string;
806
+ /**
807
+ * The `firmwareVersion` — revision of that product.
808
+ * @example "01"
809
+ */
810
+ version: string;
811
+ /**
812
+ * Firmware encryption key burned to OTP memory. Device only, and empty on hardware whose firmware predates encryption.
813
+ * @example "4622"
814
+ */
815
+ keyId: string;
816
+ /** @example "9501-01-040595-4023" */
817
+ serialNumber: string;
818
+ /**
819
+ * MAC address of the Ethernet port. Device only.
820
+ * @example "01-23-45-67-89-AB"
821
+ */
822
+ macAddress: string;
823
+ components: HardwareComponent[];
824
+ /**
825
+ * `id` and `version` joined by a dash.
826
+ * @example "9501-01"
827
+ */
828
+ buildDescriptor: string;
829
+ }
830
+ /**
831
+ * A device's `.hardware_description` file — what the hardware says it is, and the source of the descriptor that decides which firmware belongs on it.
832
+ *
833
+ * `device` is never absent, and that is structural rather than a simplification: the file lives *on* the device, so a file without one cannot exist. `assembly` is present only when the device was packaged into a product — an ACTILINK is an assembly with a SOMANET Node device inside it — and when it is, it is what firmware is matched against first.
834
+ */
835
+ export interface HardwareDescription {
836
+ /**
837
+ * Format version of the file itself, semver.
838
+ * @example "1.2.0"
839
+ */
840
+ fileVersion: string;
841
+ /** A device or an assembly. The two are one shape — the specification lists their fields in a single table and they differ only in that `keyId` and `macAddress` are device-only. */
842
+ device: HardwareProduct;
843
+ /** A device or an assembly. The two are one shape — the specification lists their fields in a single table and they differ only in that `keyId` and `macAddress` are device-only. */
844
+ assembly?: HardwareProduct;
845
+ }
846
+ /** One entry of the Integro runtime-variant option catalogue. Nothing on the server acts on `socVariables` or `incompatibleOptionIds` — the drive enforces them — but they are what make a decoded file legible. */
847
+ export interface IntegroVariantOption {
848
+ /**
849
+ * The option code as it appears in the file.
850
+ * @example 1
851
+ */
852
+ id: number;
853
+ /**
854
+ * What the option selects.
855
+ * @example "Fieldbus Protocol"
856
+ */
857
+ category: string;
858
+ /**
859
+ * Which choice within that category.
860
+ * @example "EtherCAT"
861
+ */
862
+ meaning: string;
863
+ /**
864
+ * The drive's own configuration values this option sets. Empty for an option the fieldbus firmware acts on rather than the SoC.
865
+ * @example ["adc_phase_current_sensor_gain"]
866
+ */
867
+ socVariables: string[];
868
+ /**
869
+ * Options that cannot be selected alongside this one — the other members of a category that selects exactly one choice. Empty for an independent flag such as "disable DI1".
870
+ * @example [0,2,3,39]
871
+ */
872
+ incompatibleOptionIds: number[];
873
+ /**
874
+ * Segments of the part number this option corresponds to. Empty for an option not distinguished in the part number.
875
+ * @example ["EC"]
876
+ */
877
+ mpnSegmentCodes: string[];
878
+ }
879
+ /** One option code from a decoded file, expanded into its catalogue entry. Everything but `id` is absent for a code the catalogue does not name, so "we do not know what this is" is missing properties rather than the string `unknown`. */
880
+ export type IntegroVariantFileOption = UtilRequiredKeys<IntegroVariantOption, "id">;
881
+ /**
882
+ * A decoded `.variant` file: which features a SOMANET Integro was licensed with.
883
+ *
884
+ * Only Integro drives carry one. Its layout comes from the firmware that reads it rather than from a specification — there is none — and the one thing on it that matters beyond inspection is `fieldbusProtocol`, which the hardware description deliberately does not carry and a full firmware descriptor ends with.
885
+ */
886
+ export interface IntegroVariant {
887
+ /**
888
+ * Format version; 1 in every file seen so far.
889
+ * @example 1
890
+ */
891
+ fileVersion: number;
892
+ /** Lowercase hex. Opaque — verification needs the private key and happens on the drive — and reported only so a caller can see whether one is present. */
893
+ signature: string;
894
+ /**
895
+ * Lowercase hex netX chip id this file was issued for.
896
+ * @example "4e64646c70b286a000000000"
897
+ */
898
+ chipId: string;
899
+ /** @example "9004-02-0000424-2445" */
900
+ serialNumber: string;
901
+ /** @example "40:49:8A:01:21:D6" */
902
+ macAddress: string;
903
+ /**
904
+ * Who the device was licensed to.
905
+ * @example 1
906
+ */
907
+ customerId: number;
908
+ /**
909
+ * Raw mode value. `passive` (0x51) is the failure state as much as a mode: firmware falls back to it when the file is missing, its signature does not verify, or its chip id belongs to another device.
910
+ * @example 87
911
+ */
912
+ operationMode: number;
913
+ /** @example "live" */
914
+ operationModeName: "passive" | "trial" | "production" | "live" | "unknown";
915
+ /**
916
+ * The fieldbus the device is licensed for, for the tail of a full firmware descriptor. **EtherCAT wins when several are selected** — real files do carry more than one. Absent when the file selects no fieldbus at all.
917
+ * @example 1
918
+ */
919
+ fieldbusProtocol?: number;
920
+ /** The option codes, in the order the file lists them — which is not sorted, and is the only record of how the file was written. */
921
+ options: IntegroVariantFileOption[];
922
+ }
923
+ /** The full firmware descriptors one device accepts firmware under. Two rather than one because the specification says both are compatible and lists both for the user to choose from: the assembly's firmware "should have been customized for the assembly", so it is the one to prefer, while the device package is the generic build for the hardware inside it. */
924
+ export interface FullFirmwareDescriptors {
925
+ /**
926
+ * The device's own descriptor. Always present.
927
+ * @example "9010-02-2423-1"
928
+ */
929
+ device: string;
930
+ /**
931
+ * The assembly's build descriptor with the **device's** key id — assemblies have no key of their own. Absent when the hardware description carries no assembly.
932
+ * @example "6000-01-2423-1"
933
+ */
934
+ assembly?: string;
935
+ }
936
+ /**
937
+ * Whether one firmware package belongs on one device.
938
+ *
939
+ * **The whole descriptor string is compared, never its decoded parts.** That is what makes the check correct for descriptors outside the numeric convention, and it is how the specification frames the operation — find compatible firmware by searching for the `fullFirmwareDescriptor` string.
940
+ */
941
+ export interface FirmwareCompatibility {
942
+ /** @example true */
943
+ compatible: boolean;
944
+ /**
945
+ * Which of the device's descriptors matched. `device` is a match that still has something to say: it is the generic build rather than the one customised for the assembly.
946
+ * @example "assembly"
947
+ */
948
+ match: "none" | "assembly" | "device";
949
+ /** A SOMANET firmware package filename broken into its fields. The four decoded-descriptor properties are absent — not null — when the full firmware descriptor is not the numeric kind, which the naming specification explicitly allows. */
950
+ packageName: FirmwarePackageName;
951
+ /** The full firmware descriptors one device accepts firmware under. Two rather than one because the specification says both are compatible and lists both for the user to choose from: the assembly's firmware "should have been customized for the assembly", so it is the one to prefer, while the device package is the generic build for the hardware inside it. */
952
+ deviceDescriptors: FullFirmwareDescriptors;
953
+ /**
954
+ * One sentence naming the descriptors involved, ready to show a user. Populated for a match as well as a mismatch.
955
+ * @example "This package is built for 6000-01-2423-1, which is this device's assembly."
956
+ */
957
+ explanation: string;
958
+ }
959
+ /** One procedure paired with how its last run on this device went — an entry of `GET /api/devices/{slavePosition}/procedures`. The pairing is what lets a page render in a single request instead of one per procedure. */
960
+ export interface ProcedureListing {
961
+ /** What a procedure *is*, independent of any run — everything needed to render a control for it. The text is served rather than held per client, because the house rule that every action carries a description and its caveats means it has to exist somewhere, and duplicating it in each client is how it goes stale. */
962
+ descriptor: ProcedureDescriptor;
963
+ /** The complete state of a procedure on one device — an accumulating snapshot rather than an event, which is what makes polling lossless. */
964
+ snapshot: ProcedureSnapshot;
965
+ }
966
+ /** A procedure's parameters. Which fields apply is per procedure, and each descriptor reports its own in `parameters` — so this schema is open, and a procedure that takes none may be started with no body at all. The properties below are the union of every procedure's, each naming the procedure it belongs to. */
967
+ export interface ProcedureRequest {
968
+ /**
969
+ * `os-command` only, and required for it: the eight request bytes. Byte 0 is the OS command ID; bytes 1-7 are that command's parameters.
970
+ * @maxItems 8
971
+ * @minItems 8
972
+ * @example [8,0,0,0,0,0,0,0]
973
+ */
974
+ command?: number[];
975
+ /**
976
+ * Ceiling on the whole command. Not a liveness check — the drive fails a command no service acknowledges within 5 s on its own — so size it for the command being run. Hitting it aborts the command on the drive.
977
+ * @min 1
978
+ * @max 600000
979
+ * @default 1000
980
+ * @example 30000
981
+ */
982
+ timeoutMs?: number;
983
+ /**
984
+ * `os-command` only: how often the server reads the drive's response object while waiting.
985
+ * @min 1
986
+ * @max 1000
987
+ * @default 10
988
+ */
989
+ pollIntervalMs?: number;
990
+ /**
991
+ * `os-command` only: whether the command moves bulk data through the drive's fs-buffer, and which way. Most commands move none. The transfer runs while the command runs, because the drive holds the command in progress until all the data has moved, and it needs firmware 5.2 or newer. Setting a direction for a command that moves no bulk data leaves the server waiting for a transfer the drive will never start.
992
+ * @default "none"
993
+ * @example "read"
994
+ */
995
+ fsBuffer?: "none" | "read" | "write";
996
+ /** `os-command` only, and required when `fsBuffer` is `write`: the bytes to send, base64-encoded into this JSON string. Rejected for the other two directions rather than ignored, so a request that names one and forgets the other is told rather than running a command that moves nothing. (Deliberately not `format: byte`, for the reason spelled out on `packageContent`.) */
997
+ fsBufferData?: string;
998
+ /**
999
+ * `encoder-register-communication` and `ic-mu-calibration-mode`: which of the drive's encoders to address. Encoder 1 is the encoder configured in 0x2110 and encoder 2 the one configured in 0x2112, so the ordinal picks a configuration object rather than a kind of encoder.
1000
+ * @default 1
1001
+ * @example 1
1002
+ */
1003
+ encoder?: 1 | 2;
1004
+ /**
1005
+ * `encoder-register-communication` only: false reads the register, true writes `value` into it. Either way the drive reports what the register holds afterwards.
1006
+ * @default false
1007
+ */
1008
+ write?: boolean;
1009
+ /**
1010
+ * `encoder-register-communication` only, and required for it: the register to access. The map belongs to the encoder chip rather than to the drive's firmware.
1011
+ * @min 0
1012
+ * @max 255
1013
+ * @example 117
1014
+ */
1015
+ registerAddress?: number;
1016
+ /**
1017
+ * `encoder-register-communication` only: the byte to write into the register. Ignored when reading.
1018
+ * @min 0
1019
+ * @max 255
1020
+ * @default 0
1021
+ * @example 7
1022
+ */
1023
+ value?: number;
1024
+ /**
1025
+ * `hrd-streaming` only, and required for it: which signal to record. Also decides how the recording decodes when it is read back from `/api/devices/{slavePosition}/hrd`.
1026
+ * @example "encoder-raw"
1027
+ */
1028
+ data?: "encoder-raw" | "system-identification";
1029
+ /**
1030
+ * `hrd-streaming` only, and required for it: how long to record. One sample is written every millisecond into at most five 8032-byte files, so the real ceiling depends on the sample size — 10000 ms for `encoder-raw`, but only 6000 ms for `system-identification`. The drive applies both limits; the narrower one is checked here too, so an over-long request is rejected before a run starts rather than failing on its first step.
1031
+ * @min 1
1032
+ * @max 10000
1033
+ * @example 5000
1034
+ */
1035
+ durationMs?: number;
1036
+ /**
1037
+ * `ic-mu-calibration-mode` only, and required for it: how the BiSS service should clock the encoder. `standard` is normal operation; `configuration` keeps the encoder clocked but uses only the register-communication bits, so position stops updating and no CRC fault is raised; `raw` clocks an encoder already configured for raw output and averages that data into 0x2704. There is no default — the mode is the instruction.
1038
+ * @example "configuration"
1039
+ */
1040
+ mode?: "configuration" | "raw" | "standard";
1041
+ /**
1042
+ * `restore-default-parameters` only: which group of defaults to restore — all (0x1011:01), communication (0x1011:02), application (0x1011:03), or manufacturer (0x1011:04).
1043
+ * @default "all"
1044
+ * @example "all"
1045
+ */
1046
+ group?: "all" | "communication" | "application" | "manufacturer";
1047
+ /**
1048
+ * `device-locate` only: how long the LEDs blink, in seconds. They stop at the end, and when the run is cancelled. Only a device whose transport can blink the LEDs offers `device-locate`, which today is a SPoE drive.
1049
+ * @min 1
1050
+ * @max 3600
1051
+ * @default 10
1052
+ * @example 10
1053
+ */
1054
+ duration?: number;
1055
+ /** `firmware-installation`: the .zip firmware package, base64-encoded into this JSON string. One of this or a `packageFilename` naming an already-cached package must be present; this wins when both are given. To avoid base64 entirely, `PUT` the raw bytes to `/api/user-cache/firmwares/<name>.zip` first and then send only `packageFilename` — the firmware cache is that directory. (Deliberately not `format: byte`: that is the correct OpenAPI spelling for base64, but generators map it to a binary type — `Blob` in TypeScript — which is not what goes on the wire here and would serialise to `{}`.) */
1056
+ packageContent?: string;
1057
+ /**
1058
+ * `firmware-installation`: the package's filename. Optional — it names the package for caching and identifies a cached one to re-install without uploading it again. A name outside the SOMANET convention still installs, it is just not cached.
1059
+ * @example "package_SOMANET-Circulo-7_8500-04-2332_motion-drive_v5.6.10.zip"
1060
+ */
1061
+ packageFilename?: string;
1062
+ /**
1063
+ * `firmware-installation`: entries inside the package that are not written to the device. An explicit list replaces the defaults wholesale rather than adding to them, so `[]` means "write everything the package holds". Any entry can be named, including the SII and the firmware binaries.
1064
+ * @default ["SOMANET_CiA_402.xml.zip","stack_image.svg.zip"]
1065
+ */
1066
+ skipFiles?: string[];
1067
+ /**
1068
+ * `firmware-installation`: keep a copy of the package on the server so it can be re-installed without uploading it again. Only possible when a filename is given and it follows the SOMANET package naming convention.
1069
+ * @default true
1070
+ */
1071
+ cachePackage?: boolean;
1072
+ /**
1073
+ * `firmware-installation`: where the device is left, as an AL state number — the same ETG.1000.6 encoding `POST /api/devices/state` takes and `alState` reports, so a client holds one way to name a state rather than two. `2` (PRE-OP) is the default and the confirmation that the install worked: the bootloader hands over to the newly written firmware on that transition, so reaching PRE-OP means the new firmware booted. No power cycle is needed for the firmware (an SII written from the package does need one — the ESC reads its EEPROM at reset). Choose `3` (BOOT) when no application will be present, after erasing one or between two installs, since a PRE-OP transition then has nothing to hand over to and the drive answers AL status `0x0014`, "No valid firmware". `4` and `8` climb through PRE-OP and re-map the whole bus on the way, briefly pausing every other device. The state the device was in beforehand is not restored. Over SPoE the drive restarts into the new firmware and comes up in PRE-OP, so `3` cannot keep it in BOOT.
1074
+ * @default 2
1075
+ * @example 2
1076
+ */
1077
+ finalState?: 1 | 2 | 3 | 4 | 8;
1078
+ [key: string]: any;
1079
+ }
1080
+ export interface OutputStageResult {
1081
+ /**
1082
+ * 1-based bus position of the owning device (echoes the request)
1083
+ * @example 1
1084
+ */
1085
+ slavePosition: number;
1086
+ /**
1087
+ * CoE object index (echoes the request)
1088
+ * @example 24698
1089
+ */
1090
+ index: number;
1091
+ /**
1092
+ * CoE object subindex (echoes the request)
1093
+ * @example 0
1094
+ */
1095
+ subindex: number;
1096
+ /**
1097
+ * True when the value landed in the published output image and will be sent on the next exchange cycle
1098
+ * @example true
1099
+ */
1100
+ staged: boolean;
1101
+ /**
1102
+ * Empty on success; otherwise why the object was not cyclically staged (unknown device, coercion failure, object not output-mapped, or the bus not exchanging)
1103
+ * @example ""
1104
+ */
1105
+ error: string;
1106
+ }
1107
+ export interface SyncManagerConfig {
1108
+ /**
1109
+ * Sync Manager number (0–7)
1110
+ * @example 2
1111
+ */
1112
+ index: number;
1113
+ /**
1114
+ * Physical ESC memory start address the SM guards
1115
+ * @example 4352
1116
+ */
1117
+ physicalStart: number;
1118
+ /**
1119
+ * Length of the guarded window in bytes
1120
+ * @example 12
1121
+ */
1122
+ length: number;
1123
+ /**
1124
+ * Raw SM control/flags register (buffer mode, direction, watchdog, enable) — decoded by the client
1125
+ * @example 100100
1126
+ */
1127
+ flags: number;
1128
+ /**
1129
+ * 0 unused, 1 MbxOut, 2 MbxIn, 3 Outputs, 4 Inputs
1130
+ * @example 3
1131
+ */
1132
+ type: number;
1133
+ }
1134
+ export interface FmmuConfig {
1135
+ /**
1136
+ * FMMU number (0–3)
1137
+ * @example 0
1138
+ */
1139
+ index: number;
1140
+ /**
1141
+ * Logical (bus-wide) start address
1142
+ * @example 0
1143
+ */
1144
+ logicalStart: number;
1145
+ /**
1146
+ * Mapped length in bytes
1147
+ * @example 12
1148
+ */
1149
+ length: number;
1150
+ /**
1151
+ * Start bit within the first logical byte
1152
+ * @example 0
1153
+ */
1154
+ logicalStartBit: number;
1155
+ /**
1156
+ * End bit within the last logical byte
1157
+ * @example 7
1158
+ */
1159
+ logicalEndBit: number;
1160
+ /**
1161
+ * Physical ESC start address (ties the FMMU to a Sync Manager)
1162
+ * @example 4352
1163
+ */
1164
+ physicalStart: number;
1165
+ /**
1166
+ * Start bit within the first physical byte
1167
+ * @example 0
1168
+ */
1169
+ physicalStartBit: number;
1170
+ /**
1171
+ * ESC FMMU type: 1 read (inputs/TxPDO), 2 write (outputs/RxPDO)
1172
+ * @example 2
1173
+ */
1174
+ type: number;
1175
+ /**
1176
+ * Whether the FMMU is active
1177
+ * @example true
1178
+ */
1179
+ active: boolean;
1180
+ }
1181
+ export interface SlaveConfig {
1182
+ /**
1183
+ * 1-based bus position
1184
+ * @example 1
1185
+ */
1186
+ slavePosition: number;
1187
+ /**
1188
+ * SII device name for this slave position, empty if unknown. For SOMANET drives this is the generic group name "SOMANET"; use productName to distinguish products.
1189
+ * @example "SOMANET"
1190
+ */
1191
+ deviceName: string;
1192
+ /**
1193
+ * Canonical product name, empty if unknown. For a recognised SOMANET product this distinguishes the product (e.g. "SOMANET Circulo"); otherwise it falls back to deviceName.
1194
+ * @example "SOMANET Node"
1195
+ */
1196
+ productName: string;
1197
+ /**
1198
+ * Vendor ID from EEPROM (0 if the slave is unknown)
1199
+ * @format int64
1200
+ * @example 8914
1201
+ */
1202
+ vendorId: number;
1203
+ /**
1204
+ * Product code from EEPROM
1205
+ * @format int64
1206
+ * @example 769
1207
+ */
1208
+ productCode: number;
1209
+ /**
1210
+ * Revision number from EEPROM
1211
+ * @format int64
1212
+ * @example 285212675
1213
+ */
1214
+ revisionNumber: number;
1215
+ /**
1216
+ * Serial number from EEPROM
1217
+ * @format int64
1218
+ * @example 0
1219
+ */
1220
+ serialNumber: number;
1221
+ /**
1222
+ * Station (configured) address assigned during scan
1223
+ * @example 4097
1224
+ */
1225
+ configuredAddress: number;
1226
+ /**
1227
+ * Configured station alias from EEPROM
1228
+ * @example 0
1229
+ */
1230
+ aliasAddress: number;
1231
+ /**
1232
+ * Mapped output (master→slave) bits
1233
+ * @example 96
1234
+ */
1235
+ outputBits: number;
1236
+ /**
1237
+ * Mapped input (slave→master) bits
1238
+ * @example 128
1239
+ */
1240
+ inputBits: number;
1241
+ mailbox: {
1242
+ /**
1243
+ * Write (master→slave) mailbox length in bytes; 0 if none
1244
+ * @example 128
1245
+ */
1246
+ writeLength: number;
1247
+ /**
1248
+ * Write mailbox physical ESC offset
1249
+ * @example 4096
1250
+ */
1251
+ writeOffset: number;
1252
+ /**
1253
+ * Read (slave→master) mailbox length in bytes
1254
+ * @example 128
1255
+ */
1256
+ readLength: number;
1257
+ /**
1258
+ * Read mailbox physical ESC offset
1259
+ * @example 4224
1260
+ */
1261
+ readOffset: number;
1262
+ /**
1263
+ * Supported-protocol bits (0x01 AoE, 0x02 EoE, 0x04 CoE, 0x08 FoE, 0x10 SoE, 0x20 VoE) — decoded by the client
1264
+ * @example 14
1265
+ */
1266
+ protocols: number;
1267
+ /**
1268
+ * CoE detail bits, advertised in EEPROM — decoded by the client (0x01 SDO, 0x02 SDO-Info, 0x04 PDO-Assign, 0x08 PDO-Config, 0x10 Upload, 0x20 Complete-Access). A hint, not a guarantee.
1269
+ * @example 15
1270
+ */
1271
+ coeDetails: number;
1272
+ /**
1273
+ * FoE detail byte (bit 0 = enabled).
1274
+ * @example 1
1275
+ */
1276
+ foeDetails: number;
1277
+ /**
1278
+ * EoE detail byte (bit 0 = enabled).
1279
+ * @example 0
1280
+ */
1281
+ eoeDetails: number;
1282
+ /**
1283
+ * SoE detail byte / channel count.
1284
+ * @example 0
1285
+ */
1286
+ soeDetails: number;
1287
+ };
1288
+ dc: {
1289
+ /**
1290
+ * Slave has distributed-clock hardware
1291
+ * @example true
1292
+ */
1293
+ capable: boolean;
1294
+ /**
1295
+ * SYNC0 generation enabled (false for SM-synchronous bring-up)
1296
+ * @example false
1297
+ */
1298
+ active: boolean;
1299
+ /**
1300
+ * Measured propagation delay in nanoseconds
1301
+ * @example 300
1302
+ */
1303
+ propagationDelay: number;
1304
+ /**
1305
+ * DC cycle time in nanoseconds
1306
+ * @example 0
1307
+ */
1308
+ cycleTime: number;
1309
+ /**
1310
+ * Shift from the cycle-modulus boundary in nanoseconds
1311
+ * @example 0
1312
+ */
1313
+ shift: number;
1314
+ };
1315
+ /** Configured Sync Managers, by index */
1316
+ syncManagers: SyncManagerConfig[];
1317
+ /** Configured FMMUs, by index */
1318
+ fmmus: FmmuConfig[];
1319
+ }
1320
+ export interface PortDiagnostics {
1321
+ /**
1322
+ * Physical link detected on this port (DL Status link bit)
1323
+ * @example true
1324
+ */
1325
+ linkUp: boolean;
1326
+ /**
1327
+ * Loop closed on this port (no downstream slave, or port disabled)
1328
+ * @example false
1329
+ */
1330
+ loopClosed: boolean;
1331
+ /**
1332
+ * Stable communication established on this port
1333
+ * @example true
1334
+ */
1335
+ communication: boolean;
1336
+ /**
1337
+ * Invalid-frame counter (0x0300+): frames with a bad FCS/structure. 8-bit, saturates at 255; watch for a rising delta rather than the absolute value
1338
+ * @example 0
1339
+ */
1340
+ invalidFrame: number;
1341
+ /**
1342
+ * Physical-layer RX error counter (0x0301+): RX_ER asserted by the PHY
1343
+ * @example 0
1344
+ */
1345
+ rxError: number;
1346
+ /**
1347
+ * Forwarded RX error counter (0x0308+): errors first flagged by an upstream ESC — pinpoints the segment where corruption began
1348
+ * @example 0
1349
+ */
1350
+ forwardedError: number;
1351
+ /**
1352
+ * Lost-link counter (0x0310+): link-down events on this port
1353
+ * @example 0
1354
+ */
1355
+ lostLink: number;
1356
+ }
1357
+ export interface DeviceDiagnostics {
1358
+ /**
1359
+ * 1-based position on the fieldbus
1360
+ * @example 1
1361
+ */
1362
+ slavePosition: number;
1363
+ /**
1364
+ * Device name for this slave position, empty if unknown
1365
+ * @example "SOMANET Node"
1366
+ */
1367
+ deviceName: string;
1368
+ /** Per-port link state and error counters (ports 0–3, in order) */
1369
+ ports: PortDiagnostics[];
1370
+ /**
1371
+ * ECAT processing-unit error counter (0x030C): datagrams reaching the unit malformed
1372
+ * @example 0
1373
+ */
1374
+ processingUnitError: number;
1375
+ /**
1376
+ * PDI error counter (0x030D): problems on the slave-local process-data interface
1377
+ * @example 0
1378
+ */
1379
+ pdiError: number;
1380
+ /**
1381
+ * Process-data (SM) watchdog expirations (0x0442): the slave stopped seeing fresh outputs
1382
+ * @example 0
1383
+ */
1384
+ processDataWatchdog: number;
1385
+ /**
1386
+ * PDI watchdog expirations (0x0443)
1387
+ * @example 0
1388
+ */
1389
+ pdiWatchdog: number;
1390
+ }
1391
+ export interface DcSyncStatus {
1392
+ /**
1393
+ * 1-based position on the fieldbus
1394
+ * @example 1
1395
+ */
1396
+ slavePosition: number;
1397
+ /**
1398
+ * Device name for this slave position, empty if unknown
1399
+ * @example "SOMANET Node"
1400
+ */
1401
+ deviceName: string;
1402
+ /**
1403
+ * Slave has distributed-clock hardware
1404
+ * @example true
1405
+ */
1406
+ dcCapable: boolean;
1407
+ /**
1408
+ * This slave is the DC reference clock (the first DC-capable slave) — it defines bus time, so its own systemTimeDifference is zero
1409
+ * @example false
1410
+ */
1411
+ referenceClock: boolean;
1412
+ /**
1413
+ * System-time delay / propagation delay (0x0928), nanoseconds
1414
+ * @example 300
1415
+ */
1416
+ propagationDelay: number;
1417
+ /**
1418
+ * Signed deviation of the local system time from the reference clock (0x092C), in nanoseconds. Positive = local clock ahead of the reference, negative = behind; zero on the reference clock. Meaningful only while exchanging in SAFE-OP/OP; converges toward zero as the drift-compensation loop settles
1419
+ * @example 0
1420
+ */
1421
+ systemTimeDifference: number;
1422
+ }
1423
+ /** The counts for one kind of frame. The bands are cumulative. */
1424
+ export interface CaptureKindSummary {
1425
+ /**
1426
+ * Frames the master sent. A frame sent again counts once.
1427
+ * @example 60021
1428
+ */
1429
+ sent: number;
1430
+ /**
1431
+ * Frames sent again with the same index and header while the first copy had no answer yet. A register datagram goes out again every 2 ms, so a late one shows here too.
1432
+ * @example 12
1433
+ */
1434
+ resent: number;
1435
+ /**
1436
+ * Sent frames that came back
1437
+ * @example 60018
1438
+ */
1439
+ returned: number;
1440
+ /**
1441
+ * Sent frames with no return before the capture ended
1442
+ * @example 3
1443
+ */
1444
+ lost: number;
1445
+ /**
1446
+ * Returns later than 2 ms after the first send
1447
+ * @example 1210
1448
+ */
1449
+ over2Ms: number;
1450
+ /**
1451
+ * Returns later than 20 ms. Counted in over2Ms as well.
1452
+ * @example 1198
1453
+ */
1454
+ over20Ms: number;
1455
+ /**
1456
+ * Returns later than 100 ms. Counted in the two above as well.
1457
+ * @example 1195
1458
+ */
1459
+ over100Ms: number;
1460
+ /**
1461
+ * The latest return, in microseconds after its first send
1462
+ * @format int64
1463
+ * @example 221748
1464
+ */
1465
+ latestUs: number;
1466
+ }
1467
+ /** How late the frames of a capture came back. See `POST /api/captures`. */
1468
+ export interface CaptureSummary {
1469
+ /**
1470
+ * Every record in the capture
1471
+ * @example 120050
1472
+ */
1473
+ frames: number;
1474
+ /**
1475
+ * Records that are not an EtherCAT command frame
1476
+ * @example 0
1477
+ */
1478
+ notEtherCat: number;
1479
+ /**
1480
+ * Frames from the slaves with no send to match, such as the second answer to a frame sent twice
1481
+ * @example 8
1482
+ */
1483
+ unmatchedReturns: number;
1484
+ /**
1485
+ * Timestamp of the first record, epoch microseconds
1486
+ * @format int64
1487
+ * @example 1761143405000123
1488
+ */
1489
+ firstUs: number;
1490
+ /**
1491
+ * Timestamp of the last record, epoch microseconds
1492
+ * @format int64
1493
+ * @example 1761143435000456
1494
+ */
1495
+ lastUs: number;
1496
+ /** The counts for one kind of frame. The bands are cumulative. */
1497
+ control: CaptureKindSummary;
1498
+ /** The counts for one kind of frame. The bands are cumulative. */
1499
+ cyclic: CaptureKindSummary;
1500
+ }
1501
+ export interface AlStatusCode {
1502
+ /**
1503
+ * AL Status Code value (ETG.1000.6 §6.4.1)
1504
+ * @example 20
1505
+ */
1506
+ code: number;
1507
+ /**
1508
+ * Short human-readable name
1509
+ * @example "No valid firmware"
1510
+ */
1511
+ name: string;
1512
+ /**
1513
+ * Full description of the error condition
1514
+ * @example "No valid firmware is present — the slave needs firmware flashed"
1515
+ */
1516
+ description: string;
1517
+ /**
1518
+ * True if a slave reporting this code cannot reach the requested EtherCAT state by retrying. The server abandons the slave immediately during a state transition instead of waiting for timeout; the master must change something (re-init, reflash, power cycle) before another transition attempt can succeed.
1519
+ * @example true
1520
+ */
1521
+ terminal: boolean;
1522
+ }
1523
+ export interface EscRegister {
1524
+ /**
1525
+ * Register address in the ESC address space (decimal)
1526
+ * @example 272
1527
+ */
1528
+ address: number;
1529
+ /**
1530
+ * Register width in bytes (1, 2, 4, or 8)
1531
+ * @example 2
1532
+ */
1533
+ length: number;
1534
+ /**
1535
+ * Short snake_case identifier
1536
+ * @example "dl_status"
1537
+ */
1538
+ name: string;
1539
+ /**
1540
+ * Human-readable description from the Beckhoff ESC datasheet
1541
+ * @example "DL status: EEPROM load ok, link detected, communication established per port"
1542
+ */
1543
+ description: string;
1544
+ }
1545
+ export interface FoeErrorCode {
1546
+ /**
1547
+ * 32-bit FoE error code as sent in the FoE ERROR packet (ETG.1000.6 §5.5)
1548
+ * @example 32770
1549
+ */
1550
+ code: number;
1551
+ /**
1552
+ * Short human-readable name
1553
+ * @example "File not found"
1554
+ */
1555
+ name: string;
1556
+ /**
1557
+ * Full description of the error condition
1558
+ * @example "The requested file does not exist on the slave"
1559
+ */
1560
+ description: string;
1561
+ }
1562
+ export interface SdoAbortCode {
1563
+ /**
1564
+ * 32-bit CoE SDO abort code (ETG.1000.6 §5.6.2.7.2, Table 41)
1565
+ * @example 100794368
1566
+ */
1567
+ code: number;
1568
+ /**
1569
+ * Human-readable meaning of the abort
1570
+ * @example "The object does not exist in the object dictionary"
1571
+ */
1572
+ description: string;
1573
+ }
1574
+ export interface MailboxErrorCode {
1575
+ /**
1576
+ * 16-bit mailbox error Detail code (ETG.1000.4, Table 30)
1577
+ * @example 1
1578
+ */
1579
+ code: number;
1580
+ /**
1581
+ * Symbolic name
1582
+ * @example "MBXERR_SYNTAX"
1583
+ */
1584
+ name: string;
1585
+ /**
1586
+ * Human-readable meaning of the error
1587
+ * @example "Syntax of the 6-octet mailbox header is wrong"
1588
+ */
1589
+ description: string;
1590
+ }
1591
+ export interface ObjectDataTypeInfo {
1592
+ /**
1593
+ * ETG.1020 data type code
1594
+ * @example 7
1595
+ */
1596
+ code: number;
1597
+ /**
1598
+ * Symbolic name of the data type
1599
+ * @example "UNSIGNED32"
1600
+ */
1601
+ name: string;
1602
+ /**
1603
+ * Declared bit width of one element; 0 for variable-length types
1604
+ * @example 32
1605
+ */
1606
+ bitSize: number;
1607
+ }
1608
+ /**
1609
+ * The value of one object dictionary entry, encoded by its `dataType` (ETG.1020). BOOLEAN (0x0001), INTEGER8 (0x0002), INTEGER16 (0x0003), INTEGER32 (0x0004), INTEGER64 (0x0015), UNSIGNED8 (0x0005), UNSIGNED16 (0x0006), UNSIGNED32 (0x0007), BYTE (0x001E), WORD (0x001F) and DWORD (0x0020) are a JSON integer that fits `int64`. UNSIGNED64 (0x001B) is a JSON integer that fits `uint64`, and a value above 9223372036854775807 matches only that alternative. REAL32 (0x0008) and REAL64 (0x0011) are a JSON number, which the server writes as a double, so a REAL32 shows its exact binary value. VISIBLE STRING (0x0009) and UNICODE STRING (0x000B) are a string. Every other data type, OCTET STRING and DOMAIN included, is an array of byte values. Every integer is also a valid number, so use `dataType` to choose the alternative, the way the server does. On a write, the server converts the value to the declared type of the parameter.
1610
+ * @example 12345
1611
+ */
1612
+ export type ParameterValue = number | string | number[];
1613
+ export interface DeviceParameter {
1614
+ /**
1615
+ * CoE object index
1616
+ * @example 24640
1617
+ */
1618
+ index: number;
1619
+ /**
1620
+ * CoE object subindex
1621
+ * @example 0
1622
+ */
1623
+ subindex: number;
1624
+ /**
1625
+ * Textual description from the slave's SDO Info "Get Entry Description"
1626
+ * @example "Position actual value"
1627
+ */
1628
+ name: string;
1629
+ /**
1630
+ * ETG.1000.6 §5 object code (VAR=7, ARRAY=8, RECORD=9)
1631
+ * @example 7
1632
+ */
1633
+ objectCode: number;
1634
+ /**
1635
+ * ETG.1020 data type code (e.g. 7 = UNSIGNED32)
1636
+ * @example 4
1637
+ */
1638
+ dataType: number;
1639
+ /**
1640
+ * Symbolic name of the data type (resolved server-side from `dataType`)
1641
+ * @example "INTEGER32"
1642
+ */
1643
+ dataTypeName: string;
1644
+ /**
1645
+ * Bit length of the entry's value
1646
+ * @example 32
1647
+ */
1648
+ bitLength: number;
1649
+ /**
1650
+ * ObjAccess bitfield (read/write per AL state)
1651
+ * @example 7
1652
+ */
1653
+ access: number;
1654
+ /**
1655
+ * Where this parameter's definition came from. `objectDictionary` — enumerated over the CoE object dictionary (SDO-Info). `sii` — derived from the SII EEPROM PDO categories, for a mailbox-less slave (an EtherCAT coupler / simple I/O terminal) that has no CoE object dictionary; such a parameter has no live SDO access, so its value comes only from the process image.
1656
+ * @example "objectDictionary"
1657
+ */
1658
+ origin: "objectDictionary" | "sii";
1659
+ /**
1660
+ * Last-known value, decoded according to `dataType`. Initialised to a type-appropriate zero (0 for numbers, "" for strings, [] for raw bytes) before the first read. After a successful SDO upload, holds the decoded value. `ParameterValue` says which JSON type each `dataType` uses.
1661
+ * @example 12345
1662
+ */
1663
+ value: ParameterValue;
1664
+ /**
1665
+ * ETG.1004 unit code reported by the slave for this entry. Absent when the slave does not populate the Unit field of the SDO Info response. The 32-bit code decomposes into prefix, base SI unit, and exponent per ETG.1004.
1666
+ * @example 0
1667
+ */
1668
+ unit?: number;
1669
+ /** Slave-reported default value, decoded with the same logic as `value`. Absent when the slave does not report a default. */
1670
+ defaultValue?: ParameterValue;
1671
+ /** Slave-reported minimum value, decoded with the same logic as `value`. Absent when the slave does not report a minimum. */
1672
+ minValue?: ParameterValue;
1673
+ /** Slave-reported maximum value, decoded with the same logic as `value`. Absent when the slave does not report a maximum. */
1674
+ maxValue?: ParameterValue;
1675
+ /**
1676
+ * Freshness of `value` relative to the device. `synced` — matches the device (last successful read or write); `pending` — set locally while offline or after a failed write, not yet confirmed on the device; `stale` — came from an earlier read or write, and the latest read of the object failed; `unknown` — never read, `value` is the type-appropriate default. A failed read turns `synced` into `stale` and keeps the value. It leaves `unknown` and `pending` unchanged. The next successful read sets `synced` again.
1677
+ * @example "synced"
1678
+ */
1679
+ syncState: "unknown" | "synced" | "pending" | "stale";
1680
+ }
1681
+ /** Parsed SII (EEPROM) image of a slave — the fixed header plus the decoded category section. String-index fields are 1-based references into `category.strings`. */
1682
+ export interface SlaveInformationInterface {
1683
+ /** Fixed 128-byte header (identity and mailbox configuration) */
1684
+ info: {
1685
+ pdiControl?: number;
1686
+ pdiConfiguration?: number;
1687
+ syncImpulseLen?: number;
1688
+ pdiConfiguration2?: number;
1689
+ configuredStationAlias?: number;
1690
+ checksum?: number;
1691
+ /** @example 8914 */
1692
+ vendorId?: number;
1693
+ /** @example 769 */
1694
+ productCode?: number;
1695
+ revisionNumber?: number;
1696
+ serialNumber?: number;
1697
+ bootstrapReceiveMailboxOffset?: number;
1698
+ bootstrapReceiveMailboxSize?: number;
1699
+ bootstrapSendMailboxOffset?: number;
1700
+ bootstrapSendMailboxSize?: number;
1701
+ standardReceiveMailboxOffset?: number;
1702
+ standardReceiveMailboxSize?: number;
1703
+ standardSendMailboxOffset?: number;
1704
+ standardSendMailboxSize?: number;
1705
+ /**
1706
+ * Bitfield: 0x01 AoE, 0x02 EoE, 0x04 CoE, 0x08 FoE, 0x10 SoE, 0x20 VoE
1707
+ * @example 12
1708
+ */
1709
+ mailboxProtocol?: number;
1710
+ /** Raw EEPROM-size word (ETG: size in KiBit − 1) */
1711
+ size?: number;
1712
+ version?: number;
1713
+ };
1714
+ /** Decoded SII category section */
1715
+ category: {
1716
+ /**
1717
+ * STRINGS table (category 10), referenced by 1-based index
1718
+ * @example ["SOMANET","SOMANET Circulo CiA402 Drive"]
1719
+ */
1720
+ strings?: string[];
1721
+ /** GENERAL device information (category 30) */
1722
+ general?: {
1723
+ groupIdx?: number;
1724
+ imgIdx?: number;
1725
+ orderIdx?: number;
1726
+ nameIdx?: number;
1727
+ coeDetails?: number;
1728
+ foeDetails?: number;
1729
+ eoeDetails?: number;
1730
+ soeChannels?: number;
1731
+ ds402Channels?: number;
1732
+ sysmanClass?: number;
1733
+ flags?: number;
1734
+ currentOnEBus?: number;
1735
+ physicalPort?: number;
1736
+ physicalMemoryAddress?: number;
1737
+ };
1738
+ /** FMMU defaults (category 40), one raw 16-bit word per entry */
1739
+ fmmus?: number[];
1740
+ /** Sync-Manager defaults (category 41) */
1741
+ syncManagers?: {
1742
+ physicalStartAddress?: number;
1743
+ length?: number;
1744
+ controlRegister?: number;
1745
+ statusRegister?: number;
1746
+ enableSyncManager?: number;
1747
+ /** 1 MbxOut, 2 MbxIn, 3 Outputs, 4 Inputs */
1748
+ syncManagerType?: number;
1749
+ }[];
1750
+ /** Default RxPDOs (category 51) */
1751
+ rxPdos?: SiiPdo[];
1752
+ /** Default TxPDOs (category 50) */
1753
+ txPdos?: SiiPdo[];
1754
+ /** Distributed-clock settings (category 60) */
1755
+ distributedClocks?: {
1756
+ cycleTime0?: number;
1757
+ shiftTime0?: number;
1758
+ shiftTime1?: number;
1759
+ sync1CycleFactor?: number;
1760
+ assignActivate?: number;
1761
+ sync0CycleFactor?: number;
1762
+ nameIdx?: number;
1763
+ descIdx?: number;
1764
+ }[];
1765
+ };
1766
+ }
1767
+ /** One default PDO from the SII (RxPDO category 51 or TxPDO category 50) */
1768
+ export interface SiiPdo {
1769
+ pdoIndex?: number;
1770
+ /** Declared entry count (may exceed `entries.length` if the payload was truncated) */
1771
+ nEntry?: number;
1772
+ syncM?: number;
1773
+ synchronization?: number;
1774
+ nameIdx?: number;
1775
+ flags?: number;
1776
+ entries?: {
1777
+ entryIndex?: number;
1778
+ subindex?: number;
1779
+ entryNameIdx?: number;
1780
+ dataType?: number;
1781
+ bitLen?: number;
1782
+ flags?: number;
1783
+ }[];
1784
+ }
1785
+ /** One addressable `(index, subindex)` of a device's object dictionary, assembled from the ESI. `defaultData`/`minData`/`maxData` are **raw little-endian bytes** as uppercase hexBinary, the same spelling the ESI itself uses — the first byte is the least significant, so `92010200` is `0x00020192`. Decode them with `dataType`; a byte-wise comparison of `minData` against `maxData` is wrong when `isSigned`. */
1786
+ export interface EsiEntry {
1787
+ /** Effective CoE index */
1788
+ index: number;
1789
+ subindex: number;
1790
+ /** Index as written in the source dictionary; omitted when unrelocated */
1791
+ rawIndex?: number;
1792
+ /** The parent object's name — identical across all its subindices */
1793
+ objectName: string;
1794
+ /** This subindex's own name */
1795
+ entryName: string;
1796
+ /** The ESI's display-name override, else `entryName` */
1797
+ displayName: string;
1798
+ objectCode: "VAR" | "ARRAY" | "RECORD";
1799
+ /** The CoE object code (ETG.1000.6 §5) — 7, 8 or 9 */
1800
+ objectCodeValue?: number;
1801
+ /** Highest subindex; omitted for a VAR */
1802
+ numberOfEntries?: number;
1803
+ /**
1804
+ * ESI/IEC 61131-3 type name, e.g. `UDINT`, `STRING(50)`
1805
+ * @example "UDINT"
1806
+ */
1807
+ dataTypeName: string;
1808
+ /**
1809
+ * ETG.1020 code, matching `DeviceParameter.dataType`; 0 if unresolved
1810
+ * @example 7
1811
+ */
1812
+ dataType: number;
1813
+ /**
1814
+ * The C++ type this entry's value maps to, resolved from `dataType` **and** `bitSize`. The width is not decoration: a vendor's `ARRAY [0..24] OF BYTE` resolves to the ETG.1020 code for BYTE, so trusting the code alone would call a 25-byte object a `uint8_t` and every read of it would return its first byte. Where the declared width contradicts the code, this is `std::vector<uint8_t>`.
1815
+ * @example "int32_t"
1816
+ */
1817
+ cxxType: string;
1818
+ isSigned: boolean;
1819
+ bitSize: number;
1820
+ /** Offset within the object's complete-access image */
1821
+ bitOffset: number;
1822
+ /** Uppercase hexBinary */
1823
+ defaultData?: string;
1824
+ minData?: string;
1825
+ maxData?: string;
1826
+ /** Packed ETG.1004 notation value */
1827
+ unit?: number;
1828
+ /** @example "mV" */
1829
+ unitSymbol?: string;
1830
+ access: {
1831
+ mode: "ro" | "rw" | "wo";
1832
+ readRestrictions?: "PreOP" | "PreOP_SafeOP" | "PreOP_OP" | "SafeOP" | "SafeOP_OP" | "OP";
1833
+ writeRestrictions?: "PreOP" | "PreOP_SafeOP" | "PreOP_OP" | "SafeOP" | "SafeOP_OP" | "OP";
1834
+ };
1835
+ /** Mandatory, optional or conditional */
1836
+ category: "m" | "o" | "c";
1837
+ /** Empty when not mappable; `t` TxPDO, `r` RxPDO */
1838
+ pdoMapping: "" | "t" | "r" | "tr";
1839
+ safetyMapping?: "si" | "so" | "sio" | "sp";
1840
+ sdoAccess: "SubIndexAccess" | "CompleteAccess";
1841
+ backup: boolean;
1842
+ setting: boolean;
1843
+ /** SoE IDN */
1844
+ attribute?: number;
1845
+ /** ETG.1000.6 ObjAccess bitfield synthesised from the flags — bits 0-2 read in PreOP/SafeOP/OP, 3-5 write, 6 RxPDO-mappable, 7 TxPDO-mappable, 8 backup, 9 setting. Matches `DeviceParameter.access`. */
1846
+ objAccess: number;
1847
+ /** This row's description (HTML), decoded from `properties`. On subindex 0 it is the object's; on a RECORD member it is that member's; an ARRAY element has none. */
1848
+ description?: string;
1849
+ /** Enum labels, from `<EnumInfo>` and/or an `options` property */
1850
+ options?: {
1851
+ label: string;
1852
+ value: number;
1853
+ }[];
1854
+ /** Raw `<Property>` annotations as written, for whatever this row describes. This is the ESI's generic extension mechanism; `description` and `options` above are conveniences decoded from the two conventional names, so a vendor using other names still has its data here. **Subindex 0 carries the object's own annotation** (stored once, not repeated onto every subindex); other rows carry only what that entry itself declares. */
1855
+ properties?: EsiProperties;
1856
+ /** Which dictionary this entry came from. The module's *name* is not repeated here — resolve `moduleIdent` against the top-level `modules` list. */
1857
+ source: {
1858
+ kind: "device" | "module";
1859
+ moduleIdent?: number;
1860
+ /** Zero-based slot number */
1861
+ slot?: number;
1862
+ /** Slot offset applied to `rawIndex` */
1863
+ indexOffset?: number;
1864
+ };
1865
+ }
1866
+ /** Raw `<Property>` annotations as written, for whatever this row describes. This is the ESI's generic extension mechanism; `description` and `options` above are conveniences decoded from the two conventional names, so a vendor using other names still has its data here. **Subindex 0 carries the object's own annotation** (stored once, not repeated onto every subindex); other rows carry only what that entry itself declares. */
1867
+ export type EsiProperties = {
1868
+ name: string;
1869
+ value: string;
1870
+ }[];
1871
+ export interface EsiDeviceSummary {
1872
+ /** Zero-based position in the file */
1873
+ ordinal: number;
1874
+ /** @example "SOMANET Node" */
1875
+ type: string;
1876
+ name: string;
1877
+ productCode?: number;
1878
+ revisionNo?: number;
1879
+ /** @example 402 */
1880
+ profileNo?: number;
1881
+ groupType: string;
1882
+ /** Objects in the device's own dictionary, before any module merge */
1883
+ objectCount: number;
1884
+ rxPdoCount?: number;
1885
+ txPdoCount?: number;
1886
+ /** Every `ModuleIdent` the device's slots reference, in slot order */
1887
+ moduleIdents: number[];
1888
+ /** The parsed `<Slots>` block */
1889
+ slots?: object;
1890
+ /** This device's flat, slot-merged object dictionary */
1891
+ entries?: EsiEntry[];
1892
+ /** Problems found while assembling *this device* — a value whose byte length disagrees with its declared width, an unresolvable type, a module collision. Distinct from the top-level `warnings`, which are about the document; a different `modules` selection would produce a different list here. */
1893
+ warnings?: string[];
1894
+ }
1895
+ /** A parsed ESI. Every device carries its own assembled `entries` table. */
1896
+ export interface EsiParseResult {
1897
+ /** The `EtherCATInfo/@Version` attribute */
1898
+ version?: string;
1899
+ vendor: {
1900
+ /** @example 8914 */
1901
+ id: number;
1902
+ name: string;
1903
+ url?: string;
1904
+ };
1905
+ devices: EsiDeviceSummary[];
1906
+ modules: {
1907
+ moduleIdent: number;
1908
+ /** @example "CiA402 Dictionary" */
1909
+ type: string;
1910
+ name: string;
1911
+ objectCount?: number;
1912
+ }[];
1913
+ /** Recoverable problems in the document itself — a skipped malformed object, an unparsable value. A file with warnings still parses. Per-device assembly problems are reported on the device instead. */
1914
+ warnings?: string[];
1915
+ }
1916
+ /** What Motion Master knows about the auto-tuning process, as a startup snapshot. */
1917
+ export interface AutoTuningStatus {
1918
+ /**
1919
+ * The `autoTuning.enabled` setting from the configuration file.
1920
+ * @example true
1921
+ */
1922
+ enabled: boolean;
1923
+ /**
1924
+ * The executable Motion Master looked for, as an absolute path.
1925
+ * @example "/opt/motion-master/auto-tuning"
1926
+ */
1927
+ binaryPath: string;
1928
+ /**
1929
+ * Whether a file exists at that path.
1930
+ * @example true
1931
+ */
1932
+ installed: boolean;
1933
+ /**
1934
+ * Whether the process started and answered its health endpoint. Not a liveness check: nothing polls the process after startup.
1935
+ * @example true
1936
+ */
1937
+ started: boolean;
1938
+ /**
1939
+ * The version the process reported, empty unless it started. A build older than that program's version reporting starts and reports nothing, which is why an empty string here does not mean it failed.
1940
+ * @example "3.1.1"
1941
+ */
1942
+ version: string;
1943
+ /**
1944
+ * The loopback port the process was told to serve on.
1945
+ * @example 63528
1946
+ */
1947
+ port: number;
1948
+ /**
1949
+ * Why it is not running. Empty when it is.
1950
+ * @example ""
1951
+ */
1952
+ error: string;
1953
+ }
1954
+ /** The auto-tuning program's error shape. Returned with 200 when a function rejected its inputs, and with 404 or 500 for an unknown function or an unhandled exception. */
1955
+ export interface AutoTuningError {
1956
+ error: {
1957
+ /** @example "A linear model can't be fit in the recorded data." */
1958
+ message: string;
1959
+ };
1960
+ }
1961
+ /**
1962
+ * Transfer function coefficients, highest order first.
1963
+ * @example {"numerator":[1],"denominator":[0.00015,0.000206]}
1964
+ */
1965
+ export interface PlantModel {
1966
+ numerator: number[];
1967
+ denominator: number[];
1968
+ }
1969
+ /** One controller's gains. */
1970
+ export interface Pid {
1971
+ /** @format double */
1972
+ kp?: number;
1973
+ /** @format double */
1974
+ ki?: number;
1975
+ /** @format double */
1976
+ kd?: number;
1977
+ }
1978
+ /** Controller gains. A function that tunes only the velocity loop leaves the position gains at zero. */
1979
+ export interface Gains {
1980
+ /** One controller's gains. */
1981
+ position?: Pid;
1982
+ /** One controller's gains. */
1983
+ velocity?: Pid;
1984
+ }
1985
+ /**
1986
+ * Bode diagram data, keyed by column name, every array the same length. This comes back in the response body instead of a written CSV, which is why no auto-tuning call needs a shared filesystem. A non-finite value is null.
1987
+ * @example {"Frequency_Hz":[0.5,1],"Plant_Mag_dB":[65.77570877159437,59.79191013147556],"Plant_Phase_deg":[-66.38766900151838,-76.55997369096534]}
1988
+ */
1989
+ export type Bode = Record<string, (number | null)[]>;
1990
+ /** Drive configuration, as read from the drive. */
1991
+ export interface DriveConfig {
1992
+ vel_lp_type?: number;
1993
+ /** @format double */
1994
+ vel_lp_fc?: number;
1995
+ pos_lp_type?: number;
1996
+ /** @format double */
1997
+ pos_lp_fc?: number;
1998
+ notch_en?: number;
1999
+ /** @format double */
2000
+ notch_fw?: number;
2001
+ /** @format double */
2002
+ notch_fc?: number;
2003
+ /** @format double */
2004
+ notch_dp?: number;
2005
+ /** @format double */
2006
+ vel_ff_gain?: number;
2007
+ /** @format double */
2008
+ vel_ff_fc?: number;
2009
+ /**
2010
+ * Winding inductance.
2011
+ * @format double
2012
+ */
2013
+ L?: number;
2014
+ /**
2015
+ * Winding resistance.
2016
+ * @format double
2017
+ */
2018
+ R?: number;
2019
+ /**
2020
+ * DC link voltage.
2021
+ * @format double
2022
+ */
2023
+ vdc?: number;
2024
+ /** @format double */
2025
+ current_ratio?: number;
2026
+ /** @format double */
2027
+ tc_kp?: number;
2028
+ /** @format double */
2029
+ tc_ki?: number;
2030
+ switch_F?: number;
2031
+ /** @format double */
2032
+ tc_st?: number;
2033
+ /** @format double */
2034
+ tc_damping?: number;
2035
+ software_version?: string;
2036
+ /** @format double */
2037
+ rated_torque?: number;
2038
+ /** @format double */
2039
+ max_vel_noise?: number;
2040
+ }
2041
+ /** The `data` schema depends on the value of `run`. Each variant pairs one `run` value with the inputs that function reads. `run: exit` is deliberately absent: it shuts the process down, and this endpoint refuses it with 400. */
2042
+ export type AutoTuningRunRequest = AutoTuneVelocityController | AutoTunePositionController | FullAutoTuneVelocityController | FullAutoTunePositionController | AutoTuneNotch | AutoTuneFeedbackFilters | ComputePositionControllerGains | IdentifyPlantModel | GeneratePlantBode;
2043
+ export interface AutoTuneVelocityController {
2044
+ run: "auto_tune_velocity_controller";
2045
+ data: {
2046
+ /** Transfer function coefficients, highest order first. */
2047
+ plant_model: PlantModel;
2048
+ /**
2049
+ * Damping ratio.
2050
+ * @format double
2051
+ */
2052
+ zeta: number;
2053
+ /**
2054
+ * Demanded bandwidth in Hz.
2055
+ * @format double
2056
+ */
2057
+ demanded_bw: number;
2058
+ };
2059
+ }
2060
+ export interface AutoTunePositionController {
2061
+ run: "auto_tune_position_controller";
2062
+ data: {
2063
+ /** Transfer function coefficients, highest order first. */
2064
+ plant_model: PlantModel;
2065
+ /** @example "PI-P" */
2066
+ controller_type: string;
2067
+ /** @format double */
2068
+ zeta: number;
2069
+ /**
2070
+ * Demanded settling time in seconds.
2071
+ * @format double
2072
+ */
2073
+ demanded_st: number;
2074
+ /**
2075
+ * Optional. Absent means the standard tuning rule.
2076
+ * @format double
2077
+ */
2078
+ highFrictionGain?: number;
2079
+ };
2080
+ }
2081
+ export interface FullAutoTuneVelocityController {
2082
+ run: "full_auto_tune_velocity_controller";
2083
+ data: {
2084
+ /** Transfer function coefficients, highest order first. */
2085
+ plant_model: PlantModel;
2086
+ /** Drive configuration, as read from the drive. */
2087
+ drive_config: DriveConfig;
2088
+ };
2089
+ }
2090
+ export interface FullAutoTunePositionController {
2091
+ run: "full_auto_tune_position_controller";
2092
+ data: {
2093
+ /** Transfer function coefficients, highest order first. */
2094
+ plant_model: PlantModel;
2095
+ /** @example "PI-P" */
2096
+ controller_type: string;
2097
+ /** Drive configuration, as read from the drive. */
2098
+ drive_config: DriveConfig;
2099
+ highFriction: 0 | 1;
2100
+ };
2101
+ }
2102
+ export interface AutoTuneNotch {
2103
+ run: "auto_tune_notch";
2104
+ data: {
2105
+ /** Transfer function coefficients, highest order first. */
2106
+ plant_model: PlantModel;
2107
+ };
2108
+ }
2109
+ export interface AutoTuneFeedbackFilters {
2110
+ run: "auto_tune_feedback_filters";
2111
+ data: {
2112
+ /** @format double */
2113
+ sigma_v: number;
2114
+ /** @format double */
2115
+ sigma_p: number;
2116
+ /** @format double */
2117
+ resVel: number;
2118
+ /** @format double */
2119
+ resPos: number;
2120
+ /** @format double */
2121
+ gearRatio: number;
2122
+ };
2123
+ }
2124
+ export interface ComputePositionControllerGains {
2125
+ run: "compute_position_controller_gains";
2126
+ data: {
2127
+ /** @format double */
2128
+ pk: number;
2129
+ /** @format double */
2130
+ pt: number;
2131
+ /** @format double */
2132
+ omega: number;
2133
+ /** @format double */
2134
+ alpha: number;
2135
+ /** @format double */
2136
+ zeta: number;
2137
+ /** @example "PI-P" */
2138
+ controller_type: string;
2139
+ };
2140
+ }
2141
+ /** Identifies a plant model from chirp measurements. The measurements are uploaded in `data.csv`; `data.filepath` names a file on the auto-tuning process's own machine instead, and is a fallback that Motion Master has no use for. */
2142
+ export interface IdentifyPlantModel {
2143
+ run: "identify_plant_model" | "identify_plant_model_inline";
2144
+ data: {
2145
+ /** Contents of the measurement CSV. Three columns, no header: time, torque in Nm, velocity in rad/s, sampled at 1000 Hz. */
2146
+ csv?: string;
2147
+ /** Path to that CSV instead of its contents. */
2148
+ filepath?: string;
2149
+ /**
2150
+ * Chirp start frequency in Hz.
2151
+ * @format double
2152
+ */
2153
+ f0: number;
2154
+ /**
2155
+ * Chirp end frequency in Hz.
2156
+ * @format double
2157
+ */
2158
+ f1: number;
2159
+ };
2160
+ }
2161
+ /** Computes the bode data of a plant model and returns it inline. */
2162
+ export interface GeneratePlantBode {
2163
+ run: "generate_plant_bode_file" | "generate_plant_bode";
2164
+ data: {
2165
+ /** Transfer function coefficients, highest order first. */
2166
+ plant_model: PlantModel;
2167
+ };
2168
+ }
2169
+ /** Which variant comes back depends on the request's `run`. Every result carries `duration`, the function's execution time in seconds. A function that rejected its inputs answers with `AutoTuningError` and status 200. */
2170
+ export type AutoTuningRunResponse = GainsResult | FullVelocityResult | FullPositionResult | NotchResult | FeedbackFiltersResult | IdentifyPlantModelResult | BodeResult | AutoTuningError;
2171
+ export interface GainsResult {
2172
+ /** Controller gains. A function that tunes only the velocity loop leaves the position gains at zero. */
2173
+ gains?: Gains;
2174
+ /** @format double */
2175
+ duration?: number;
2176
+ }
2177
+ export interface FullVelocityResult {
2178
+ /** Controller gains. A function that tunes only the velocity loop leaves the position gains at zero. */
2179
+ gains?: Gains;
2180
+ /** @format double */
2181
+ demanded_bw?: number;
2182
+ /** @format double */
2183
+ demanded_zeta?: number;
2184
+ /** Stability margins and closed-loop metrics. */
2185
+ state?: {
2186
+ /** @format double */
2187
+ gm?: number;
2188
+ /** @format double */
2189
+ pm?: number;
2190
+ /** @format double */
2191
+ msens?: number;
2192
+ /** @format double */
2193
+ act_bw?: number;
2194
+ /** @format double */
2195
+ vel_cl?: number;
2196
+ /** @format double */
2197
+ noise_resp?: number;
2198
+ /** @format double */
2199
+ max_KS?: number;
2200
+ };
2201
+ /** @format double */
2202
+ duration?: number;
2203
+ }
2204
+ export interface FullPositionResult {
2205
+ /** Controller gains. A function that tunes only the velocity loop leaves the position gains at zero. */
2206
+ gains?: Gains;
2207
+ /** @format double */
2208
+ demanded_st?: number;
2209
+ /** @format double */
2210
+ demanded_zeta?: number;
2211
+ /** @format double */
2212
+ highFrictionGain?: number;
2213
+ /** Stability margins and closed-loop metrics, position and velocity loop. */
2214
+ state?: {
2215
+ /** @format double */
2216
+ gm_p?: number;
2217
+ /** @format double */
2218
+ pm_p?: number;
2219
+ /** @format double */
2220
+ msens_p?: number;
2221
+ /** @format double */
2222
+ gm_v?: number;
2223
+ /** @format double */
2224
+ pm_v?: number;
2225
+ /** @format double */
2226
+ msens_v?: number;
2227
+ /** @format double */
2228
+ noise_resp?: number;
2229
+ /** @format double */
2230
+ max_KS?: number;
2231
+ /** @format double */
2232
+ bw_p?: number;
2233
+ /** @format double */
2234
+ bw_v?: number;
2235
+ /** @format double */
2236
+ act_st?: number;
2237
+ /** @format double */
2238
+ pos_cl?: number;
2239
+ };
2240
+ /** @format double */
2241
+ duration?: number;
2242
+ }
2243
+ export interface NotchResult {
2244
+ notch_en?: boolean;
2245
+ /** @format double */
2246
+ notch_fc?: number | null;
2247
+ /** @format double */
2248
+ notch_fw?: number | null;
2249
+ /** @format double */
2250
+ notch_dp?: number | null;
2251
+ /** @format double */
2252
+ duration?: number;
2253
+ }
2254
+ export interface FeedbackFiltersResult {
2255
+ /**
2256
+ * Velocity feedback filter cut-off in Hz.
2257
+ * @format double
2258
+ */
2259
+ fcv?: number;
2260
+ /**
2261
+ * Position feedback filter cut-off in Hz.
2262
+ * @format double
2263
+ */
2264
+ fcp?: number;
2265
+ /** @format double */
2266
+ duration?: number;
2267
+ }
2268
+ export interface IdentifyPlantModelResult {
2269
+ numerators?: number[];
2270
+ denominators?: number[];
2271
+ /** Bode diagram data, keyed by column name, every array the same length. This comes back in the response body instead of a written CSV, which is why no auto-tuning call needs a shared filesystem. A non-finite value is null. */
2272
+ bode?: Bode;
2273
+ /** @format double */
2274
+ duration?: number;
2275
+ }
2276
+ export interface BodeResult {
2277
+ /** Bode diagram data, keyed by column name, every array the same length. This comes back in the response body instead of a written CSV, which is why no auto-tuning call needs a shared filesystem. A non-finite value is null. */
2278
+ bode?: Bode;
2279
+ /** @format double */
2280
+ duration?: number;
2281
+ }
2282
+ export {};