@international-iot-association/plugin-contracts 3.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/index.cjs +421 -0
- package/dist/index.d.cts +1931 -0
- package/dist/index.d.ts +1931 -0
- package/dist/index.js +369 -0
- package/package.json +41 -0
package/README.md
ADDED
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,421 @@
|
|
|
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/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
CURRENT_METER_LOGICAL: () => CURRENT_METER_LOGICAL,
|
|
24
|
+
DIALOG_READ_CONTENT_MAX_BYTES: () => DIALOG_READ_CONTENT_MAX_BYTES,
|
|
25
|
+
DIALOG_SAVE_CONTENT_MAX_BYTES: () => DIALOG_SAVE_CONTENT_MAX_BYTES,
|
|
26
|
+
DUT_LOGICAL: () => DUT_LOGICAL,
|
|
27
|
+
FIXTURE_BAUD_RATE: () => FIXTURE_BAUD_RATE,
|
|
28
|
+
FIXTURE_BOARD_ADDRESS: () => FIXTURE_BOARD_ADDRESS,
|
|
29
|
+
FIXTURE_LOGICAL: () => FIXTURE_LOGICAL,
|
|
30
|
+
KNOWN_T9W_DUT_ENDPOINT: () => KNOWN_T9W_DUT_ENDPOINT,
|
|
31
|
+
KNOWN_T9W_FIXTURE_ENDPOINT: () => KNOWN_T9W_FIXTURE_ENDPOINT,
|
|
32
|
+
T9W_DUT_BAUD_RATE: () => T9W_DUT_BAUD_RATE,
|
|
33
|
+
allSerialPortPaths: () => allSerialPortPaths,
|
|
34
|
+
asChannelStatus: () => asChannelStatus,
|
|
35
|
+
asResponseObject: () => asResponseObject,
|
|
36
|
+
asSerialDeviceSuggestions: () => asSerialDeviceSuggestions,
|
|
37
|
+
asSerialPorts: () => asSerialPorts,
|
|
38
|
+
buildDutRawTextSerialConfig: () => buildDutRawTextSerialConfig,
|
|
39
|
+
buildFixtureSerialConfig: () => buildFixtureSerialConfig,
|
|
40
|
+
chooseFixtureAndDutPortPairs: () => chooseFixtureAndDutPortPairs,
|
|
41
|
+
chooseFixtureAndDutPorts: () => chooseFixtureAndDutPorts,
|
|
42
|
+
isFixtureReadyEvent: () => isFixtureReadyEvent,
|
|
43
|
+
looksLikeUsbSerialPort: () => looksLikeUsbSerialPort,
|
|
44
|
+
parseOperatorSignals: () => parseOperatorSignals,
|
|
45
|
+
preferredSerialPathFromPort: () => preferredSerialPathFromPort,
|
|
46
|
+
preferredSerialPortPath: () => preferredSerialPortPath,
|
|
47
|
+
serialEndpointId: () => serialEndpointId,
|
|
48
|
+
serialPortHasEndpoint: () => serialPortHasEndpoint
|
|
49
|
+
});
|
|
50
|
+
module.exports = __toCommonJS(index_exports);
|
|
51
|
+
|
|
52
|
+
// src/fixtureControl.ts
|
|
53
|
+
var FIXTURE_LOGICAL = "serial.fixture";
|
|
54
|
+
var DUT_LOGICAL = "serial.dut";
|
|
55
|
+
var CURRENT_METER_LOGICAL = "instrument.current-meter";
|
|
56
|
+
var FIXTURE_BOARD_ADDRESS = 250;
|
|
57
|
+
var FIXTURE_BAUD_RATE = 115200;
|
|
58
|
+
var T9W_DUT_BAUD_RATE = 460800;
|
|
59
|
+
var KNOWN_T9W_FIXTURE_ENDPOINT = "58b20024743";
|
|
60
|
+
var KNOWN_T9W_DUT_ENDPOINT = "58b20024741";
|
|
61
|
+
function isFixtureReadyEvent(event) {
|
|
62
|
+
return event.fixtureReady === true || event.ok === true && event.functionCode === 6 && event.register === 201 && event.value === 1;
|
|
63
|
+
}
|
|
64
|
+
function preferredSerialPortPath(path) {
|
|
65
|
+
if (path.includes("/dev/tty.")) return path.replace("/dev/tty.", "/dev/cu.");
|
|
66
|
+
return path;
|
|
67
|
+
}
|
|
68
|
+
function allSerialPortPaths(port) {
|
|
69
|
+
return [port.path, ...port.aliases ?? []];
|
|
70
|
+
}
|
|
71
|
+
function serialEndpointId(path) {
|
|
72
|
+
const name = path.split("/").pop()?.toLowerCase() ?? "";
|
|
73
|
+
return name.match(/(?:wchusbserial|usbserial|usbmodem)([a-z0-9]+)$/)?.[1] ?? null;
|
|
74
|
+
}
|
|
75
|
+
function serialPortHasEndpoint(port, endpoint) {
|
|
76
|
+
return allSerialPortPaths(port).some(
|
|
77
|
+
(path) => serialEndpointId(path) === endpoint.toLowerCase()
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
function preferredSerialPathFromPort(port) {
|
|
81
|
+
return allSerialPortPaths(port).sort((a, b) => serialPathPreference(b) - serialPathPreference(a))[0] ?? port.path;
|
|
82
|
+
}
|
|
83
|
+
function looksLikeUsbSerialPort(port) {
|
|
84
|
+
const pathBlob = [port.path, ...port.aliases ?? []].filter(Boolean).join(" ").toLowerCase();
|
|
85
|
+
if (/(?:^|[\s\\/])com\d+\b/i.test(pathBlob) || /^com\d+$/i.test(port.path.trim())) {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
const text = [
|
|
89
|
+
pathBlob,
|
|
90
|
+
port.manufacturer,
|
|
91
|
+
port.friendlyName,
|
|
92
|
+
port.serialNumber,
|
|
93
|
+
port.vendorId,
|
|
94
|
+
port.productId,
|
|
95
|
+
port.pnpId,
|
|
96
|
+
port.locationId
|
|
97
|
+
].filter(Boolean).join(" ").toLowerCase().replace(/[\s_\-]+/g, "");
|
|
98
|
+
if (text.includes("wch") || text.includes("usbserial") || text.includes("usbmodem") || text.includes("ch340") || text.includes("ch341") || text.includes("ch910") || text.includes("cp210") || text.includes("ftdi") || text.includes("ft232") || text.includes("pl2303")) {
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
const vid = (port.vendorId ?? "").toLowerCase().replace(/^0x/, "");
|
|
102
|
+
if (vid === "1a86" || vid === "10c4" || vid === "0403" || vid === "067b") {
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
if (text.includes("vid_1a86") || text.includes("vid_10c4") || text.includes("vid_0403") || text.includes("vid_067b")) {
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
function chooseFixtureAndDutPorts(ports, suggestions = [], options = {}) {
|
|
111
|
+
const { pairs, reasons } = chooseFixtureAndDutPortPairs(ports, suggestions, {
|
|
112
|
+
...options,
|
|
113
|
+
count: 1
|
|
114
|
+
});
|
|
115
|
+
const first = pairs[0];
|
|
116
|
+
if (first) return { fixture: first.fixture, dut: first.dut, reasons };
|
|
117
|
+
return { reasons };
|
|
118
|
+
}
|
|
119
|
+
function chooseFixtureAndDutPortPairs(ports, suggestions = [], options = {}) {
|
|
120
|
+
const count = Math.max(1, Math.floor(options.count ?? 1));
|
|
121
|
+
const allowKnown = options.allowKnownEndpointFallback !== false;
|
|
122
|
+
const reasons = [];
|
|
123
|
+
const pairs = [];
|
|
124
|
+
const used = /* @__PURE__ */ new Set();
|
|
125
|
+
for (const path of options.excludePaths ?? []) markPathsUsed(used, path);
|
|
126
|
+
const suggestedPorts = suggestions.filter(
|
|
127
|
+
(item) => item.kind === "fixture-modbus" || item.role === "fixture" || item.role === "dut"
|
|
128
|
+
).map((item) => item.port);
|
|
129
|
+
const candidates = mergePortLists(
|
|
130
|
+
ports.filter(looksLikeUsbSerialPort),
|
|
131
|
+
suggestedPorts.filter((port) => ports.some((p) => samePhysicalPort(p, port)))
|
|
132
|
+
);
|
|
133
|
+
const available = () => candidates.filter((port) => !isPortUsed(used, port));
|
|
134
|
+
const availableAll = () => ports.filter((port) => !isPortUsed(used, port));
|
|
135
|
+
const protocolFixtures = suggestions.filter((item) => item.kind === "fixture-modbus").sort((a, b) => b.confidence - a.confidence);
|
|
136
|
+
for (const detected of protocolFixtures) {
|
|
137
|
+
if (pairs.length >= count) break;
|
|
138
|
+
const fixture = findPortInList(available(), detected.port) ?? findPortInList(availableAll(), detected.port);
|
|
139
|
+
if (!fixture) {
|
|
140
|
+
reasons.push(
|
|
141
|
+
`\u534F\u8BAE\u547D\u4E2D\u5939\u5177 ${detected.port.path}\uFF08\u7F6E\u4FE1\u5EA6 ${detected.confidence}%\uFF09\uFF0C\u4F46 listPorts \u4E2D\u65E0\u5BF9\u5E94\u7269\u7406\u53E3\uFF08\u53EF\u80FD\u5DF2\u62D4\u51FA\u6216\u8DEF\u5F84\u4E0D\u4E00\u81F4\uFF09`
|
|
142
|
+
);
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
const pool = mergePortLists(available(), availableAll());
|
|
146
|
+
const pairedDutPath = detected.pairedWith;
|
|
147
|
+
const pairedDut = pairedDutPath ? pool.find(
|
|
148
|
+
(port) => allSerialPortPaths(port).some(
|
|
149
|
+
(p) => p.toLowerCase() === pairedDutPath.toLowerCase()
|
|
150
|
+
)
|
|
151
|
+
) : void 0;
|
|
152
|
+
const roleDut = suggestions.filter((item) => item.role === "dut" && !isPortUsed(used, item.port)).sort((a, b) => b.confidence - a.confidence).map((item) => findPortInList(pool, item.port)).find((port) => Boolean(port));
|
|
153
|
+
const dut = pairedDut ?? roleDut ?? chooseDutForFixture(fixture, pool) ?? pickSoleOtherPort(fixture, pool);
|
|
154
|
+
if (!dut) {
|
|
155
|
+
reasons.push(
|
|
156
|
+
`\u534F\u8BAE\u786E\u8BA4\u5939\u5177 ${preferredSerialPathFromPort(fixture)}\uFF08\u7F6E\u4FE1\u5EA6 ${detected.confidence}%\uFF09\uFF0C\u4F46\u672A\u627E\u5230\u53EF\u7528 DUT \u8F6C\u53D1\u53E3`
|
|
157
|
+
);
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
pairs.push({ fixture, dut });
|
|
161
|
+
markPortUsed(used, fixture);
|
|
162
|
+
markPortUsed(used, dut);
|
|
163
|
+
reasons.push(
|
|
164
|
+
`Agent \u81EA\u52A8\u63A2\u6D4B\u8BC6\u522B\u5939\u5177\u63A7\u5236\u677F\uFF1A${fixture.path}\uFF0C\u7F6E\u4FE1\u5EA6 ${detected.confidence}%\uFF080xFA \u534F\u8BAE\u63E1\u624B\u6210\u529F\uFF0C\u4E0D\u533A\u5206\u4EA7\u54C1\u578B\u53F7\uFF09`
|
|
165
|
+
);
|
|
166
|
+
reasons.push(
|
|
167
|
+
pairedDut || roleDut ? `\u6839\u636E Agent \u89D2\u8272/\u914D\u5BF9\u5EFA\u8BAE\u9009\u62E9 DUT \u8F6C\u53D1\u7AEF\u53E3\uFF08${preferredSerialPathFromPort(dut)}\uFF09` : `\u6839\u636E Agent \u5939\u5177\u63A2\u6D4B\u7ED3\u679C\u548C\u540C\u65CF USB \u4E32\u53E3\u63A8\u65AD DUT \u8F6C\u53D1\u7AEF\u53E3\uFF08${preferredSerialPathFromPort(dut)}\uFF09`
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
if (pairs.length < count && allowKnown) {
|
|
171
|
+
const fixtureEndpoint = options.fixtureEndpoint === null ? null : options.fixtureEndpoint ?? KNOWN_T9W_FIXTURE_ENDPOINT;
|
|
172
|
+
const dutEndpoint = options.dutEndpoint === null ? null : options.dutEndpoint ?? KNOWN_T9W_DUT_ENDPOINT;
|
|
173
|
+
if (fixtureEndpoint) {
|
|
174
|
+
const fixtureKnown = available().find(
|
|
175
|
+
(port) => serialPortHasEndpoint(port, fixtureEndpoint)
|
|
176
|
+
);
|
|
177
|
+
if (fixtureKnown) {
|
|
178
|
+
const dutKnown = dutEndpoint ? available().find((port) => serialPortHasEndpoint(port, dutEndpoint)) : void 0;
|
|
179
|
+
const dut = dutKnown ?? chooseDutForFixture(fixtureKnown, available());
|
|
180
|
+
if (dut && pairs.length < count) {
|
|
181
|
+
pairs.push({ fixture: fixtureKnown, dut });
|
|
182
|
+
markPortUsed(used, fixtureKnown);
|
|
183
|
+
markPortUsed(used, dut);
|
|
184
|
+
reasons.push(
|
|
185
|
+
`\u7AEF\u70B9\u515C\u5E95\uFF1A\u5939\u5177 ${fixtureEndpoint} \u2192 ${preferredSerialPathFromPort(fixtureKnown)}\uFF08\u534F\u8BAE\u63A2\u6D4B\u672A\u8986\u76D6\u65F6\u7684\u5B9E\u9A8C\u5BA4\u7EBF\u5E8F\uFF09`
|
|
186
|
+
);
|
|
187
|
+
reasons.push(
|
|
188
|
+
dutKnown ? `\u7AEF\u70B9\u515C\u5E95\uFF1ADUT ${dutEndpoint} \u2192 ${preferredSerialPathFromPort(dut)}` : `\u7AEF\u70B9\u515C\u5E95\uFF1ADUT \u540C\u65CF\u63A8\u65AD \u2192 ${preferredSerialPathFromPort(dut)}`
|
|
189
|
+
);
|
|
190
|
+
} else if (!dut) {
|
|
191
|
+
reasons.push(
|
|
192
|
+
`\u7AEF\u70B9\u515C\u5E95\u627E\u5230\u5939\u5177\u7AEF\u70B9 ${fixtureEndpoint}\uFF0C\u4F46\u65E0\u53EF\u7528 DUT \u8F6C\u53D1\u53E3`
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if (pairs.length === 0) {
|
|
199
|
+
reasons.push(
|
|
200
|
+
"\u672A\u627E\u5230\u53EF\u53EF\u9760\u5F52\u7C7B\u7684\u5939\u5177\u53CC\u4E32\u53E3\u5019\u9009\uFF1A\u5939\u5177\u63A7\u5236\u677F\u5FC5\u987B\u901A\u8FC7\u5DF2\u77E5\u7AEF\u70B9\u6216 Modbus \u63A2\u6D4B\u786E\u8BA4\uFF08detectDevices \u2192 fixture-modbus / 0xFA \u534F\u8BAE\u63E1\u624B\uFF09\u3002\u8BF7\u786E\u8BA4 USB \u5DF2\u8FDE\u63A5\u4E14\u672A\u88AB\u5176\u5B83\u8FDB\u7A0B\u5360\u7528\u3002"
|
|
201
|
+
);
|
|
202
|
+
} else if (pairs.length < count) {
|
|
203
|
+
reasons.push(
|
|
204
|
+
`\u4EC5\u5206\u914D\u5230 ${pairs.length}/${count} \u5BF9\u5939\u5177+DUT\uFF1B\u591A\u5E2D\u4F4D\u8BF7\u63A5\u5165\u5BF9\u5E94\u6570\u91CF\u7684\u63A7\u5236\u677F/\u8F6C\u53D1\u53E3`
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
return { pairs, reasons };
|
|
208
|
+
}
|
|
209
|
+
function findPortInList(ports, target) {
|
|
210
|
+
return ports.find((port) => samePhysicalPort(port, target));
|
|
211
|
+
}
|
|
212
|
+
function pathKeys(path) {
|
|
213
|
+
const preferred = preferredSerialPortPath(path).toLowerCase();
|
|
214
|
+
const raw = path.toLowerCase();
|
|
215
|
+
return preferred === raw ? [raw] : [preferred, raw];
|
|
216
|
+
}
|
|
217
|
+
function markPathsUsed(used, path) {
|
|
218
|
+
for (const key of pathKeys(path)) used.add(key);
|
|
219
|
+
}
|
|
220
|
+
function markPortUsed(used, port) {
|
|
221
|
+
for (const path of allSerialPortPaths(port)) markPathsUsed(used, path);
|
|
222
|
+
}
|
|
223
|
+
function isPortUsed(used, port) {
|
|
224
|
+
return allSerialPortPaths(port).some(
|
|
225
|
+
(path) => pathKeys(path).some((key) => used.has(key))
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
function buildFixtureSerialConfig(port, options = {}) {
|
|
229
|
+
return {
|
|
230
|
+
logicalName: options.logicalName ?? FIXTURE_LOGICAL,
|
|
231
|
+
provider: "serial",
|
|
232
|
+
...port ? { port: preferredSerialPortPath(preferredSerialPathFromPort(port)) } : {},
|
|
233
|
+
baudRate: FIXTURE_BAUD_RATE,
|
|
234
|
+
dataBits: 8,
|
|
235
|
+
stopBits: 1,
|
|
236
|
+
parity: "none",
|
|
237
|
+
codec: {
|
|
238
|
+
type: "modbus-rtu",
|
|
239
|
+
deviceAddress: options.boardAddress ?? FIXTURE_BOARD_ADDRESS,
|
|
240
|
+
maxFrameBytes: 256
|
|
241
|
+
},
|
|
242
|
+
timeouts: { openMs: 3e3, responseMs: 2e3, idleFrameMs: 50 },
|
|
243
|
+
signals: { dtr: false, rts: false },
|
|
244
|
+
openStabilizeMs: 200
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
function buildDutRawTextSerialConfig(port, options = {}) {
|
|
248
|
+
return {
|
|
249
|
+
logicalName: options.logicalName ?? DUT_LOGICAL,
|
|
250
|
+
provider: "serial",
|
|
251
|
+
...port ? { port: preferredSerialPortPath(preferredSerialPathFromPort(port)) } : {},
|
|
252
|
+
baudRate: options.baudRate ?? T9W_DUT_BAUD_RATE,
|
|
253
|
+
dataBits: 8,
|
|
254
|
+
stopBits: 1,
|
|
255
|
+
parity: "none",
|
|
256
|
+
codec: {
|
|
257
|
+
type: "raw-text",
|
|
258
|
+
delimiter: "\r\n",
|
|
259
|
+
maxFrameBytes: 8192,
|
|
260
|
+
encoding: "utf8",
|
|
261
|
+
appendDelimiter: true
|
|
262
|
+
},
|
|
263
|
+
timeouts: { openMs: 3e3, responseMs: 1600, idleFrameMs: 80 },
|
|
264
|
+
signals: { dtr: false, rts: false },
|
|
265
|
+
openStabilizeMs: 300
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
function parseOperatorSignals(text) {
|
|
269
|
+
const normalized = normalizeText(text);
|
|
270
|
+
const keys = /* @__PURE__ */ new Set();
|
|
271
|
+
for (const match of normalized.matchAll(/\bkey[_-]?([0-9A-Za-z]+)\s+pressed\b/gi)) {
|
|
272
|
+
if (match[1]) keys.add(match[1]);
|
|
273
|
+
}
|
|
274
|
+
for (const match of normalized.matchAll(/\bkey\s*[=:]\s*([0-9A-Za-z]+)\b/gi)) {
|
|
275
|
+
if (match[1]) keys.add(match[1]);
|
|
276
|
+
}
|
|
277
|
+
for (const match of normalized.matchAll(/\bkey_press_map\s*[=:]\s*(0x[0-9a-f]+|\d+)/gi)) {
|
|
278
|
+
const map = parseIntegerToken(match[1]);
|
|
279
|
+
if (map == null || map === 0) continue;
|
|
280
|
+
for (let bit = 0; bit < 32; bit += 1) {
|
|
281
|
+
if (Math.trunc(map / 2 ** bit) % 2 === 1) keys.add(String(bit + 1));
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
const lower = normalized.toLowerCase();
|
|
285
|
+
const encoderForward = lower.includes("rotate direction is clockwise") || /\b(?:encoder|knob)[_-]?(?:forward|cw|clockwise)\s*[=:]\s*(?:1|true|yes|seen)\b/i.test(
|
|
286
|
+
normalized
|
|
287
|
+
) || /\b(?:encoder|knob)[\s_-]*(?:direction|dir)\s*[=:]\s*(?:clockwise|cw|forward|right)\b/i.test(
|
|
288
|
+
normalized
|
|
289
|
+
);
|
|
290
|
+
const encoderReverse = lower.includes("rotate direction is anti-clockwise") || lower.includes("rotate direction is anticlockwise") || lower.includes("rotate direction is counterclockwise") || /\b(?:ccw|anti-clockwise|anticlockwise|counterclockwise)\b/i.test(normalized) || /\b(?:encoder|knob)[_-]?(?:reverse|ccw|anticlockwise|counterclockwise)\s*[=:]\s*(?:1|true|yes|seen)\b/i.test(
|
|
291
|
+
normalized
|
|
292
|
+
) || /\b(?:encoder|knob)[\s_-]*(?:direction|dir)\s*[=:]\s*(?:anti-clockwise|anticlockwise|counterclockwise|ccw|reverse|left)\b/i.test(
|
|
293
|
+
normalized
|
|
294
|
+
);
|
|
295
|
+
return {
|
|
296
|
+
keys: [...keys],
|
|
297
|
+
encoderForward,
|
|
298
|
+
encoderReverse
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
function serialPathPreference(path) {
|
|
302
|
+
const p = path.toLowerCase();
|
|
303
|
+
let score = 0;
|
|
304
|
+
if (p.includes("/dev/cu.")) score += 20;
|
|
305
|
+
if (p.includes("wchusbserial")) score += 12;
|
|
306
|
+
if (p.includes("usbserial")) score += 8;
|
|
307
|
+
if (p.includes("usbmodem")) score += 2;
|
|
308
|
+
return score;
|
|
309
|
+
}
|
|
310
|
+
function normalizeText(value) {
|
|
311
|
+
return value.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
312
|
+
}
|
|
313
|
+
function parseIntegerToken(value) {
|
|
314
|
+
if (!value) return void 0;
|
|
315
|
+
const trimmed = value.trim();
|
|
316
|
+
const parsed = trimmed.toLowerCase().startsWith("0x") ? Number.parseInt(trimmed.slice(2), 16) : Number.parseInt(trimmed, 10);
|
|
317
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
318
|
+
}
|
|
319
|
+
function sameUsbFamily(a, b) {
|
|
320
|
+
return Boolean(
|
|
321
|
+
a.vendorId && b.vendorId && a.productId && b.productId && a.vendorId.toLowerCase() === b.vendorId.toLowerCase() && a.productId.toLowerCase() === b.productId.toLowerCase()
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
function endpointKey(port) {
|
|
325
|
+
for (const path of allSerialPortPaths(port)) {
|
|
326
|
+
const id = serialEndpointId(path);
|
|
327
|
+
if (id) return id;
|
|
328
|
+
}
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
331
|
+
function samePhysicalPort(a, b) {
|
|
332
|
+
const aPaths = new Set(allSerialPortPaths(a).map((path) => path.toLowerCase()));
|
|
333
|
+
return allSerialPortPaths(b).some((path) => aPaths.has(path.toLowerCase()));
|
|
334
|
+
}
|
|
335
|
+
function chooseDutForFixture(fixture, candidates) {
|
|
336
|
+
const fixtureEndpoint = endpointKey(fixture);
|
|
337
|
+
if (fixtureEndpoint) {
|
|
338
|
+
const sibling = candidates.find((port) => {
|
|
339
|
+
if (samePhysicalPort(port, fixture)) return false;
|
|
340
|
+
const endpoint = endpointKey(port);
|
|
341
|
+
return endpoint && endpoint !== fixtureEndpoint && sameUsbFamily(fixture, port);
|
|
342
|
+
});
|
|
343
|
+
if (sibling) return sibling;
|
|
344
|
+
}
|
|
345
|
+
const sameFamily = candidates.find(
|
|
346
|
+
(port) => !samePhysicalPort(port, fixture) && sameUsbFamily(fixture, port)
|
|
347
|
+
);
|
|
348
|
+
if (sameFamily) return sameFamily;
|
|
349
|
+
const sn = (fixture.serialNumber ?? "").trim().toLowerCase();
|
|
350
|
+
if (sn.length >= 4) {
|
|
351
|
+
const bySerial = candidates.find((port) => {
|
|
352
|
+
if (samePhysicalPort(port, fixture)) return false;
|
|
353
|
+
const other = (port.serialNumber ?? "").trim().toLowerCase();
|
|
354
|
+
return other.length >= 4 && (other === sn || other.startsWith(sn) || sn.startsWith(other));
|
|
355
|
+
});
|
|
356
|
+
if (bySerial) return bySerial;
|
|
357
|
+
}
|
|
358
|
+
return void 0;
|
|
359
|
+
}
|
|
360
|
+
function pickSoleOtherPort(fixture, candidates) {
|
|
361
|
+
const others = candidates.filter((port) => !samePhysicalPort(port, fixture));
|
|
362
|
+
return others.length === 1 ? others[0] : void 0;
|
|
363
|
+
}
|
|
364
|
+
function mergePortLists(...lists) {
|
|
365
|
+
const out = [];
|
|
366
|
+
for (const list of lists) {
|
|
367
|
+
for (const port of list) {
|
|
368
|
+
if (!out.some((existing) => samePhysicalPort(existing, port))) {
|
|
369
|
+
out.push(port);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
return out;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// src/runtimeValues.ts
|
|
377
|
+
function asSerialPorts(value) {
|
|
378
|
+
return Array.isArray(value) ? value : [];
|
|
379
|
+
}
|
|
380
|
+
function asSerialDeviceSuggestions(value) {
|
|
381
|
+
return Array.isArray(value) ? value : [];
|
|
382
|
+
}
|
|
383
|
+
function asChannelStatus(value) {
|
|
384
|
+
return value;
|
|
385
|
+
}
|
|
386
|
+
function asResponseObject(value) {
|
|
387
|
+
return value && typeof value === "object" ? value : {};
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// src/index.ts
|
|
391
|
+
var DIALOG_READ_CONTENT_MAX_BYTES = 4 * 1024 * 1024;
|
|
392
|
+
var DIALOG_SAVE_CONTENT_MAX_BYTES = 8 * 1024 * 1024;
|
|
393
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
394
|
+
0 && (module.exports = {
|
|
395
|
+
CURRENT_METER_LOGICAL,
|
|
396
|
+
DIALOG_READ_CONTENT_MAX_BYTES,
|
|
397
|
+
DIALOG_SAVE_CONTENT_MAX_BYTES,
|
|
398
|
+
DUT_LOGICAL,
|
|
399
|
+
FIXTURE_BAUD_RATE,
|
|
400
|
+
FIXTURE_BOARD_ADDRESS,
|
|
401
|
+
FIXTURE_LOGICAL,
|
|
402
|
+
KNOWN_T9W_DUT_ENDPOINT,
|
|
403
|
+
KNOWN_T9W_FIXTURE_ENDPOINT,
|
|
404
|
+
T9W_DUT_BAUD_RATE,
|
|
405
|
+
allSerialPortPaths,
|
|
406
|
+
asChannelStatus,
|
|
407
|
+
asResponseObject,
|
|
408
|
+
asSerialDeviceSuggestions,
|
|
409
|
+
asSerialPorts,
|
|
410
|
+
buildDutRawTextSerialConfig,
|
|
411
|
+
buildFixtureSerialConfig,
|
|
412
|
+
chooseFixtureAndDutPortPairs,
|
|
413
|
+
chooseFixtureAndDutPorts,
|
|
414
|
+
isFixtureReadyEvent,
|
|
415
|
+
looksLikeUsbSerialPort,
|
|
416
|
+
parseOperatorSignals,
|
|
417
|
+
preferredSerialPathFromPort,
|
|
418
|
+
preferredSerialPortPath,
|
|
419
|
+
serialEndpointId,
|
|
420
|
+
serialPortHasEndpoint
|
|
421
|
+
});
|