tci-client-node 0.3.0 → 0.4.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.
Files changed (39) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +24 -0
  3. package/dist/audio/index.d.cts +2 -1
  4. package/dist/audio/index.d.ts +2 -1
  5. package/dist/dialect/index.cjs +175 -12
  6. package/dist/dialect/index.cjs.map +1 -1
  7. package/dist/dialect/index.d.cts +3 -2
  8. package/dist/dialect/index.d.ts +3 -2
  9. package/dist/dialect/index.js +175 -12
  10. package/dist/dialect/index.js.map +1 -1
  11. package/dist/errors-CT3b8LLw.d.cts +9 -0
  12. package/dist/errors-CT3b8LLw.d.ts +9 -0
  13. package/dist/index.cjs +404 -5
  14. package/dist/index.cjs.map +1 -1
  15. package/dist/index.d.cts +14 -5
  16. package/dist/index.d.ts +14 -5
  17. package/dist/index.js +399 -5
  18. package/dist/index.js.map +1 -1
  19. package/dist/meter/index.cjs +348 -0
  20. package/dist/meter/index.cjs.map +1 -0
  21. package/dist/meter/index.d.cts +78 -0
  22. package/dist/meter/index.d.ts +78 -0
  23. package/dist/meter/index.js +317 -0
  24. package/dist/meter/index.js.map +1 -0
  25. package/dist/protocol/index.d.cts +36 -2
  26. package/dist/protocol/index.d.ts +36 -2
  27. package/dist/testing/index.cjs +32 -0
  28. package/dist/testing/index.cjs.map +1 -1
  29. package/dist/testing/index.d.cts +19 -1
  30. package/dist/testing/index.d.ts +19 -1
  31. package/dist/testing/index.js +32 -0
  32. package/dist/testing/index.js.map +1 -1
  33. package/dist/types-C0qVJVSO.d.ts +74 -0
  34. package/dist/types-C4MtLKoy.d.cts +74 -0
  35. package/dist/{types-1YXGwrgI.d.cts → types-CYK_NOTz.d.cts} +2 -0
  36. package/dist/{types-BtPh4Dbd.d.ts → types-DVIPU-VR.d.ts} +2 -0
  37. package/package.json +11 -2
  38. package/dist/index-lbK6NGY4.d.cts +0 -42
  39. package/dist/index-paj1AOJY.d.ts +0 -42
@@ -0,0 +1,348 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/meter/index.ts
21
+ var meter_exports = {};
22
+ __export(meter_exports, {
23
+ StandardTciMeterAdapter: () => StandardTciMeterAdapter,
24
+ TciMeterStreamSession: () => TciMeterStreamSession,
25
+ UNKNOWN_TCI_METER_CAPABILITIES: () => UNKNOWN_TCI_METER_CAPABILITIES,
26
+ cloneMeterCapabilities: () => cloneMeterCapabilities,
27
+ createUnknownTciMeterAdapter: () => createUnknownTciMeterAdapter
28
+ });
29
+ module.exports = __toCommonJS(meter_exports);
30
+
31
+ // src/meter/types.ts
32
+ var UNKNOWN_TCI_METER_CAPABILITIES = {
33
+ rxLevel: "unknown",
34
+ rxAverageLevel: "unknown",
35
+ rxPeakBin: "unknown",
36
+ txMicLevel: "unknown",
37
+ txRmsPower: "unknown",
38
+ txPeakPower: "unknown",
39
+ txSwr: "unknown",
40
+ txAlcDbfs: "unknown"
41
+ };
42
+ function cloneMeterCapabilities(capabilities) {
43
+ return { ...capabilities };
44
+ }
45
+
46
+ // src/meter/adapters.ts
47
+ var StandardTciMeterAdapter = class {
48
+ declaredCapabilities;
49
+ options;
50
+ constructor(options = {}) {
51
+ this.options = options;
52
+ this.declaredCapabilities = {
53
+ ...UNKNOWN_TCI_METER_CAPABILITIES,
54
+ rxLevel: "declared",
55
+ txMicLevel: "declared",
56
+ txRmsPower: "declared",
57
+ txPeakPower: "declared",
58
+ txSwr: "declared",
59
+ rxAverageLevel: options.supportsRxExtended ? "declared" : "unknown",
60
+ rxPeakBin: options.supportsRxExtended ? "declared" : "unknown",
61
+ txAlcDbfs: options.txAlcUnit === "dbfs" ? "declared" : "unknown",
62
+ ...options.capabilities
63
+ };
64
+ }
65
+ normalizeInterval(intervalMs) {
66
+ const requestedMs = Math.round(intervalMs);
67
+ if (this.options.interval?.fixedMs !== void 0) {
68
+ return { requestedMs, appliedMs: this.options.interval.fixedMs };
69
+ }
70
+ const minMs = this.options.interval?.minMs ?? requestedMs;
71
+ const maxMs = this.options.interval?.maxMs ?? requestedMs;
72
+ const normalized = Math.max(minMs, Math.min(maxMs, requestedMs));
73
+ return {
74
+ requestedMs,
75
+ appliedMs: this.options.interval?.reportsApplied === false ? void 0 : normalized
76
+ };
77
+ }
78
+ buildEnableCommand(kind, enabled, intervalMs) {
79
+ return {
80
+ name: kind === "rx" ? "RX_SENSORS_ENABLE" : "TX_SENSORS_ENABLE",
81
+ args: enabled ? [true, intervalMs] : [false]
82
+ };
83
+ }
84
+ decode(command, receivedAtMs) {
85
+ switch (command.name) {
86
+ case "rx_sensors":
87
+ return decodeRx(command, receivedAtMs, "rx_sensors");
88
+ case "rx_channel_sensors":
89
+ return decodeRx(command, receivedAtMs, "rx_channel_sensors");
90
+ case "rx_channel_sensors_ex":
91
+ return decodeRx(command, receivedAtMs, "rx_channel_sensors_ex");
92
+ case "tx_sensors":
93
+ return decodeTx(command, receivedAtMs, this.options.txAlcUnit);
94
+ default:
95
+ return void 0;
96
+ }
97
+ }
98
+ };
99
+ function createUnknownTciMeterAdapter() {
100
+ return new StandardTciMeterAdapter({
101
+ capabilities: cloneMeterCapabilities(UNKNOWN_TCI_METER_CAPABILITIES),
102
+ interval: { reportsApplied: false }
103
+ });
104
+ }
105
+ function decodeRx(command, receivedAtMs, source) {
106
+ const receiver = integer(command.args[0]);
107
+ const hasChannel = source !== "rx_sensors";
108
+ const channel = hasChannel ? integer(command.args[1]) : 0;
109
+ const levelIndex = hasChannel ? 2 : 1;
110
+ const levelDbm = finite(command.args[levelIndex]);
111
+ if (receiver === void 0 || receiver < 0 || channel === void 0 || channel < 0 || levelDbm === void 0) {
112
+ return { issue: `Invalid ${command.originalName} meter frame: ${command.raw}` };
113
+ }
114
+ const frame = { receiver, channel, levelDbm, source, receivedAtMs };
115
+ if (source === "rx_channel_sensors_ex") {
116
+ const averageLevelDbm = finite(command.args[3]);
117
+ const peakBinDbm = finite(command.args[4]);
118
+ if (averageLevelDbm === void 0 || peakBinDbm === void 0) {
119
+ return { issue: `Invalid ${command.originalName} extended meter frame: ${command.raw}` };
120
+ }
121
+ frame.averageLevelDbm = averageLevelDbm;
122
+ frame.peakBinDbm = peakBinDbm;
123
+ if (command.args.length > 5) frame.extraArgs = command.args.slice(5);
124
+ } else if (command.args.length > levelIndex + 1) {
125
+ frame.extraArgs = command.args.slice(levelIndex + 1);
126
+ }
127
+ return { decoded: { kind: "rx", frame } };
128
+ }
129
+ function decodeTx(command, receivedAtMs, alcUnit) {
130
+ const trx = integer(command.args[0]);
131
+ if (trx === void 0 || trx < 0) {
132
+ return { issue: `Invalid ${command.originalName} transmitter index: ${command.raw}` };
133
+ }
134
+ const micLevelDbm = optionalFinite(command.args[1]);
135
+ const rmsPowerWatts = optionalFinite(command.args[2]);
136
+ const peakPowerWatts = optionalFinite(command.args[3]);
137
+ const swr = optionalFinite(command.args[4]);
138
+ const alcValue = alcUnit ? optionalFinite(command.args[5]) : void 0;
139
+ if (micLevelDbm.invalid || rmsPowerWatts.invalid || peakPowerWatts.invalid || swr.invalid || alcValue?.invalid) {
140
+ return { issue: `Invalid ${command.originalName} numeric meter frame: ${command.raw}` };
141
+ }
142
+ if (rmsPowerWatts.value !== void 0 && rmsPowerWatts.value < 0 || peakPowerWatts.value !== void 0 && peakPowerWatts.value < 0 || swr.value !== void 0 && swr.value < 1) {
143
+ return { issue: `Out-of-range ${command.originalName} meter frame: ${command.raw}` };
144
+ }
145
+ if (micLevelDbm.value === void 0 && rmsPowerWatts.value === void 0 && peakPowerWatts.value === void 0 && swr.value === void 0 && alcValue?.value === void 0) {
146
+ return { issue: `Empty ${command.originalName} meter frame: ${command.raw}` };
147
+ }
148
+ const frame = {
149
+ trx,
150
+ micLevelDbm: micLevelDbm.value,
151
+ rmsPowerWatts: rmsPowerWatts.value,
152
+ peakPowerWatts: peakPowerWatts.value,
153
+ swr: swr.value,
154
+ receivedAtMs
155
+ };
156
+ if (alcUnit && alcValue?.value !== void 0) frame.alc = { value: alcValue.value, unit: alcUnit };
157
+ const knownArgs = alcUnit ? 6 : 5;
158
+ if (command.args.length > knownArgs) frame.extraArgs = command.args.slice(knownArgs);
159
+ return { decoded: { kind: "tx", frame } };
160
+ }
161
+ function finite(value) {
162
+ if (value === void 0 || value === "") return void 0;
163
+ const parsed = Number(value);
164
+ return Number.isFinite(parsed) ? parsed : void 0;
165
+ }
166
+ function integer(value) {
167
+ const parsed = finite(value);
168
+ return parsed !== void 0 && Number.isInteger(parsed) ? parsed : void 0;
169
+ }
170
+ function optionalFinite(value) {
171
+ if (value === void 0 || value === "") return { invalid: false };
172
+ const parsed = Number(value);
173
+ return Number.isFinite(parsed) ? { value: parsed, invalid: false } : { invalid: true };
174
+ }
175
+
176
+ // src/meter/TciMeterStreamSession.ts
177
+ var import_eventemitter3 = require("eventemitter3");
178
+
179
+ // src/errors.ts
180
+ var TciError = class extends Error {
181
+ code;
182
+ details;
183
+ constructor(code, message, details) {
184
+ super(message);
185
+ this.name = "TciError";
186
+ this.code = code;
187
+ this.details = details;
188
+ }
189
+ };
190
+
191
+ // src/meter/TciMeterStreamSession.ts
192
+ var RX_COALESCE_MS = 20;
193
+ var TciMeterStreamSession = class extends import_eventemitter3.EventEmitter {
194
+ receiver;
195
+ channel;
196
+ trx;
197
+ requestedIntervalMs;
198
+ appliedIntervalMs;
199
+ rxEnabled;
200
+ txEnabled;
201
+ adapter;
202
+ callbacks;
203
+ capabilities;
204
+ pendingRx = /* @__PURE__ */ new Map();
205
+ closed = false;
206
+ constructor(options) {
207
+ super();
208
+ this.receiver = options.receiver;
209
+ this.channel = options.channel;
210
+ this.trx = options.trx;
211
+ this.requestedIntervalMs = options.requestedIntervalMs;
212
+ this.appliedIntervalMs = options.appliedIntervalMs;
213
+ this.rxEnabled = options.rxEnabled;
214
+ this.txEnabled = options.txEnabled;
215
+ this.adapter = options.adapter;
216
+ this.callbacks = options.callbacks;
217
+ this.capabilities = cloneMeterCapabilities(options.adapter.declaredCapabilities);
218
+ }
219
+ getCapabilities() {
220
+ return cloneMeterCapabilities(this.capabilities);
221
+ }
222
+ async close() {
223
+ if (this.closed) return;
224
+ this.closed = true;
225
+ this.clearPendingRx();
226
+ try {
227
+ await this.callbacks.close();
228
+ } finally {
229
+ this.emit("closed");
230
+ this.removeAllListeners();
231
+ }
232
+ }
233
+ _acceptCommand(command, receivedAtMs) {
234
+ if (this.closed) return;
235
+ this.acceptEnableAcknowledgement(command);
236
+ const result = this.adapter.decode(command, receivedAtMs);
237
+ if (!result) return;
238
+ if (result.issue) {
239
+ this.emit("error", new TciError("protocol-error", result.issue));
240
+ return;
241
+ }
242
+ if (result.decoded?.kind === "rx") this.acceptRxFrame(result.decoded.frame);
243
+ if (result.decoded?.kind === "tx") this.acceptTxFrame(result.decoded.frame);
244
+ }
245
+ _fail(error) {
246
+ if (this.closed) return;
247
+ this.closed = true;
248
+ this.clearPendingRx();
249
+ this.emit("error", error);
250
+ this.emit("closed");
251
+ this.removeAllListeners();
252
+ }
253
+ acceptRxFrame(frame) {
254
+ if (!this.rxEnabled || frame.receiver !== this.receiver || frame.channel !== this.channel) return;
255
+ this.observe("rxLevel");
256
+ if (frame.averageLevelDbm !== void 0) this.observe("rxAverageLevel");
257
+ if (frame.peakBinDbm !== void 0) this.observe("rxPeakBin");
258
+ const key = `${frame.receiver}:${frame.channel}`;
259
+ const pending = this.pendingRx.get(key);
260
+ if (pending) {
261
+ const sameReading = Math.abs(pending.frame.levelDbm - frame.levelDbm) < 0.05;
262
+ if (sameReading && rxPriority(frame) >= rxPriority(pending.frame)) {
263
+ clearTimeout(pending.timer);
264
+ this.pendingRx.delete(key);
265
+ } else if (sameReading) {
266
+ return;
267
+ } else {
268
+ this.flushRx(key, pending);
269
+ }
270
+ }
271
+ const timer = setTimeout(() => {
272
+ const current = this.pendingRx.get(key);
273
+ if (current?.frame === frame) this.flushRx(key, current);
274
+ }, RX_COALESCE_MS);
275
+ this.pendingRx.set(key, { frame, timer });
276
+ }
277
+ acceptTxFrame(frame) {
278
+ if (!this.txEnabled || frame.trx !== this.trx) return;
279
+ if (frame.micLevelDbm !== void 0) this.observe("txMicLevel");
280
+ if (frame.rmsPowerWatts !== void 0) this.observe("txRmsPower");
281
+ if (frame.peakPowerWatts !== void 0) this.observe("txPeakPower");
282
+ if (frame.swr !== void 0) this.observe("txSwr");
283
+ if (frame.alc?.unit === "dbfs") this.observe("txAlcDbfs");
284
+ this.emit("txFrame", frame);
285
+ }
286
+ acceptEnableAcknowledgement(command) {
287
+ const enabled = command.args[0]?.toLowerCase();
288
+ if (enabled !== "true" && enabled !== "1" && enabled !== "on") return;
289
+ if (command.name === "rx_sensors_enable" && this.rxEnabled) {
290
+ this.acknowledge(["rxLevel"]);
291
+ }
292
+ if (command.name === "tx_sensors_enable" && this.txEnabled) {
293
+ this.acknowledge(["txMicLevel", "txRmsPower", "txPeakPower", "txSwr"]);
294
+ }
295
+ }
296
+ acknowledge(keys) {
297
+ let changed = false;
298
+ for (const key of keys) {
299
+ if (supportRank(this.capabilities[key]) < supportRank("acknowledged")) {
300
+ this.capabilities[key] = "acknowledged";
301
+ changed = true;
302
+ }
303
+ }
304
+ if (changed) this.emit("capabilitiesChanged", this.getCapabilities());
305
+ }
306
+ observe(key) {
307
+ if (this.capabilities[key] === "observed") return;
308
+ this.capabilities[key] = "observed";
309
+ this.emit("capabilitiesChanged", this.getCapabilities());
310
+ }
311
+ flushRx(key, pending) {
312
+ clearTimeout(pending.timer);
313
+ if (this.pendingRx.get(key) === pending) this.pendingRx.delete(key);
314
+ this.emit("rxFrame", pending.frame);
315
+ }
316
+ clearPendingRx() {
317
+ for (const pending of this.pendingRx.values()) clearTimeout(pending.timer);
318
+ this.pendingRx.clear();
319
+ }
320
+ };
321
+ function rxPriority(frame) {
322
+ if (frame.source === "rx_channel_sensors_ex") return 3;
323
+ if (frame.source === "rx_channel_sensors") return 2;
324
+ return 1;
325
+ }
326
+ function supportRank(value) {
327
+ switch (value) {
328
+ case "unsupported":
329
+ return -1;
330
+ case "unknown":
331
+ return 0;
332
+ case "declared":
333
+ return 1;
334
+ case "acknowledged":
335
+ return 2;
336
+ case "observed":
337
+ return 3;
338
+ }
339
+ }
340
+ // Annotate the CommonJS export names for ESM import in node:
341
+ 0 && (module.exports = {
342
+ StandardTciMeterAdapter,
343
+ TciMeterStreamSession,
344
+ UNKNOWN_TCI_METER_CAPABILITIES,
345
+ cloneMeterCapabilities,
346
+ createUnknownTciMeterAdapter
347
+ });
348
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/meter/index.ts","../../src/meter/types.ts","../../src/meter/adapters.ts","../../src/meter/TciMeterStreamSession.ts","../../src/errors.ts"],"sourcesContent":["export * from './types.js';\nexport * from './adapters.js';\nexport * from './TciMeterStreamSession.js';\n","import type { TciCommand } from '../protocol/index.js';\n\nexport type TciMeterSupport =\n | 'unknown'\n | 'declared'\n | 'acknowledged'\n | 'observed'\n | 'unsupported';\n\nexport interface TciMeterCapabilities {\n rxLevel: TciMeterSupport;\n rxAverageLevel: TciMeterSupport;\n rxPeakBin: TciMeterSupport;\n txMicLevel: TciMeterSupport;\n txRmsPower: TciMeterSupport;\n txPeakPower: TciMeterSupport;\n txSwr: TciMeterSupport;\n txAlcDbfs: TciMeterSupport;\n}\n\nexport type TciRxMeterSource = 'rx_sensors' | 'rx_channel_sensors' | 'rx_channel_sensors_ex';\n\nexport interface TciRxMeterFrame {\n receiver: number;\n channel: number;\n levelDbm: number;\n averageLevelDbm?: number;\n peakBinDbm?: number;\n source: TciRxMeterSource;\n receivedAtMs: number;\n extraArgs?: readonly string[];\n}\n\nexport interface TciTxMeterFrame {\n trx: number;\n micLevelDbm?: number;\n rmsPowerWatts?: number;\n peakPowerWatts?: number;\n swr?: number;\n alc?: { value: number; unit: 'dbfs' | 'percent' };\n receivedAtMs: number;\n extraArgs?: readonly string[];\n}\n\nexport interface TciMeterStreamOptions {\n receiver?: number;\n channel?: number;\n trx?: number;\n rx?: boolean;\n tx?: boolean;\n intervalMs?: number;\n}\n\nexport interface TciMeterInterval {\n requestedMs: number;\n appliedMs?: number;\n}\n\nexport interface TciMeterCommand {\n name: string;\n args: readonly unknown[];\n}\n\nexport type TciMeterDecodedFrame =\n | { kind: 'rx'; frame: TciRxMeterFrame }\n | { kind: 'tx'; frame: TciTxMeterFrame };\n\nexport interface TciMeterDecodeResult {\n decoded?: TciMeterDecodedFrame;\n issue?: string;\n}\n\nexport interface TciMeterAdapter {\n readonly declaredCapabilities: TciMeterCapabilities;\n normalizeInterval(intervalMs: number): TciMeterInterval;\n buildEnableCommand(kind: 'rx' | 'tx', enabled: boolean, intervalMs: number): TciMeterCommand;\n decode(command: TciCommand, receivedAtMs: number): TciMeterDecodeResult | undefined;\n}\n\nexport const UNKNOWN_TCI_METER_CAPABILITIES: TciMeterCapabilities = {\n rxLevel: 'unknown',\n rxAverageLevel: 'unknown',\n rxPeakBin: 'unknown',\n txMicLevel: 'unknown',\n txRmsPower: 'unknown',\n txPeakPower: 'unknown',\n txSwr: 'unknown',\n txAlcDbfs: 'unknown',\n};\n\nexport function cloneMeterCapabilities(capabilities: TciMeterCapabilities): TciMeterCapabilities {\n return { ...capabilities };\n}\n","import type { TciCommand } from '../protocol/index.js';\nimport {\n cloneMeterCapabilities,\n UNKNOWN_TCI_METER_CAPABILITIES,\n type TciMeterAdapter,\n type TciMeterCapabilities,\n type TciMeterDecodeResult,\n type TciMeterInterval,\n type TciRxMeterFrame,\n type TciTxMeterFrame,\n} from './types.js';\n\ninterface StandardTciMeterAdapterOptions {\n capabilities?: Partial<TciMeterCapabilities>;\n interval?: { minMs?: number; maxMs?: number; fixedMs?: number; reportsApplied?: boolean };\n supportsRxExtended?: boolean;\n txAlcUnit?: 'dbfs' | 'percent';\n}\n\nexport class StandardTciMeterAdapter implements TciMeterAdapter {\n readonly declaredCapabilities: TciMeterCapabilities;\n private readonly options: StandardTciMeterAdapterOptions;\n\n constructor(options: StandardTciMeterAdapterOptions = {}) {\n this.options = options;\n this.declaredCapabilities = {\n ...UNKNOWN_TCI_METER_CAPABILITIES,\n rxLevel: 'declared',\n txMicLevel: 'declared',\n txRmsPower: 'declared',\n txPeakPower: 'declared',\n txSwr: 'declared',\n rxAverageLevel: options.supportsRxExtended ? 'declared' : 'unknown',\n rxPeakBin: options.supportsRxExtended ? 'declared' : 'unknown',\n txAlcDbfs: options.txAlcUnit === 'dbfs' ? 'declared' : 'unknown',\n ...options.capabilities,\n };\n }\n\n normalizeInterval(intervalMs: number): TciMeterInterval {\n const requestedMs = Math.round(intervalMs);\n if (this.options.interval?.fixedMs !== undefined) {\n return { requestedMs, appliedMs: this.options.interval.fixedMs };\n }\n const minMs = this.options.interval?.minMs ?? requestedMs;\n const maxMs = this.options.interval?.maxMs ?? requestedMs;\n const normalized = Math.max(minMs, Math.min(maxMs, requestedMs));\n return {\n requestedMs,\n appliedMs: this.options.interval?.reportsApplied === false ? undefined : normalized,\n };\n }\n\n buildEnableCommand(kind: 'rx' | 'tx', enabled: boolean, intervalMs: number) {\n return {\n name: kind === 'rx' ? 'RX_SENSORS_ENABLE' : 'TX_SENSORS_ENABLE',\n args: enabled ? [true, intervalMs] : [false],\n };\n }\n\n decode(command: TciCommand, receivedAtMs: number): TciMeterDecodeResult | undefined {\n switch (command.name) {\n case 'rx_sensors':\n return decodeRx(command, receivedAtMs, 'rx_sensors');\n case 'rx_channel_sensors':\n return decodeRx(command, receivedAtMs, 'rx_channel_sensors');\n case 'rx_channel_sensors_ex':\n return decodeRx(command, receivedAtMs, 'rx_channel_sensors_ex');\n case 'tx_sensors':\n return decodeTx(command, receivedAtMs, this.options.txAlcUnit);\n default:\n return undefined;\n }\n }\n}\n\nexport function createUnknownTciMeterAdapter(): TciMeterAdapter {\n return new StandardTciMeterAdapter({\n capabilities: cloneMeterCapabilities(UNKNOWN_TCI_METER_CAPABILITIES),\n interval: { reportsApplied: false },\n });\n}\n\nfunction decodeRx(\n command: TciCommand,\n receivedAtMs: number,\n source: TciRxMeterFrame['source'],\n): TciMeterDecodeResult {\n const receiver = integer(command.args[0]);\n const hasChannel = source !== 'rx_sensors';\n const channel = hasChannel ? integer(command.args[1]) : 0;\n const levelIndex = hasChannel ? 2 : 1;\n const levelDbm = finite(command.args[levelIndex]);\n if (receiver === undefined || receiver < 0 || channel === undefined || channel < 0 || levelDbm === undefined) {\n return { issue: `Invalid ${command.originalName} meter frame: ${command.raw}` };\n }\n\n const frame: TciRxMeterFrame = { receiver, channel, levelDbm, source, receivedAtMs };\n if (source === 'rx_channel_sensors_ex') {\n const averageLevelDbm = finite(command.args[3]);\n const peakBinDbm = finite(command.args[4]);\n if (averageLevelDbm === undefined || peakBinDbm === undefined) {\n return { issue: `Invalid ${command.originalName} extended meter frame: ${command.raw}` };\n }\n frame.averageLevelDbm = averageLevelDbm;\n frame.peakBinDbm = peakBinDbm;\n if (command.args.length > 5) frame.extraArgs = command.args.slice(5);\n } else if (command.args.length > levelIndex + 1) {\n frame.extraArgs = command.args.slice(levelIndex + 1);\n }\n return { decoded: { kind: 'rx', frame } };\n}\n\nfunction decodeTx(\n command: TciCommand,\n receivedAtMs: number,\n alcUnit?: 'dbfs' | 'percent',\n): TciMeterDecodeResult {\n const trx = integer(command.args[0]);\n if (trx === undefined || trx < 0) {\n return { issue: `Invalid ${command.originalName} transmitter index: ${command.raw}` };\n }\n\n const micLevelDbm = optionalFinite(command.args[1]);\n const rmsPowerWatts = optionalFinite(command.args[2]);\n const peakPowerWatts = optionalFinite(command.args[3]);\n const swr = optionalFinite(command.args[4]);\n const alcValue = alcUnit ? optionalFinite(command.args[5]) : undefined;\n if (micLevelDbm.invalid || rmsPowerWatts.invalid || peakPowerWatts.invalid || swr.invalid || alcValue?.invalid) {\n return { issue: `Invalid ${command.originalName} numeric meter frame: ${command.raw}` };\n }\n if ((rmsPowerWatts.value !== undefined && rmsPowerWatts.value < 0)\n || (peakPowerWatts.value !== undefined && peakPowerWatts.value < 0)\n || (swr.value !== undefined && swr.value < 1)) {\n return { issue: `Out-of-range ${command.originalName} meter frame: ${command.raw}` };\n }\n if (micLevelDbm.value === undefined && rmsPowerWatts.value === undefined\n && peakPowerWatts.value === undefined && swr.value === undefined && alcValue?.value === undefined) {\n return { issue: `Empty ${command.originalName} meter frame: ${command.raw}` };\n }\n\n const frame: TciTxMeterFrame = {\n trx,\n micLevelDbm: micLevelDbm.value,\n rmsPowerWatts: rmsPowerWatts.value,\n peakPowerWatts: peakPowerWatts.value,\n swr: swr.value,\n receivedAtMs,\n };\n if (alcUnit && alcValue?.value !== undefined) frame.alc = { value: alcValue.value, unit: alcUnit };\n const knownArgs = alcUnit ? 6 : 5;\n if (command.args.length > knownArgs) frame.extraArgs = command.args.slice(knownArgs);\n return { decoded: { kind: 'tx', frame } };\n}\n\nfunction finite(value: string | undefined): number | undefined {\n if (value === undefined || value === '') return undefined;\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : undefined;\n}\n\nfunction integer(value: string | undefined): number | undefined {\n const parsed = finite(value);\n return parsed !== undefined && Number.isInteger(parsed) ? parsed : undefined;\n}\n\nfunction optionalFinite(value: string | undefined): { value?: number; invalid: boolean } {\n if (value === undefined || value === '') return { invalid: false };\n const parsed = Number(value);\n return Number.isFinite(parsed) ? { value: parsed, invalid: false } : { invalid: true };\n}\n","import { EventEmitter } from 'eventemitter3';\nimport { TciError } from '../errors.js';\nimport type { TciCommand } from '../protocol/index.js';\nimport {\n cloneMeterCapabilities,\n type TciMeterAdapter,\n type TciMeterCapabilities,\n type TciMeterSupport,\n type TciRxMeterFrame,\n type TciTxMeterFrame,\n} from './types.js';\n\nconst RX_COALESCE_MS = 20;\n\nexport interface TciMeterStreamEvents {\n rxFrame: (frame: TciRxMeterFrame) => void;\n txFrame: (frame: TciTxMeterFrame) => void;\n capabilitiesChanged: (capabilities: TciMeterCapabilities) => void;\n error: (error: TciError) => void;\n closed: () => void;\n}\n\ninterface TciMeterStreamCallbacks {\n close: () => Promise<void>;\n}\n\ninterface PendingRxFrame {\n frame: TciRxMeterFrame;\n timer: NodeJS.Timeout;\n}\n\nexport class TciMeterStreamSession extends EventEmitter<TciMeterStreamEvents> {\n readonly receiver: number;\n readonly channel: number;\n readonly trx: number;\n readonly requestedIntervalMs: number;\n readonly appliedIntervalMs?: number;\n readonly rxEnabled: boolean;\n readonly txEnabled: boolean;\n\n private readonly adapter: TciMeterAdapter;\n private readonly callbacks: TciMeterStreamCallbacks;\n private capabilities: TciMeterCapabilities;\n private readonly pendingRx = new Map<string, PendingRxFrame>();\n private closed = false;\n\n constructor(options: {\n receiver: number;\n channel: number;\n trx: number;\n requestedIntervalMs: number;\n appliedIntervalMs?: number;\n rxEnabled: boolean;\n txEnabled: boolean;\n adapter: TciMeterAdapter;\n callbacks: TciMeterStreamCallbacks;\n }) {\n super();\n this.receiver = options.receiver;\n this.channel = options.channel;\n this.trx = options.trx;\n this.requestedIntervalMs = options.requestedIntervalMs;\n this.appliedIntervalMs = options.appliedIntervalMs;\n this.rxEnabled = options.rxEnabled;\n this.txEnabled = options.txEnabled;\n this.adapter = options.adapter;\n this.callbacks = options.callbacks;\n this.capabilities = cloneMeterCapabilities(options.adapter.declaredCapabilities);\n }\n\n getCapabilities(): TciMeterCapabilities {\n return cloneMeterCapabilities(this.capabilities);\n }\n\n async close(): Promise<void> {\n if (this.closed) return;\n this.closed = true;\n this.clearPendingRx();\n try {\n await this.callbacks.close();\n } finally {\n this.emit('closed');\n this.removeAllListeners();\n }\n }\n\n _acceptCommand(command: TciCommand, receivedAtMs: number): void {\n if (this.closed) return;\n this.acceptEnableAcknowledgement(command);\n const result = this.adapter.decode(command, receivedAtMs);\n if (!result) return;\n if (result.issue) {\n this.emit('error', new TciError('protocol-error', result.issue));\n return;\n }\n if (result.decoded?.kind === 'rx') this.acceptRxFrame(result.decoded.frame);\n if (result.decoded?.kind === 'tx') this.acceptTxFrame(result.decoded.frame);\n }\n\n _fail(error: TciError): void {\n if (this.closed) return;\n this.closed = true;\n this.clearPendingRx();\n this.emit('error', error);\n this.emit('closed');\n this.removeAllListeners();\n }\n\n private acceptRxFrame(frame: TciRxMeterFrame): void {\n if (!this.rxEnabled || frame.receiver !== this.receiver || frame.channel !== this.channel) return;\n this.observe('rxLevel');\n if (frame.averageLevelDbm !== undefined) this.observe('rxAverageLevel');\n if (frame.peakBinDbm !== undefined) this.observe('rxPeakBin');\n\n const key = `${frame.receiver}:${frame.channel}`;\n const pending = this.pendingRx.get(key);\n if (pending) {\n const sameReading = Math.abs(pending.frame.levelDbm - frame.levelDbm) < 0.05;\n if (sameReading && rxPriority(frame) >= rxPriority(pending.frame)) {\n clearTimeout(pending.timer);\n this.pendingRx.delete(key);\n } else if (sameReading) {\n return;\n } else {\n this.flushRx(key, pending);\n }\n }\n const timer = setTimeout(() => {\n const current = this.pendingRx.get(key);\n if (current?.frame === frame) this.flushRx(key, current);\n }, RX_COALESCE_MS);\n this.pendingRx.set(key, { frame, timer });\n }\n\n private acceptTxFrame(frame: TciTxMeterFrame): void {\n if (!this.txEnabled || frame.trx !== this.trx) return;\n if (frame.micLevelDbm !== undefined) this.observe('txMicLevel');\n if (frame.rmsPowerWatts !== undefined) this.observe('txRmsPower');\n if (frame.peakPowerWatts !== undefined) this.observe('txPeakPower');\n if (frame.swr !== undefined) this.observe('txSwr');\n if (frame.alc?.unit === 'dbfs') this.observe('txAlcDbfs');\n this.emit('txFrame', frame);\n }\n\n private acceptEnableAcknowledgement(command: TciCommand): void {\n const enabled = command.args[0]?.toLowerCase();\n if (enabled !== 'true' && enabled !== '1' && enabled !== 'on') return;\n if (command.name === 'rx_sensors_enable' && this.rxEnabled) {\n this.acknowledge(['rxLevel']);\n }\n if (command.name === 'tx_sensors_enable' && this.txEnabled) {\n this.acknowledge(['txMicLevel', 'txRmsPower', 'txPeakPower', 'txSwr']);\n }\n }\n\n private acknowledge(keys: Array<keyof TciMeterCapabilities>): void {\n let changed = false;\n for (const key of keys) {\n if (supportRank(this.capabilities[key]) < supportRank('acknowledged')) {\n this.capabilities[key] = 'acknowledged';\n changed = true;\n }\n }\n if (changed) this.emit('capabilitiesChanged', this.getCapabilities());\n }\n\n private observe(key: keyof TciMeterCapabilities): void {\n if (this.capabilities[key] === 'observed') return;\n this.capabilities[key] = 'observed';\n this.emit('capabilitiesChanged', this.getCapabilities());\n }\n\n private flushRx(key: string, pending: PendingRxFrame): void {\n clearTimeout(pending.timer);\n if (this.pendingRx.get(key) === pending) this.pendingRx.delete(key);\n this.emit('rxFrame', pending.frame);\n }\n\n private clearPendingRx(): void {\n for (const pending of this.pendingRx.values()) clearTimeout(pending.timer);\n this.pendingRx.clear();\n }\n}\n\nfunction rxPriority(frame: TciRxMeterFrame): number {\n if (frame.source === 'rx_channel_sensors_ex') return 3;\n if (frame.source === 'rx_channel_sensors') return 2;\n return 1;\n}\n\nfunction supportRank(value: TciMeterSupport): number {\n switch (value) {\n case 'unsupported': return -1;\n case 'unknown': return 0;\n case 'declared': return 1;\n case 'acknowledged': return 2;\n case 'observed': return 3;\n }\n}\n","export type TciErrorCode =\n | 'connect-timeout'\n | 'handshake-timeout'\n | 'invalid-handshake'\n | 'unknown-dialect'\n | 'command-timeout'\n | 'not-connected'\n | 'disconnected'\n | 'protocol-error'\n | 'invalid-frame'\n | 'cancelled';\n\nexport class TciError extends Error {\n readonly code: TciErrorCode;\n readonly details?: unknown;\n\n constructor(code: TciErrorCode, message: string, details?: unknown) {\n super(message);\n this.name = 'TciError';\n this.code = code;\n this.details = details;\n }\n}\n\nexport function toTciError(error: unknown, fallbackCode: TciErrorCode = 'protocol-error'): TciError {\n if (error instanceof TciError) {\n return error;\n }\n if (error instanceof Error) {\n return new TciError(fallbackCode, error.message, error);\n }\n return new TciError(fallbackCode, String(error), error);\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,78 @@
1
+ import { b as TciMeterAdapter, T as TciMeterCapabilities, f as TciMeterInterval, d as TciMeterDecodeResult, h as TciRxMeterFrame, j as TciTxMeterFrame } from '../types-C4MtLKoy.cjs';
2
+ export { c as TciMeterCommand, e as TciMeterDecodedFrame, a as TciMeterStreamOptions, g as TciMeterSupport, i as TciRxMeterSource, U as UNKNOWN_TCI_METER_CAPABILITIES, k as cloneMeterCapabilities } from '../types-C4MtLKoy.cjs';
3
+ import { T as TciCommand } from '../text-BwCWY1k1.cjs';
4
+ import { EventEmitter } from 'eventemitter3';
5
+ import { T as TciError } from '../errors-CT3b8LLw.cjs';
6
+
7
+ interface StandardTciMeterAdapterOptions {
8
+ capabilities?: Partial<TciMeterCapabilities>;
9
+ interval?: {
10
+ minMs?: number;
11
+ maxMs?: number;
12
+ fixedMs?: number;
13
+ reportsApplied?: boolean;
14
+ };
15
+ supportsRxExtended?: boolean;
16
+ txAlcUnit?: 'dbfs' | 'percent';
17
+ }
18
+ declare class StandardTciMeterAdapter implements TciMeterAdapter {
19
+ readonly declaredCapabilities: TciMeterCapabilities;
20
+ private readonly options;
21
+ constructor(options?: StandardTciMeterAdapterOptions);
22
+ normalizeInterval(intervalMs: number): TciMeterInterval;
23
+ buildEnableCommand(kind: 'rx' | 'tx', enabled: boolean, intervalMs: number): {
24
+ name: string;
25
+ args: (number | boolean)[];
26
+ };
27
+ decode(command: TciCommand, receivedAtMs: number): TciMeterDecodeResult | undefined;
28
+ }
29
+ declare function createUnknownTciMeterAdapter(): TciMeterAdapter;
30
+
31
+ interface TciMeterStreamEvents {
32
+ rxFrame: (frame: TciRxMeterFrame) => void;
33
+ txFrame: (frame: TciTxMeterFrame) => void;
34
+ capabilitiesChanged: (capabilities: TciMeterCapabilities) => void;
35
+ error: (error: TciError) => void;
36
+ closed: () => void;
37
+ }
38
+ interface TciMeterStreamCallbacks {
39
+ close: () => Promise<void>;
40
+ }
41
+ declare class TciMeterStreamSession extends EventEmitter<TciMeterStreamEvents> {
42
+ readonly receiver: number;
43
+ readonly channel: number;
44
+ readonly trx: number;
45
+ readonly requestedIntervalMs: number;
46
+ readonly appliedIntervalMs?: number;
47
+ readonly rxEnabled: boolean;
48
+ readonly txEnabled: boolean;
49
+ private readonly adapter;
50
+ private readonly callbacks;
51
+ private capabilities;
52
+ private readonly pendingRx;
53
+ private closed;
54
+ constructor(options: {
55
+ receiver: number;
56
+ channel: number;
57
+ trx: number;
58
+ requestedIntervalMs: number;
59
+ appliedIntervalMs?: number;
60
+ rxEnabled: boolean;
61
+ txEnabled: boolean;
62
+ adapter: TciMeterAdapter;
63
+ callbacks: TciMeterStreamCallbacks;
64
+ });
65
+ getCapabilities(): TciMeterCapabilities;
66
+ close(): Promise<void>;
67
+ _acceptCommand(command: TciCommand, receivedAtMs: number): void;
68
+ _fail(error: TciError): void;
69
+ private acceptRxFrame;
70
+ private acceptTxFrame;
71
+ private acceptEnableAcknowledgement;
72
+ private acknowledge;
73
+ private observe;
74
+ private flushRx;
75
+ private clearPendingRx;
76
+ }
77
+
78
+ export { StandardTciMeterAdapter, TciMeterAdapter, TciMeterCapabilities, TciMeterDecodeResult, TciMeterInterval, type TciMeterStreamEvents, TciMeterStreamSession, TciRxMeterFrame, TciTxMeterFrame, createUnknownTciMeterAdapter };
@@ -0,0 +1,78 @@
1
+ import { b as TciMeterAdapter, T as TciMeterCapabilities, f as TciMeterInterval, d as TciMeterDecodeResult, h as TciRxMeterFrame, j as TciTxMeterFrame } from '../types-C0qVJVSO.js';
2
+ export { c as TciMeterCommand, e as TciMeterDecodedFrame, a as TciMeterStreamOptions, g as TciMeterSupport, i as TciRxMeterSource, U as UNKNOWN_TCI_METER_CAPABILITIES, k as cloneMeterCapabilities } from '../types-C0qVJVSO.js';
3
+ import { T as TciCommand } from '../text-BwCWY1k1.js';
4
+ import { EventEmitter } from 'eventemitter3';
5
+ import { T as TciError } from '../errors-CT3b8LLw.js';
6
+
7
+ interface StandardTciMeterAdapterOptions {
8
+ capabilities?: Partial<TciMeterCapabilities>;
9
+ interval?: {
10
+ minMs?: number;
11
+ maxMs?: number;
12
+ fixedMs?: number;
13
+ reportsApplied?: boolean;
14
+ };
15
+ supportsRxExtended?: boolean;
16
+ txAlcUnit?: 'dbfs' | 'percent';
17
+ }
18
+ declare class StandardTciMeterAdapter implements TciMeterAdapter {
19
+ readonly declaredCapabilities: TciMeterCapabilities;
20
+ private readonly options;
21
+ constructor(options?: StandardTciMeterAdapterOptions);
22
+ normalizeInterval(intervalMs: number): TciMeterInterval;
23
+ buildEnableCommand(kind: 'rx' | 'tx', enabled: boolean, intervalMs: number): {
24
+ name: string;
25
+ args: (number | boolean)[];
26
+ };
27
+ decode(command: TciCommand, receivedAtMs: number): TciMeterDecodeResult | undefined;
28
+ }
29
+ declare function createUnknownTciMeterAdapter(): TciMeterAdapter;
30
+
31
+ interface TciMeterStreamEvents {
32
+ rxFrame: (frame: TciRxMeterFrame) => void;
33
+ txFrame: (frame: TciTxMeterFrame) => void;
34
+ capabilitiesChanged: (capabilities: TciMeterCapabilities) => void;
35
+ error: (error: TciError) => void;
36
+ closed: () => void;
37
+ }
38
+ interface TciMeterStreamCallbacks {
39
+ close: () => Promise<void>;
40
+ }
41
+ declare class TciMeterStreamSession extends EventEmitter<TciMeterStreamEvents> {
42
+ readonly receiver: number;
43
+ readonly channel: number;
44
+ readonly trx: number;
45
+ readonly requestedIntervalMs: number;
46
+ readonly appliedIntervalMs?: number;
47
+ readonly rxEnabled: boolean;
48
+ readonly txEnabled: boolean;
49
+ private readonly adapter;
50
+ private readonly callbacks;
51
+ private capabilities;
52
+ private readonly pendingRx;
53
+ private closed;
54
+ constructor(options: {
55
+ receiver: number;
56
+ channel: number;
57
+ trx: number;
58
+ requestedIntervalMs: number;
59
+ appliedIntervalMs?: number;
60
+ rxEnabled: boolean;
61
+ txEnabled: boolean;
62
+ adapter: TciMeterAdapter;
63
+ callbacks: TciMeterStreamCallbacks;
64
+ });
65
+ getCapabilities(): TciMeterCapabilities;
66
+ close(): Promise<void>;
67
+ _acceptCommand(command: TciCommand, receivedAtMs: number): void;
68
+ _fail(error: TciError): void;
69
+ private acceptRxFrame;
70
+ private acceptTxFrame;
71
+ private acceptEnableAcknowledgement;
72
+ private acknowledge;
73
+ private observe;
74
+ private flushRx;
75
+ private clearPendingRx;
76
+ }
77
+
78
+ export { StandardTciMeterAdapter, TciMeterAdapter, TciMeterCapabilities, TciMeterDecodeResult, TciMeterInterval, type TciMeterStreamEvents, TciMeterStreamSession, TciRxMeterFrame, TciTxMeterFrame, createUnknownTciMeterAdapter };