abb-rws-client 0.7.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +137 -0
- package/README.md +17 -8
- package/dist/HalJsonParser.d.ts +55 -0
- package/dist/HalJsonParser.d.ts.map +1 -0
- package/dist/HalJsonParser.js +155 -0
- package/dist/HalJsonParser.js.map +1 -0
- package/dist/HttpSession.d.ts.map +1 -1
- package/dist/HttpSession.js +13 -2
- package/dist/HttpSession.js.map +1 -1
- package/dist/IRWSAdapter.d.ts +7 -1
- package/dist/IRWSAdapter.d.ts.map +1 -1
- package/dist/MdnsDiscovery.d.ts +57 -0
- package/dist/MdnsDiscovery.d.ts.map +1 -0
- package/dist/MdnsDiscovery.js +313 -0
- package/dist/MdnsDiscovery.js.map +1 -0
- package/dist/MultiRobotManager.d.ts +5 -2
- package/dist/MultiRobotManager.d.ts.map +1 -1
- package/dist/MultiRobotManager.js +8 -3
- package/dist/MultiRobotManager.js.map +1 -1
- package/dist/RWS1Adapter.d.ts +60 -2
- package/dist/RWS1Adapter.d.ts.map +1 -1
- package/dist/RWS1Adapter.js +152 -4
- package/dist/RWS1Adapter.js.map +1 -1
- package/dist/ResourceMapper.d.ts +4 -0
- package/dist/ResourceMapper.d.ts.map +1 -1
- package/dist/ResourceMapper.js +9 -1
- package/dist/ResourceMapper.js.map +1 -1
- package/dist/RobotManager.d.ts +72 -12
- package/dist/RobotManager.d.ts.map +1 -1
- package/dist/RobotManager.js +255 -50
- package/dist/RobotManager.js.map +1 -1
- package/dist/RwsClient2.d.ts +150 -10
- package/dist/RwsClient2.d.ts.map +1 -1
- package/dist/RwsClient2.js +599 -236
- package/dist/RwsClient2.js.map +1 -1
- package/dist/WsSubscriber.d.ts +31 -5
- package/dist/WsSubscriber.d.ts.map +1 -1
- package/dist/WsSubscriber.js +104 -50
- package/dist/WsSubscriber.js.map +1 -1
- package/dist/detect.d.ts +12 -3
- package/dist/detect.d.ts.map +1 -1
- package/dist/detect.js +69 -25
- package/dist/detect.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/types.js +3 -3
- package/dist/types.js.map +1 -1
- package/examples/05-remote-control-rmmp.mjs +10 -12
- package/examples/06-pull-module-source.mjs +13 -20
- package/package.json +62 -60
- package/src/HalJsonParser.ts +137 -0
- package/src/HttpSession.ts +460 -0
- package/src/IRWSAdapter.ts +422 -0
- package/src/Logger.ts +54 -0
- package/src/MdnsDiscovery.ts +336 -0
- package/src/MultiRobotManager.ts +159 -0
- package/src/RWS1Adapter.ts +1018 -0
- package/src/RWS2Adapter.ts +19 -0
- package/src/ResourceMapper.ts +517 -0
- package/src/ResponseParser.ts +710 -0
- package/src/RobotManager.ts +1705 -0
- package/src/RwsClient.ts +1150 -0
- package/src/RwsClient2.ts +2214 -0
- package/src/WsSubscriber.ts +350 -0
- package/src/XhtmlParser.ts +53 -0
- package/src/detect.ts +261 -0
- package/src/index.ts +83 -0
- package/src/types.ts +336 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { RwsClient2 } from './RwsClient2.js';
|
|
2
|
+
import type { IRWSAdapter } from './IRWSAdapter.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* RWS 2.0 adapter that satisfies the `IRWSAdapter` unified interface.
|
|
6
|
+
*
|
|
7
|
+
* Thin wrapper over `RwsClient2` — the protocol-level client. They expose the
|
|
8
|
+
* same public surface (the protocol method set IS the IRWSAdapter contract for
|
|
9
|
+
* RWS 2.0); this class just brands the type with `implements IRWSAdapter` so
|
|
10
|
+
* code that's polymorphic over RWS 1.0 + 2.0 (e.g. RobotManager) can hold
|
|
11
|
+
* either an `RWS1Adapter` or `RWS2Adapter` in a single typed reference.
|
|
12
|
+
*
|
|
13
|
+
* Use directly when you want the unified-adapter API:
|
|
14
|
+
* `const a: IRWSAdapter = new RWS2Adapter('https://controller', 'Admin', 'robotics');`
|
|
15
|
+
*
|
|
16
|
+
* Use `RwsClient2` directly if you only ever target RWS 2.0 and don't need
|
|
17
|
+
* the abstraction layer.
|
|
18
|
+
*/
|
|
19
|
+
export class RWS2Adapter extends RwsClient2 implements IRWSAdapter {}
|
|
@@ -0,0 +1,517 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ResourceMapper — pure functions that map RWS operations to URL paths and
|
|
3
|
+
* application/x-www-form-urlencoded request bodies.
|
|
4
|
+
*
|
|
5
|
+
* No HTTP, no state. All functions are individually exported for tree-shaking.
|
|
6
|
+
* Targets RWS 1.0 (RobotWare 6.x). Not compatible with RWS 2.0 / RobotWare 7.x.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// ─── Controller ──────────────────────────────────────────────────────────────
|
|
10
|
+
|
|
11
|
+
/** Path to read the current controller state (motoron, motoroff, etc.) */
|
|
12
|
+
export function controllerState(): string {
|
|
13
|
+
return '/rw/panel/ctrlstate';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Path + body to set the controller motor state (motoron / motoroff). Requires mastership. */
|
|
17
|
+
export function setControllerState(state: 'motoron' | 'motoroff'): { path: string; body: string } {
|
|
18
|
+
return {
|
|
19
|
+
path: '/rw/panel/ctrlstate?action=setctrlstate',
|
|
20
|
+
body: `ctrl-state=${state}`,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Path to read the current operation mode (AUTO, MANR, MANF) */
|
|
25
|
+
export function operationMode(): string {
|
|
26
|
+
return '/rw/panel/opmode';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Path to read the current speed ratio (0–100) */
|
|
30
|
+
export function speedRatio(): string {
|
|
31
|
+
return '/rw/panel/speedratio';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Path + body to set the speed ratio. Only valid in AUTO mode. @param ratio 0–100 */
|
|
35
|
+
export function setSpeedRatio(ratio: number): { path: string; body: string } {
|
|
36
|
+
return {
|
|
37
|
+
path: '/rw/panel/speedratio?action=setspeedratio',
|
|
38
|
+
body: `speed-ratio=${Math.round(Math.max(0, Math.min(100, ratio)))}`,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// ─── RAPID ───────────────────────────────────────────────────────────────────
|
|
43
|
+
|
|
44
|
+
/** Path to list all RAPID tasks */
|
|
45
|
+
export function rapidTasks(): string {
|
|
46
|
+
return '/rw/rapid/tasks';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Path to read the RAPID execution state (running / stopped) */
|
|
50
|
+
export function rapidExecutionState(): string {
|
|
51
|
+
return '/rw/rapid/execution';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Path + body to start RAPID program execution */
|
|
55
|
+
export function startRapid(): { path: string; body: string } {
|
|
56
|
+
return {
|
|
57
|
+
path: '/rw/rapid/execution?action=start',
|
|
58
|
+
body: 'regain=continue&execmode=continue&cycle=forever&condition=none&stopatbp=disabled&alltaskbytsp=false',
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Path + body to stop RAPID program execution */
|
|
63
|
+
export function stopRapid(): { path: string; body: string } {
|
|
64
|
+
return {
|
|
65
|
+
path: '/rw/rapid/execution?action=stop',
|
|
66
|
+
body: 'stopmode=stop',
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Path + body to reset the RAPID program pointer to main.
|
|
72
|
+
* The body is empty but Content-Type must still be application/x-www-form-urlencoded.
|
|
73
|
+
*/
|
|
74
|
+
export function resetRapid(): { path: string; body: string } {
|
|
75
|
+
return {
|
|
76
|
+
path: '/rw/rapid/execution?action=resetpp',
|
|
77
|
+
body: '',
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Path + body to set the RAPID execution cycle mode.
|
|
83
|
+
* @param cycle - 'once' (run once then stop) | 'forever' (loop indefinitely) | 'asis' (keep current)
|
|
84
|
+
*/
|
|
85
|
+
export function setExecutionCycle(cycle: 'once' | 'forever' | 'asis'): { path: string; body: string } {
|
|
86
|
+
return {
|
|
87
|
+
path: '/rw/rapid/execution?action=setcycle',
|
|
88
|
+
body: `cycle=${cycle}`,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// ─── Controller panel ────────────────────────────────────────────────────────
|
|
93
|
+
|
|
94
|
+
/** Path to read the collision detection state (INIT/TRIGGERED/CONFIRMED/TRIGGERED_ACK). */
|
|
95
|
+
export function collisionDetectionState(): string {
|
|
96
|
+
return '/rw/panel/coldetstate';
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Path + body to restart (or shutdown) the controller.
|
|
101
|
+
* @param mode - 'restart' | 'istart' | 'pstart' | 'bstart'
|
|
102
|
+
*/
|
|
103
|
+
export function restartController(mode: 'restart' | 'istart' | 'pstart' | 'bstart'): { path: string; body: string } {
|
|
104
|
+
return {
|
|
105
|
+
path: '/rw/panel?action=restart',
|
|
106
|
+
body: `restart-mode=${mode}`,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Path + body to lock the operation mode selector.
|
|
112
|
+
* @param pin - 4-digit PIN
|
|
113
|
+
* @param permanent - true = permanent lock; false = temporary
|
|
114
|
+
*/
|
|
115
|
+
export function lockOperationMode(pin: string, permanent: boolean): { path: string; body: string } {
|
|
116
|
+
return {
|
|
117
|
+
path: '/rw/panel/opmode?action=lock',
|
|
118
|
+
body: `pin=${encodeURIComponent(pin)}&permanent=${permanent ? 1 : 0}`,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Path + body to unlock the operation mode selector. */
|
|
123
|
+
export function unlockOperationMode(): { path: string; body: string } {
|
|
124
|
+
return { path: '/rw/panel/opmode?action=unlock', body: '' };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ─── RAPID UI instructions ───────────────────────────────────────────────────
|
|
128
|
+
|
|
129
|
+
/** Path to GET the currently active RAPID UI instruction (if any). */
|
|
130
|
+
export function activeUiInstruction(): string {
|
|
131
|
+
return '/rw/rapid/uiinstr/active';
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Path + body to set a parameter value on the active RAPID UI instruction.
|
|
136
|
+
* Used to respond programmatically to TPReadNum, TPReadFK, etc.
|
|
137
|
+
*
|
|
138
|
+
* @param stackurl - Full stack URL from the UiInstruction.stack field (e.g. 'RAPID/T_ROB1/%$104')
|
|
139
|
+
* @param uiparam - Parameter name: 'Result', 'TPFK1' … 'TPFK5', 'TPCompleted', etc.
|
|
140
|
+
* @param value - New value (e.g. '42', 'TRUE', '0')
|
|
141
|
+
*/
|
|
142
|
+
export function setUiInstructionParam(
|
|
143
|
+
stackurl: string, uiparam: string, value: string,
|
|
144
|
+
): { path: string; body: string } {
|
|
145
|
+
return {
|
|
146
|
+
path: `/rw/rapid/uiinstr/active/param/${encodeURIComponent(stackurl)}/${encodeURIComponent(uiparam)}?action=set`,
|
|
147
|
+
body: `value=${encodeURIComponent(value)}`,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// ─── RAPID task activation ───────────────────────────────────────────────────
|
|
152
|
+
|
|
153
|
+
/** Path + body to activate a single RAPID task (multitasking). */
|
|
154
|
+
export function activateRapidTask(task: string): { path: string; body: string } {
|
|
155
|
+
return { path: `/rw/rapid/tasks/${encodeURIComponent(task)}?action=activate`, body: '' };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** Path + body to deactivate a single RAPID task (multitasking). */
|
|
159
|
+
export function deactivateRapidTask(task: string): { path: string; body: string } {
|
|
160
|
+
return { path: `/rw/rapid/tasks/${encodeURIComponent(task)}?action=deactivate`, body: '' };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** Path + body to activate ALL RAPID tasks. */
|
|
164
|
+
export function activateAllRapidTasks(): { path: string; body: string } {
|
|
165
|
+
return { path: '/rw/rapid/tasks?action=activate', body: '' };
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/** Path + body to deactivate ALL RAPID tasks. */
|
|
169
|
+
export function deactivateAllRapidTasks(): { path: string; body: string } {
|
|
170
|
+
return { path: '/rw/rapid/tasks?action=deactivate', body: '' };
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// ─── RAPID symbol search / validate ─────────────────────────────────────────
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Path + body to search RAPID symbols across a task.
|
|
177
|
+
* POST /rw/rapid/symbols?action=search-symbol
|
|
178
|
+
*/
|
|
179
|
+
export function searchRapidSymbols(params: {
|
|
180
|
+
task: string;
|
|
181
|
+
view?: string;
|
|
182
|
+
vartyp?: string;
|
|
183
|
+
symtyp?: string;
|
|
184
|
+
dattyp?: string;
|
|
185
|
+
regexp?: string;
|
|
186
|
+
recursive?: boolean;
|
|
187
|
+
blockurl?: string;
|
|
188
|
+
}): { path: string; body: string } {
|
|
189
|
+
const parts: string[] = [];
|
|
190
|
+
parts.push(`task=${encodeURIComponent(params.task)}`);
|
|
191
|
+
if (params.view) parts.push(`view=${encodeURIComponent(params.view)}`);
|
|
192
|
+
if (params.vartyp) parts.push(`vartyp=${encodeURIComponent(params.vartyp)}`);
|
|
193
|
+
if (params.symtyp) parts.push(`symtyp=${encodeURIComponent(params.symtyp)}`);
|
|
194
|
+
if (params.dattyp) parts.push(`dattyp=${encodeURIComponent(params.dattyp)}`);
|
|
195
|
+
if (params.regexp) parts.push(`regexp=${encodeURIComponent(params.regexp)}`);
|
|
196
|
+
if (params.blockurl) parts.push(`blockurl=${encodeURIComponent(params.blockurl)}`);
|
|
197
|
+
if (params.recursive !== undefined) parts.push(`recursive=${params.recursive}`);
|
|
198
|
+
return {
|
|
199
|
+
path: '/rw/rapid/symbols?action=search-symbol',
|
|
200
|
+
body: parts.join('&'),
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Path + body to validate a value against a RAPID data type.
|
|
206
|
+
* POST /rw/rapid/symbol/data?action=validate
|
|
207
|
+
* Returns 204 if valid, 400 if invalid.
|
|
208
|
+
*/
|
|
209
|
+
export function validateRapidValue(task: string, value: string, datatype: string): { path: string; body: string } {
|
|
210
|
+
return {
|
|
211
|
+
path: '/rw/rapid/symbol/data?action=validate',
|
|
212
|
+
body: `task=${encodeURIComponent(task)}&value=${encodeURIComponent(value)}&datatype=${encodeURIComponent(datatype)}`,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// ─── RAPID symbols ───────────────────────────────────────────────────────────
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Path to read RAPID symbol properties (type, dimensions, storage, etc.).
|
|
220
|
+
* @param taskName - RAPID task name, e.g. 'T_ROB1'
|
|
221
|
+
* @param moduleName - Module name, e.g. 'user'
|
|
222
|
+
* @param symbolName - Symbol name, e.g. 'reg1'
|
|
223
|
+
*/
|
|
224
|
+
export function rapidSymbolProperties(taskName: string, moduleName: string, symbolName: string): string {
|
|
225
|
+
return `/rw/rapid/symbol/properties/RAPID/${encodeURIComponent(taskName)}/${encodeURIComponent(moduleName)}/${encodeURIComponent(symbolName)}`;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Path to read a RAPID symbol value.
|
|
230
|
+
* @param taskName - RAPID task name, e.g. 'T_ROB1'
|
|
231
|
+
* @param moduleName - Module name, e.g. 'user'
|
|
232
|
+
* @param symbolName - Symbol name, e.g. 'reg1'
|
|
233
|
+
*/
|
|
234
|
+
export function rapidSymbol(taskName: string, moduleName: string, symbolName: string): string {
|
|
235
|
+
return `/rw/rapid/symbol/data/RAPID/${encodeURIComponent(taskName)}/${encodeURIComponent(moduleName)}/${encodeURIComponent(symbolName)}`;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Path + body to set a RAPID symbol value.
|
|
240
|
+
* @param taskName - RAPID task name
|
|
241
|
+
* @param moduleName - Module name
|
|
242
|
+
* @param symbolName - Symbol name
|
|
243
|
+
* @param value - New value as RAPID-formatted string, e.g. '42', '"hello"', '[1,2,3]'
|
|
244
|
+
*/
|
|
245
|
+
export function setRapidSymbol(
|
|
246
|
+
taskName: string,
|
|
247
|
+
moduleName: string,
|
|
248
|
+
symbolName: string,
|
|
249
|
+
value: string,
|
|
250
|
+
): { path: string; body: string } {
|
|
251
|
+
return {
|
|
252
|
+
path: `${rapidSymbol(taskName, moduleName, symbolName)}?action=set`,
|
|
253
|
+
body: `value=${encodeURIComponent(value)}`,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// ─── Motion ──────────────────────────────────────────────────────────────────
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Path to read joint-space positions for a mechanical unit.
|
|
261
|
+
* @param mechunit - Default 'ROB_1' (the primary robot mechanical unit)
|
|
262
|
+
*/
|
|
263
|
+
export function jointTarget(mechunit = 'ROB_1'): string {
|
|
264
|
+
return `/rw/motionsystem/mechunits/${encodeURIComponent(mechunit)}/jointtarget`;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Path to read Cartesian robot target.
|
|
269
|
+
* @param mechunit - Default 'ROB_1'
|
|
270
|
+
* @param tool - Active tool frame; default 'tool0'
|
|
271
|
+
* @param wobj - Active work object frame; default 'wobj0'
|
|
272
|
+
*/
|
|
273
|
+
export function robTarget(mechunit = 'ROB_1', tool = 'tool0', wobj = 'wobj0'): string {
|
|
274
|
+
return `/rw/motionsystem/mechunits/${encodeURIComponent(mechunit)}/robtarget?tool=${encodeURIComponent(tool)}&wobj=${encodeURIComponent(wobj)}`;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Path to read Cartesian position including robot configuration flags (j1, j4, j6, jx).
|
|
279
|
+
* Uses the /cartesian sub-resource instead of /robtarget — no tool/wobj parameters.
|
|
280
|
+
* @param mechunit - Default 'ROB_1'
|
|
281
|
+
*/
|
|
282
|
+
export function cartesianFull(mechunit = 'ROB_1'): string {
|
|
283
|
+
return `/rw/motionsystem/mechunits/${encodeURIComponent(mechunit)}/cartesian`;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// ─── Modules ─────────────────────────────────────────────────────────────────
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Path + body to load a RAPID module into a task.
|
|
290
|
+
* @param taskName - RAPID task name, e.g. 'T_ROB1'
|
|
291
|
+
* @param modulePath - Controller filesystem path, e.g. '$HOME/MyMod.mod'
|
|
292
|
+
* Do not double-encode the '$' prefix — the controller expects it literal.
|
|
293
|
+
*/
|
|
294
|
+
export function loadModule(taskName: string, modulePath: string, replace = false): { path: string; body: string } {
|
|
295
|
+
return {
|
|
296
|
+
path: `/rw/rapid/tasks/${encodeURIComponent(taskName)}?action=loadmod`,
|
|
297
|
+
body: `modulepath=${encodeURIComponent(modulePath)}&replace=${replace}`,
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Path to retrieve details about a specific loaded module.
|
|
303
|
+
* @param taskName - RAPID task name
|
|
304
|
+
* @param moduleName - Module name (without path or extension)
|
|
305
|
+
*/
|
|
306
|
+
export function getModule(taskName: string, moduleName: string): string {
|
|
307
|
+
return `/rw/rapid/tasks/${encodeURIComponent(taskName)}/modules/${encodeURIComponent(moduleName)}`;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Path to list all modules loaded in a RAPID task.
|
|
312
|
+
* @param taskName - RAPID task name
|
|
313
|
+
*/
|
|
314
|
+
export function listModules(taskName: string): string {
|
|
315
|
+
return `/rw/rapid/modules?task=${encodeURIComponent(taskName)}`;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// ─── File system ─────────────────────────────────────────────────────────────
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* PUT path for uploading a file to the controller filesystem.
|
|
322
|
+
* Use '$HOME/' prefix to target the controller home directory.
|
|
323
|
+
* @param remotePath - Controller path, e.g. '$HOME/MyMod.mod'
|
|
324
|
+
*/
|
|
325
|
+
export function uploadFile(remotePath: string): string {
|
|
326
|
+
return fileServicePath(remotePath);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// ─── Controller info ─────────────────────────────────────────────────────────
|
|
330
|
+
|
|
331
|
+
/** Path to get RobotWare system information (version, options, sysid) */
|
|
332
|
+
export function systemInfo(): string {
|
|
333
|
+
return '/rw/system';
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/** Path to get controller hardware identity (name, id, type, mac) */
|
|
337
|
+
export function controllerIdentity(): string {
|
|
338
|
+
return '/ctrl/identity';
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/** Path to GET the controller clock datetime. */
|
|
342
|
+
export function clockInfo(): string {
|
|
343
|
+
return '/ctrl/clock';
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Path + body to SET the controller clock (PUT /ctrl/clock).
|
|
348
|
+
* All values are interpreted as UTC by the controller.
|
|
349
|
+
*/
|
|
350
|
+
export function setControllerClock(
|
|
351
|
+
year: number, month: number, day: number,
|
|
352
|
+
hour: number, min: number, sec: number,
|
|
353
|
+
): { path: string; body: string; method: 'PUT' } {
|
|
354
|
+
return {
|
|
355
|
+
path: '/ctrl/clock',
|
|
356
|
+
body: `sys-clock-year=${year}&sys-clock-month=${month}&sys-clock-day=${day}&sys-clock-hour=${hour}&sys-clock-min=${min}&sys-clock-sec=${sec}`,
|
|
357
|
+
method: 'PUT',
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// ─── Event log ───────────────────────────────────────────────────────────────
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Path to read event log messages.
|
|
365
|
+
* Domain 0 = common controller log (up to 1000 entries, most useful).
|
|
366
|
+
* @param domain - Log domain number; default 0
|
|
367
|
+
* @param lang - Language for message text; default 'en'
|
|
368
|
+
*/
|
|
369
|
+
export function elogMessages(domain = 0, lang = 'en'): string {
|
|
370
|
+
return `/rw/elog/${domain}?lang=${encodeURIComponent(lang)}`;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/** Path + body to clear all messages in a specific elog domain. */
|
|
374
|
+
export function clearElogDomain(domain = 0): { path: string; body: string } {
|
|
375
|
+
return { path: `/rw/elog/${domain}?action=clear`, body: '' };
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/** Path + body to clear ALL elog messages across all domains. */
|
|
379
|
+
export function clearAllElogs(): { path: string; body: string } {
|
|
380
|
+
return { path: '/rw/elog?action=clearall', body: '' };
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// ─── File system ─────────────────────────────────────────────────────────────
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Path for GET (download file or list directory) and PUT (upload file).
|
|
387
|
+
* Use '$HOME/' prefix to target the controller home directory.
|
|
388
|
+
*
|
|
389
|
+
* Each segment is percent-encoded so names with spaces, '#', '%', etc. survive
|
|
390
|
+
* URL parsing. The '$' of IRC5 volume roots ($HOME, $TEMP, …) stays literal —
|
|
391
|
+
* the controller rejects '%24'.
|
|
392
|
+
*/
|
|
393
|
+
export function fileServicePath(remotePath: string): string {
|
|
394
|
+
const normalised = remotePath.replace(/^\//, '');
|
|
395
|
+
const encoded = normalised
|
|
396
|
+
.split('/')
|
|
397
|
+
.map(seg => seg.startsWith('$') ? `$${encodeURIComponent(seg.slice(1))}` : encodeURIComponent(seg))
|
|
398
|
+
.join('/');
|
|
399
|
+
return `/fileservice/${encoded}`;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/** DELETE path to remove a file from the controller filesystem. */
|
|
403
|
+
export function deleteFile(remotePath: string): string {
|
|
404
|
+
return fileServicePath(remotePath);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Path to create a new directory on the controller filesystem.
|
|
409
|
+
* POST to this path with body 'fs-action=create&fs-newname={dirName}'.
|
|
410
|
+
* @param parentPath - Parent directory path, e.g. '$HOME'
|
|
411
|
+
*/
|
|
412
|
+
export function createDirectory(parentPath: string): { path: string } {
|
|
413
|
+
return { path: fileServicePath(parentPath) };
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Path to copy a file on the controller filesystem.
|
|
418
|
+
* POST to this path with body 'fs-action=copy&fs-newname={filename}'.
|
|
419
|
+
*
|
|
420
|
+
* RWS 1.0 fileservice copy operates *within the source's directory only*:
|
|
421
|
+
* fs-newname must be a bare filename, not a path. Passing a full path
|
|
422
|
+
* returns 400 "Invalid". To copy across directories, copy first then move
|
|
423
|
+
* (or upload to the new path directly).
|
|
424
|
+
*
|
|
425
|
+
* @param sourcePath - Source file path, e.g. '$HOME/Source.mod'
|
|
426
|
+
* @param destPath - Destination path. The basename is extracted and used
|
|
427
|
+
* as fs-newname; any directory component is ignored.
|
|
428
|
+
*/
|
|
429
|
+
export function copyFile(sourcePath: string, destPath: string): { path: string; body: string } {
|
|
430
|
+
const destBasename = destPath.replace(/^.*[\\/]/, '');
|
|
431
|
+
return {
|
|
432
|
+
path: fileServicePath(sourcePath),
|
|
433
|
+
body: `fs-action=copy&fs-newname=${encodeURIComponent(destBasename)}`,
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// ─── Mastership ───────────────────────────────────────────────────────────────
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Path + body to request mastership on a domain.
|
|
441
|
+
* Must be released after use. Domains: 'cfg' | 'motion' | 'rapid'.
|
|
442
|
+
*/
|
|
443
|
+
export function requestMastership(domain: 'cfg' | 'motion' | 'rapid'): { path: string; body: string } {
|
|
444
|
+
return { path: `/rw/mastership/${domain}?action=request`, body: '' };
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/** Path + body to release mastership on a domain. */
|
|
448
|
+
export function releaseMastership(domain: 'cfg' | 'motion' | 'rapid'): { path: string; body: string } {
|
|
449
|
+
return { path: `/rw/mastership/${domain}?action=release`, body: '' };
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// ─── I/O ─────────────────────────────────────────────────────────────────────
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* Build the signal path segment from optional network/device/name.
|
|
456
|
+
* If network and device are empty, the signal is a virtual flat signal (no prefix).
|
|
457
|
+
*/
|
|
458
|
+
function signalPath(network: string, device: string, name: string): string {
|
|
459
|
+
if (network && device) {
|
|
460
|
+
return `/rw/iosystem/signals/${encodeURIComponent(network)}/${encodeURIComponent(device)}/${encodeURIComponent(name)}`;
|
|
461
|
+
}
|
|
462
|
+
return `/rw/iosystem/signals/${encodeURIComponent(name)}`;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* Path to list all I/O signals (paginated).
|
|
467
|
+
* @param start - Starting index (default 0)
|
|
468
|
+
* @param limit - Max results per page (default 100)
|
|
469
|
+
*/
|
|
470
|
+
export function allSignals(start = 0, limit = 100): string {
|
|
471
|
+
return `/rw/iosystem/signals?start=${start}&limit=${limit}`;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/** Path to list all configured I/O networks */
|
|
475
|
+
export function networks(): string {
|
|
476
|
+
return '/rw/iosystem/networks';
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Path to list all devices on a network.
|
|
481
|
+
* @param network - Network name, e.g. 'Local'
|
|
482
|
+
*/
|
|
483
|
+
export function devices(network: string): string {
|
|
484
|
+
return `/rw/iosystem/devices?network=${encodeURIComponent(network)}`;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* Path to read a digital/analog I/O signal value.
|
|
489
|
+
*
|
|
490
|
+
* @param network - I/O network name, e.g. 'Local'. Pass '' for virtual/flat signals.
|
|
491
|
+
* @param device - I/O device name, e.g. 'DRV_1'. Pass '' for virtual/flat signals.
|
|
492
|
+
* @param name - Signal name, e.g. 'DI_1'
|
|
493
|
+
*/
|
|
494
|
+
export function signal(network: string, device: string, name: string): string {
|
|
495
|
+
return signalPath(network, device, name);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Path to write a digital/analog I/O signal value.
|
|
500
|
+
* The body with lvalue={value} is supplied by the caller (RwsClient.writeSignal).
|
|
501
|
+
*
|
|
502
|
+
* @param network - I/O network name. Pass '' for virtual/flat signals.
|
|
503
|
+
* @param device - I/O device name. Pass '' for virtual/flat signals.
|
|
504
|
+
* @param name - Signal name
|
|
505
|
+
*/
|
|
506
|
+
export function setSignal(network: string, device: string, name: string): { path: string } {
|
|
507
|
+
return {
|
|
508
|
+
path: `${signalPath(network, device, name)}?action=set`,
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// ─── Subscriptions ───────────────────────────────────────────────────────────
|
|
513
|
+
|
|
514
|
+
/** Path to create a new WebSocket subscription (POST /subscription) */
|
|
515
|
+
export function subscriptions(): string {
|
|
516
|
+
return '/subscription';
|
|
517
|
+
}
|