@synapticon/motion-master-client 6.0.0-alpha.82 → 6.0.0-alpha.83

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.
@@ -495,7 +495,7 @@ export declare class Api<SecurityDataType = unknown> extends HttpClient<Security
495
495
  }[];
496
496
  }[], any>>;
497
497
  /**
498
- * @description The register map of the Integro's internal (Kübler) encoder — the reference table for POST /api/devices/{slavePosition}/procedures/kuebler-register-communication, and documentation in its own right. Static: it describes the encoder type, not any connected device, so it needs no bus and no scan. Transcribed from the vendor's own draft table. Each entry carries the width, the access type, whether the encoder actually implements it — seven are documented but not implemented — and the vendor's bit definitions verbatim, which for a bit-field register is the only place its meaning is recorded. `format` says how to read the assembled value, because signedness is not uniform and one register is not a single number at all: `unsigned`, `signed`, `bitField` (the number means nothing on its own), or `signedHalves` — two signed 16-bit values packed into 32 bits, which register 0x3C is the only case of. `readableInOneCommand` is false for the one 64-bit register, since the command's length byte caps at 4 bytes.
498
+ * @description The register map of the Integro's internal (Kübler) encoder — the reference table for POST /api/devices/{slavePosition}/procedures/kuebler-register-communication, and documentation in its own right. Static: it describes the encoder type, not any connected device, so it needs no bus and no scan. Transcribed from the vendor's own draft table, then corrected against what the encoder really does: the draft calls four registers not implemented that the encoder calibration sequence reads or writes, and leaves out four more. Each entry carries the width, the access type, whether the encoder implements it, and the vendor's bit definitions verbatim, which for a bit-field register is the only place its meaning is recorded. A register the draft does not document says so in `definition`, because a reader has nowhere else to look. `format` says how to read the assembled value, because signedness is not uniform and one register is not a single number at all: `unsigned`, `signed`, `bitField` (the number means nothing on its own), or `signedHalves` — two signed 16-bit values packed into 32 bits, which register 0x3C is the only case of. `readableInOneCommand` says whether one command can carry the register, since the command's length byte caps at 4 bytes. Every register fits today, so it is true for all of them.
499
499
  *
500
500
  * @name GetKueblerRegisters
501
501
  * @summary The Integro internal encoder's register map
@@ -1028,6 +1028,23 @@ export declare class Api<SecurityDataType = unknown> extends HttpClient<Security
1028
1028
  */
1029
1029
  error: string;
1030
1030
  }>>;
1031
+ /**
1032
+ * @description Deletes `filename` from the flash of the device at `slavePosition`. **Vendor-specific despite reading like a filesystem operation.** FoE has no delete, so SOMANET firmware acts on a pseudo-file instead: reading the name `fs-remove=<filename>` removes that file. This endpoint exists so no client has to know that, and a device that is not a SOMANET drive is refused rather than probed. **A file that was not there answers 200.** The caller asked for the file to be gone, and it is. Every other FoE failure is a 500 naming the reason. The file is gone from flash immediately. Deleting `config.csv` discards the stored parameter values, so the drive falls back to its defaults on the next power cycle.
1033
+ *
1034
+ * @name DeleteDeviceFile
1035
+ * @summary Delete a file from a device
1036
+ * @request DELETE:/api/devices/{slavePosition}/files/{filename}
1037
+ */
1038
+ deleteDeviceFile: (slavePosition: number, filename: string, params?: RequestParams) => Promise<import("./http-client.js").HttpResponse<{
1039
+ /** @example true */
1040
+ ok?: boolean;
1041
+ }, void | {
1042
+ /**
1043
+ * Human-readable error message from the driver
1044
+ * @example "SDOread slave 1 0x2345:01 failed (no response — mailbox timeout)"
1045
+ */
1046
+ error: string;
1047
+ }>>;
1031
1048
  /**
1032
1049
  * @description Reads the raw SII EEPROM image of the device at `slavePosition` through the ESC's EEPROM-control registers and returns either the parsed structure or the raw bytes, selected by the `Accept` request header. With `Accept: application/json` (or `*\/*`, or no `Accept` header) the parsed `SlaveInformationInterface` is returned — the 128-byte fixed header plus the decoded category section (strings, general info, FMMU/Sync-Manager and PDO defaults, distributed-clock settings). With `Accept: application/octet-stream` the raw EEPROM image is returned unparsed, suitable for a hex dump or archival. EEPROM access is a control-plane operation and is most reliable while the device is in INIT or PRE-OP. String-index fields in the parsed structure (e.g. `general.nameIdx`) are 1-based references into `category.strings`.
1033
1050
  *
@@ -273,7 +273,7 @@ export class Api extends HttpClient {
273
273
  ...params,
274
274
  });
275
275
  /**
276
- * @description The register map of the Integro's internal (Kübler) encoder — the reference table for POST /api/devices/{slavePosition}/procedures/kuebler-register-communication, and documentation in its own right. Static: it describes the encoder type, not any connected device, so it needs no bus and no scan. Transcribed from the vendor's own draft table. Each entry carries the width, the access type, whether the encoder actually implements it — seven are documented but not implemented — and the vendor's bit definitions verbatim, which for a bit-field register is the only place its meaning is recorded. `format` says how to read the assembled value, because signedness is not uniform and one register is not a single number at all: `unsigned`, `signed`, `bitField` (the number means nothing on its own), or `signedHalves` — two signed 16-bit values packed into 32 bits, which register 0x3C is the only case of. `readableInOneCommand` is false for the one 64-bit register, since the command's length byte caps at 4 bytes.
276
+ * @description The register map of the Integro's internal (Kübler) encoder — the reference table for POST /api/devices/{slavePosition}/procedures/kuebler-register-communication, and documentation in its own right. Static: it describes the encoder type, not any connected device, so it needs no bus and no scan. Transcribed from the vendor's own draft table, then corrected against what the encoder really does: the draft calls four registers not implemented that the encoder calibration sequence reads or writes, and leaves out four more. Each entry carries the width, the access type, whether the encoder implements it, and the vendor's bit definitions verbatim, which for a bit-field register is the only place its meaning is recorded. A register the draft does not document says so in `definition`, because a reader has nowhere else to look. `format` says how to read the assembled value, because signedness is not uniform and one register is not a single number at all: `unsigned`, `signed`, `bitField` (the number means nothing on its own), or `signedHalves` — two signed 16-bit values packed into 32 bits, which register 0x3C is the only case of. `readableInOneCommand` says whether one command can carry the register, since the command's length byte caps at 4 bytes. Every register fits today, so it is true for all of them.
277
277
  *
278
278
  * @name GetKueblerRegisters
279
279
  * @summary The Integro internal encoder's register map
@@ -765,6 +765,19 @@ export class Api extends HttpClient {
765
765
  format: "json",
766
766
  ...params,
767
767
  });
768
+ /**
769
+ * @description Deletes `filename` from the flash of the device at `slavePosition`. **Vendor-specific despite reading like a filesystem operation.** FoE has no delete, so SOMANET firmware acts on a pseudo-file instead: reading the name `fs-remove=<filename>` removes that file. This endpoint exists so no client has to know that, and a device that is not a SOMANET drive is refused rather than probed. **A file that was not there answers 200.** The caller asked for the file to be gone, and it is. Every other FoE failure is a 500 naming the reason. The file is gone from flash immediately. Deleting `config.csv` discards the stored parameter values, so the drive falls back to its defaults on the next power cycle.
770
+ *
771
+ * @name DeleteDeviceFile
772
+ * @summary Delete a file from a device
773
+ * @request DELETE:/api/devices/{slavePosition}/files/{filename}
774
+ */
775
+ deleteDeviceFile = (slavePosition, filename, params = {}) => this.request({
776
+ path: `/api/devices/${slavePosition}/files/${filename}`,
777
+ method: "DELETE",
778
+ format: "json",
779
+ ...params,
780
+ });
768
781
  /**
769
782
  * @description Reads the raw SII EEPROM image of the device at `slavePosition` through the ESC's EEPROM-control registers and returns either the parsed structure or the raw bytes, selected by the `Accept` request header. With `Accept: application/json` (or `*\/*`, or no `Accept` header) the parsed `SlaveInformationInterface` is returned — the 128-byte fixed header plus the decoded category section (strings, general info, FMMU/Sync-Manager and PDO defaults, distributed-clock settings). With `Accept: application/octet-stream` the raw EEPROM image is returned unparsed, suitable for a hex dump or archival. EEPROM access is a control-plane operation and is most reliable while the device is in INIT or PRE-OP. String-index fields in the parsed structure (e.g. `general.nameIdx`) are 1-based references into `category.strings`.
770
783
  *
@@ -418,7 +418,7 @@ export interface ProgressStep {
418
418
  /** @example "succeeded" */
419
419
  status: "idle" | "running" | "succeeded" | "failed";
420
420
  /**
421
- * 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`, and `errorCode` when the drive sent one.
421
+ * 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`.
422
422
  * @example {"status":1,"data":[1,2,3,4,5,6]}
423
423
  */
424
424
  value?: any;
@@ -897,6 +897,14 @@ export interface ProcedureRequest {
897
897
  * @default 10
898
898
  */
899
899
  pollIntervalMs?: number;
900
+ /**
901
+ * `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.
902
+ * @default "none"
903
+ * @example "read"
904
+ */
905
+ fsBuffer?: "none" | "read" | "write";
906
+ /** `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`.) */
907
+ fsBufferData?: string;
900
908
  /**
901
909
  * `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.
902
910
  * @default 1
@@ -19,6 +19,7 @@ type MonitoringListener = (rows: MonitoringBatch) => void;
19
19
  type NotificationListener = (data: unknown) => void;
20
20
  type ProgressListener = (data: unknown) => void;
21
21
  type StateListener = (state: ReadyState) => void;
22
+ export declare const NOTIFICATION_TOPIC = "notifications";
22
23
  export interface WebSocketLike {
23
24
  readyState: number;
24
25
  send(data: string): void;
@@ -3,12 +3,20 @@
3
3
  // progress, and client->server topic subscribe/unsubscribe. It owns reconnection, multiplexes
4
4
  // per-topic subscriptions over the one socket (ref-counted: subscribe on the first listener,
5
5
  // unsubscribe on the last, re-subscribe everything on reconnect), and routes inbound frames by
6
- // type. It is isomorphic: the browser global `WebSocket` is used by default, and any compatible
7
- // implementation (e.g. the Node `ws` package) can be injected — there is no hard dependency on
8
- // either, so the package stays usable in both environments.
6
+ // type. Nothing arrives until something is subscribed: `subscribe(topic, cb)` for one monitoring's
7
+ // batches, `onNotification(cb)` for every server notification — the latter is one shared topic, so
8
+ // a single subscription covers events added in a later server version. It is isomorphic: the
9
+ // browser global `WebSocket` is used by default, and any compatible implementation (e.g. the Node
10
+ // `ws` package) can be injected — there is no hard dependency on either, so the package stays
11
+ // usable in both environments.
9
12
  /// The numeric `readyState` value a WebSocket reports when it is open. Hard-coded (rather than read
10
13
  /// off a global) so the client never depends on a particular `WebSocket` implementation's statics.
11
14
  const WS_OPEN = 1;
15
+ /// The one topic every server notification is published to. One topic rather than one per event, so
16
+ /// a client subscribes once and keeps receiving events added in a later server version — uWebSockets
17
+ /// matches topic names exactly, with no wildcard, so there is no way to ask for "all of them".
18
+ /// Events are told apart by `data.event`, which is kebab-case.
19
+ export const NOTIFICATION_TOPIC = 'notifications';
12
20
  export class WebSocketConnection {
13
21
  url;
14
22
  WebSocketImpl;
@@ -69,6 +77,9 @@ export class WebSocketConnection {
69
77
  for (const topic of this.topicListeners.keys()) {
70
78
  this.send({ subscribe: topic });
71
79
  }
80
+ if (this.notificationListeners.size > 0) {
81
+ this.send({ subscribe: NOTIFICATION_TOPIC });
82
+ }
72
83
  };
73
84
  socket.onmessage = (event) => this.route(event.data);
74
85
  socket.onclose = () => this.handleDisconnect();
@@ -117,13 +128,21 @@ export class WebSocketConnection {
117
128
  }
118
129
  };
119
130
  }
120
- /// Registers a listener for server notifications (e.g. `{ event: 'slaves_changed' }`). Connects
121
- /// lazily. Returns a removal function.
131
+ /// Registers a listener for server notifications (e.g. `{ event: 'short-working-counter' }`). Every
132
+ /// notification arrives on one topic, so the first listener subscribes and the last to leave
133
+ /// unsubscribes — the same ref-counting `subscribe` uses. Connects lazily. Returns a removal
134
+ /// function.
122
135
  onNotification(listener) {
136
+ if (this.notificationListeners.size === 0) {
137
+ this.send({ subscribe: NOTIFICATION_TOPIC });
138
+ }
123
139
  this.notificationListeners.add(listener);
124
140
  this.connect();
125
141
  return () => {
126
142
  this.notificationListeners.delete(listener);
143
+ if (this.notificationListeners.size === 0) {
144
+ this.send({ unsubscribe: NOTIFICATION_TOPIC });
145
+ }
127
146
  };
128
147
  }
129
148
  /// Registers a listener for procedure progress messages (reserved; fires once the backend ships
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synapticon/motion-master-client",
3
- "version": "6.0.0-alpha.82",
3
+ "version": "6.0.0-alpha.83",
4
4
  "description": "Isomorphic TypeScript client for Motion Master: the generated HTTP API client, the WebSocket connection, and helpers.",
5
5
  "license": "MIT",
6
6
  "repository": {