bmweb-cli 0.1.6 → 0.1.7
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 +281 -26
- package/dist/bmweb.js +1492 -243
- package/package.json +1 -1
- package/runtime/core/ipofile/encode.js +701 -0
- package/runtime/core/ipofile/exec.js +155 -0
- package/runtime/core/webshim/web-serial-bus.js +59 -10
- package/runtime/screens/ipo-runtime/program.js +8 -2
package/README.md
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
# bmweb-cli
|
|
2
2
|
|
|
3
3
|
[BMWeb](https://bmweb.danner.ink/)'s tools as a command line. Read what an
|
|
4
|
-
INPA `.IPO` script does, compile an `.IPS` / `.SRC` source
|
|
5
|
-
module the site ships for the key that does a thing,
|
|
6
|
-
report links the app's Garage shares,
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
INPA `.IPO` script does, compile an `.IPS` / `.SRC` source into a real
|
|
5
|
+
`.IPO`, search every module the site ships for the key that does a thing,
|
|
6
|
+
decode or compare the report links the app's Garage shares, list what a
|
|
7
|
+
module's SGBD declares (its jobs and their arguments, results and lookup
|
|
8
|
+
tables), and, with a K+DCAN cable, run jobs, read every fault memory of a
|
|
9
|
+
car, and drive a module's INPA screens from the terminal.
|
|
9
10
|
|
|
10
11
|
The commands run the app's own code: the `.IPO` reader and the source
|
|
11
12
|
compiler, the job search, the Garage report codec, the transport (framing,
|
|
@@ -28,9 +29,10 @@ Only the project's own code. Nothing BMW-derived ships with it: no scripts,
|
|
|
28
29
|
no SGBDs, no fault database, no parts data. Everything the tool needs that
|
|
29
30
|
it does not carry is fetched from the site (or `--api <url>`) and kept
|
|
30
31
|
under `$XDG_CACHE_HOME/bmweb-cli/` (default `~/.cache/bmweb-cli/`) for a
|
|
31
|
-
day: the job search index (about 2.5 MB), and, for the commands
|
|
32
|
-
cable, the chassis archives the app
|
|
33
|
-
about 20 MB for an E46), the
|
|
32
|
+
day: the job search index (about 2.5 MB), and, for the `sgbd` commands,
|
|
33
|
+
`job --info` and the commands on the cable, the chassis archives the app
|
|
34
|
+
itself loads (`api/chassis/E46.chassis`, about 20 MB for an E46), the
|
|
35
|
+
group bytecode and the shared tables.
|
|
34
36
|
`--refresh` fetches again; when the site cannot be reached the cached copy
|
|
35
37
|
is used and a warning says so.
|
|
36
38
|
|
|
@@ -97,7 +99,7 @@ m_main F10 Back DIAGNOSE_ENDE, (exit)
|
|
|
97
99
|
m_main Shift+F10 Print (printscreen)
|
|
98
100
|
```
|
|
99
101
|
|
|
100
|
-
### `bmweb ipo compile <file.IPS> [-I dir]... [-o out]`
|
|
102
|
+
### `bmweb ipo compile <file.IPS> [-I dir]... [-o out] [--exec]`
|
|
101
103
|
|
|
102
104
|
Compile an INPA source. Includes are looked up beside the script and in
|
|
103
105
|
each `-I` directory, by file name, case-insensitively, the way INPA's own
|
|
@@ -106,18 +108,22 @@ tooling finds them; a missing one is named rather than half-compiled.
|
|
|
106
108
|
```
|
|
107
109
|
$ bmweb ipo compile MY_SCRIPT.IPS -I ~/INPA/SGDAT
|
|
108
110
|
MY_SCRIPT.IPS: compiled 8 procedures (2 menus, 3 screens, 3 functions, 0 state machines), includes INPA.H
|
|
109
|
-
wrote /home/me/MY_SCRIPT.
|
|
111
|
+
wrote /home/me/MY_SCRIPT.IPO (44902 bytes, INPA's .IPO container)
|
|
110
112
|
|
|
111
113
|
$ bmweb ipo compile MY_SCRIPT.IPS
|
|
112
114
|
bmweb: MY_SCRIPT.IPS: missing include INPA.H (searched /home/me; pass -I <dir> with the INPA headers)
|
|
113
115
|
```
|
|
114
116
|
|
|
115
|
-
What it writes is
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
117
|
+
What it writes is a real `.IPO`: INPA's own binary container, the same
|
|
118
|
+
block layout the shipped scripts use. The writer is the app's own, and it
|
|
119
|
+
is held to reproduction -- every script in a full INPA install decodes and
|
|
120
|
+
re-encodes to its own bytes exactly, so the bytes it writes for a source
|
|
121
|
+
are the bytes that format calls for.
|
|
122
|
+
|
|
123
|
+
`--exec` writes the app's exec form instead (`{procs, byid}` as JSON, the
|
|
124
|
+
token stream the runtime executes and the same shape the Script runner
|
|
125
|
+
builds from a dropped file), which is what this command wrote before it
|
|
126
|
+
could write the container.
|
|
121
127
|
|
|
122
128
|
### `bmweb search <query...> [--chassis E46] [--limit N] [--json]`
|
|
123
129
|
|
|
@@ -197,6 +203,88 @@ Answering changed:
|
|
|
197
203
|
+ new - cleared = still present ~ ident field changed
|
|
198
204
|
```
|
|
199
205
|
|
|
206
|
+
### `bmweb sgbd jobs <sgbd> [--api url] [--refresh] [--json]`
|
|
207
|
+
|
|
208
|
+
Every job an SGBD declares, with the arguments it takes, the results it
|
|
209
|
+
returns, a comment, and whether the app's write gate would ask about it
|
|
210
|
+
before sending it. Nothing is sent and no port is opened: this is the
|
|
211
|
+
module's shipped declaration, the same one the app's Tool32 lists a job
|
|
212
|
+
from. A diagnostic group (`d_motor`, `d_0012`) is read from its own group
|
|
213
|
+
file rather than resolved on the wire, so it lists the job names and the
|
|
214
|
+
tables the group carries.
|
|
215
|
+
|
|
216
|
+
```
|
|
217
|
+
$ bmweb sgbd jobs lws5
|
|
218
|
+
NAME ARGS RESULTS COMMENT WRITE
|
|
219
|
+
------------------------- ----------------------------------------- ---------------------------------------------------------------------- ----------------------------------- -----
|
|
220
|
+
ABGLEICH_LESEN JOB_STATUS, ABGL_LRW_OFFSET, ABGL_LWS_ID, ABGL_FGSTNR, _TEL_ANTWORT OKAY, wenn fehlerfrei
|
|
221
|
+
ABGLEICH_SCHREIBEN JOB_STATUS, _TEL_ANTWORT OKAY, wenn fehlerfrei yes
|
|
222
|
+
ABGLEICH_VORGEBEN ABGL_LRW_OFFSET, ABGL_LWS_ID, ABGL_FGSTNR JOB_STATUS, _TEL_AN_SG, _TEL_ANTWORT OKAY, wenn fehlerfrei yes
|
|
223
|
+
CODIERUNG_LESEN BLOCK JOB_STATUS, COD_DATEN, _TEL_AN_SG, _TEL_ANTWORT OKAY, wenn fehlerfrei
|
|
224
|
+
FS_LESEN JOB_STATUS, F_HEX_CODE, F_ORT_NR, F_ORT_TEXT, F_HFK, F_ART_ANZ, +4 more OKAY, wenn fehlerfrei
|
|
225
|
+
FS_LOESCHEN JOB_STATUS, _TEL_ANTWORT OKAY, wenn fehlerfrei yes
|
|
226
|
+
...
|
|
227
|
+
|
|
228
|
+
24 jobs, 9 the app would ask about before sending
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
The WRITE column is the app's classifier (`isWriteJob`), the same verdict
|
|
232
|
+
`bmweb job` gates on: a read token in the name wins, a write token makes a
|
|
233
|
+
write, and an unknown name is a write. A cell that lists only the first few
|
|
234
|
+
names says how many more there are; `--json` and `bmweb job <sgbd> <JOB>
|
|
235
|
+
--info` carry every one.
|
|
236
|
+
|
|
237
|
+
The site's export writes a job's results as `NAME : comment` and keeps no
|
|
238
|
+
comment above them, so COMMENT is the `JOB_COMMENT` result where the SGBD's
|
|
239
|
+
author wrote one and the first declared result's comment otherwise.
|
|
240
|
+
|
|
241
|
+
### `bmweb sgbd tables <sgbd> [--api url] [--refresh] [--json]`
|
|
242
|
+
|
|
243
|
+
The lookup tables an SGBD carries for its own bytecode -- the ones its jobs
|
|
244
|
+
read with `tabset` to turn a byte into a word -- with the rows and columns
|
|
245
|
+
of each.
|
|
246
|
+
|
|
247
|
+
```
|
|
248
|
+
$ bmweb sgbd tables ms450ds0
|
|
249
|
+
NAME ROWS COLS COLUMNS
|
|
250
|
+
------------------------ ---- ---- ---------------------------------------------------
|
|
251
|
+
AUTHENTISIERUNG 4 2 AUTH_NR, AUTH_TEXT
|
|
252
|
+
BAUDRATE 7 3 NR, BAUD, BAUD_TEXT
|
|
253
|
+
BETRIEBSSTUNDENSTATUS 4 2 WERT, UWTEXT
|
|
254
|
+
BITS 72 4 NAME, BYTE, MASK, VALUE
|
|
255
|
+
CBSKENNUNG 16 3 NR, CBS_K, CBS_K_TEXT
|
|
256
|
+
...
|
|
257
|
+
|
|
258
|
+
53 tables (bmweb sgbd table ms450ds0 <NAME> prints one)
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
These are the module's own tables. The four shared table files (`t_pcod`,
|
|
262
|
+
`t_scod`, `t_ausb`, `t_grtb`, which an SGBD reads with `tabsetex`) belong
|
|
263
|
+
to no one module -- every job VM is handed all of them -- so they are not
|
|
264
|
+
listed here, and a module is never said to carry them.
|
|
265
|
+
|
|
266
|
+
### `bmweb sgbd table <sgbd> <NAME> [--api url] [--refresh] [--json]`
|
|
267
|
+
|
|
268
|
+
One table's rows.
|
|
269
|
+
|
|
270
|
+
```
|
|
271
|
+
$ bmweb sgbd table ms450ds0 BAUDRATE
|
|
272
|
+
NR BAUD BAUD_TEXT
|
|
273
|
+
---- -------- --------------------
|
|
274
|
+
0x01 PC9600 Baudrate 9.6 kBaud
|
|
275
|
+
0x02 PC19200 Baudrate 19.2 kBaud
|
|
276
|
+
0x03 PC38400 Baudrate 38.4 kBaud
|
|
277
|
+
0x04 PC57600 Baudrate 57.6 kBaud
|
|
278
|
+
0x05 PC115200 Baudrate 115.2 kBaud
|
|
279
|
+
0x06 SB Specific Baudrate
|
|
280
|
+
0xXY -- unbekannte Baudrate
|
|
281
|
+
|
|
282
|
+
7 rows in BAUDRATE
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
The name is matched without regard to case, and a near miss is named:
|
|
286
|
+
`bmweb sgbd table lws5 BITS` answers `lws5 carries no table BITS`.
|
|
287
|
+
|
|
200
288
|
## Commands on the cable
|
|
201
289
|
|
|
202
290
|
These need a K+DCAN cable (an FTDI cable, or a clone) on the car's OBD
|
|
@@ -218,11 +306,18 @@ own bytecode branches on. An FTDI cable wants a 1 ms latency timer (set for
|
|
|
218
306
|
you on Linux; on macOS and Windows a driver setting), and an echo failure
|
|
219
307
|
(IFH-0003) says so.
|
|
220
308
|
|
|
221
|
-
**
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
309
|
+
**Run on a real car.** Since 0.1.4, `job`, `scan` and `tui` have been run
|
|
310
|
+
on an E46 over an FTDI K+DCAN cable on macOS. What that run fixed is in
|
|
311
|
+
`src/serial.ts`: on macOS a Node serial port never wakes on bytes an FTDI
|
|
312
|
+
cable sends back, so the reader polls the port's modem lines while it is
|
|
313
|
+
reading and picks the bytes up itself. The offline commands need no cable
|
|
314
|
+
and never open one.
|
|
315
|
+
|
|
316
|
+
Everything is still tested offline as well: the transport end to end
|
|
317
|
+
against a fake cable (the DS2 and BMW-FAST framing, the reopen, the DTR
|
|
318
|
+
sequence, the echo), and `job`, `scan` and `tui` against the fake car the
|
|
319
|
+
app's own runtime tests use, both directly and through a gateway on a real
|
|
320
|
+
socket. The gateway itself has not been on a car yet.
|
|
226
321
|
|
|
227
322
|
### `bmweb ports [--json]`
|
|
228
323
|
|
|
@@ -235,7 +330,116 @@ $ bmweb ports
|
|
|
235
330
|
/dev/cu.usbserial-AB0JQ9XY FTDI 0403:6001 sn AB0JQ9XY
|
|
236
331
|
```
|
|
237
332
|
|
|
238
|
-
###
|
|
333
|
+
### Gateway
|
|
334
|
+
|
|
335
|
+
One machine owns the cable; another drives it. `bmweb gateway` opens the
|
|
336
|
+
local port exactly as `job` does and serves it over a WebSocket, and
|
|
337
|
+
`--gateway` on `job`, `scan` and `tui` (and the app in a browser) hands
|
|
338
|
+
that socket to the same transport, which cannot tell it from a cable in
|
|
339
|
+
its own USB port.
|
|
340
|
+
|
|
341
|
+
Nothing about the wire moves. The framing, the checksums, the reopen for a
|
|
342
|
+
concept change, DTR as the K-line transmit enable, the echo dropped by
|
|
343
|
+
count, the timeouts measured to the first byte and every write
|
|
344
|
+
confirmation all run on the machine you typed the command on, because
|
|
345
|
+
that is where the bus is. The machine with the cable moves bytes and
|
|
346
|
+
modem-line states, and nothing else.
|
|
347
|
+
|
|
348
|
+
**It is a pipe, not a gate.** The gateway never sees a job name, only
|
|
349
|
+
bytes, so it cannot tell a read from a write and does not try. Anyone who
|
|
350
|
+
can reach the listening port can drive the car. It binds `127.0.0.1` by
|
|
351
|
+
default, which is this machine only; `--listen 0.0.0.0:6801` opens it to
|
|
352
|
+
whoever can route to the machine, and says so when it starts.
|
|
353
|
+
|
|
354
|
+
On the machine with the cable:
|
|
355
|
+
|
|
356
|
+
```
|
|
357
|
+
$ bmweb gateway --listen 0.0.0.0:6801
|
|
358
|
+
gateway: /dev/cu.usbserial-AB0JQ9XY served at ws://0.0.0.0:6801
|
|
359
|
+
this is a byte pipe with no gate of its own: anyone who can reach this port can drive the car.
|
|
360
|
+
listening beyond this machine; the port is open to whoever can route to it
|
|
361
|
+
one client at a time; the cable is closed when the client goes.
|
|
362
|
+
client 192.168.1.24:52233 connected
|
|
363
|
+
client 192.168.1.24:52233 disconnected, cable closed
|
|
364
|
+
^C
|
|
365
|
+
gateway: stopping, the cable is closed
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
On the machine driving it:
|
|
369
|
+
|
|
370
|
+
```
|
|
371
|
+
$ bmweb job ms450ds0 STATUS_LESEN --gateway 192.168.1.9:6801
|
|
372
|
+
ms450ds0 MS450DS0 STATUS_LESEN: 1 set
|
|
373
|
+
|
|
374
|
+
set 1
|
|
375
|
+
STAT_MOTORDREHZAHL_WERT 812.5
|
|
376
|
+
STAT_MOTORDREHZAHL_EINH 1/min
|
|
377
|
+
JOB_STATUS OKAY
|
|
378
|
+
|
|
379
|
+
$ bmweb job ms450ds0 FS_LOESCHEN --gateway 192.168.1.9:6801
|
|
380
|
+
FS_LOESCHEN on ms450ds0 is a write (it changes the module or drives something). Send it? [y/N] n
|
|
381
|
+
FS_LOESCHEN on ms450ds0: not sent (a write needs --yes or a y answer)
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
The question is asked here, on the driving machine, and a `n` means the
|
|
385
|
+
bytes never leave it. `--gateway` takes `host:port`, a bare host (port
|
|
386
|
+
6801 is assumed), or a full `ws://` / `wss://` URL. One client at a time:
|
|
387
|
+
a second connection is refused with a message, and the cable is closed
|
|
388
|
+
when the client goes, so the host machine can use its own port in
|
|
389
|
+
between.
|
|
390
|
+
|
|
391
|
+
#### From a browser
|
|
392
|
+
|
|
393
|
+
The app drives a gateway too. Set the address in Settings, under "Cable on
|
|
394
|
+
another machine", or open the page with `?gateway=ws://192.168.1.9:6801`,
|
|
395
|
+
which stores it. The topbar's cable chip then reads
|
|
396
|
+
`cable: gateway 192.168.1.9:6801 (/dev/cu.usbserial-AB0JQ9XY)`, so the car
|
|
397
|
+
never looks local when it is not.
|
|
398
|
+
|
|
399
|
+
Where this works is a browser rule, not ours: **a page served over http
|
|
400
|
+
(localhost, an offline export opened from a file, an offline copy served
|
|
401
|
+
on your own network) may open a plain `ws://` gateway. The hosted https
|
|
402
|
+
site may not** -- browsers block `ws://` from an https page as mixed
|
|
403
|
+
content, with no override. From https, only a `wss://` gateway works,
|
|
404
|
+
which means putting a TLS front end with a certificate the browser trusts
|
|
405
|
+
in front of it.
|
|
406
|
+
|
|
407
|
+
#### The protocol
|
|
408
|
+
|
|
409
|
+
JSON text frames for control, binary frames for the bytes the wire
|
|
410
|
+
carries, so a read crosses as one frame with no base64 and no copy.
|
|
411
|
+
|
|
412
|
+
| direction | frame | meaning |
|
|
413
|
+
| -------------- | ------ | ------------------------------------------------------------------------------------------- |
|
|
414
|
+
| client to host | text | `{"id":1,"op":"open","config":{"baudRate":9600,"dataBits":8,"stopBits":1,"parity":"even"}}` |
|
|
415
|
+
| client to host | text | `{"id":2,"op":"close"}` |
|
|
416
|
+
| client to host | text | `{"id":3,"op":"setSignals","signals":{"dataTerminalReady":true}}` |
|
|
417
|
+
| client to host | text | `{"id":4,"op":"getSignals"}` |
|
|
418
|
+
| client to host | binary | the bytes to write, exactly as given |
|
|
419
|
+
| host to client | text | `{"id":1,"ok":true}`, or `{"id":4,"ok":true,"signals":{...}}` |
|
|
420
|
+
| host to client | text | `{"id":2,"ok":false,"error":"..."}` |
|
|
421
|
+
| host to client | text | `{"event":"hello","port":"/dev/cu.usbserial-AB0JQ9XY","gateway":"bmweb"}` |
|
|
422
|
+
| host to client | text | `{"event":"writeFailed","error":"..."}` |
|
|
423
|
+
| host to client | binary | bytes as they arrive off the wire, streamed |
|
|
424
|
+
|
|
425
|
+
A write needs no reply: the wire has no acknowledgement to give, and the
|
|
426
|
+
transport never waited for one, so a round trip here would only lengthen
|
|
427
|
+
the DTR hold and lose the answer. A write that FAILS does travel, as an
|
|
428
|
+
unsolicited `writeFailed`, because a client that thinks a request went out
|
|
429
|
+
when it never left the cable reports a phantom fault against a healthy
|
|
430
|
+
module. Reads are streamed as the bytes arrive rather than gathered into
|
|
431
|
+
an answer, so a timeout still means time-to-first-byte on the driving
|
|
432
|
+
machine. `setSignals` keeps the lines it does not name, and keeps them
|
|
433
|
+
across the reopen a concept change makes, exactly as a local port does.
|
|
434
|
+
Every failure travels back as the same message text a local port would
|
|
435
|
+
have raised, so the app throws it verbatim and cannot tell the difference.
|
|
436
|
+
|
|
437
|
+
The WebSocket is RFC 6455 with no compression and no extensions, written
|
|
438
|
+
in the package itself (`src/ws.ts`) rather than pulled in, because the
|
|
439
|
+
package promises zero runtime dependencies and Node ships a WebSocket
|
|
440
|
+
client only from version 22 and no server at all.
|
|
441
|
+
|
|
442
|
+
### `bmweb job <sgbd> <JOB> [arg] [--results a,b] [--info] [--port p] [--gateway h:p] [--yes] [--json]`
|
|
239
443
|
|
|
240
444
|
One raw job on one module, like the app's Tool32: the SGBD's own bytecode
|
|
241
445
|
runs in the job VM over the cable, inside its EDIABAS session
|
|
@@ -263,7 +467,51 @@ name wins, a write token makes a write, and an unknown name is a write.
|
|
|
263
467
|
A write goes out only with `--yes` or a `y` on the terminal; without a
|
|
264
468
|
terminal the answer is no. A write is never sent silently.
|
|
265
469
|
|
|
266
|
-
|
|
470
|
+
`--results` names the results to print, comma-separated and without regard
|
|
471
|
+
to case. The job still runs whole -- the flag narrows what is shown, not
|
|
472
|
+
what is asked of the module -- and `--json` is filtered the same way, so
|
|
473
|
+
the table and the JSON never disagree about what was read. A name that
|
|
474
|
+
matched nothing is a warning on stderr and the exit code stays 0.
|
|
475
|
+
|
|
476
|
+
```
|
|
477
|
+
$ bmweb job ms450ds0 STATUS_LESEN --results stat_motordrehzahl_wert,JOB_STATUS
|
|
478
|
+
ms450ds0 MS450DS0 STATUS_LESEN: 1 set
|
|
479
|
+
|
|
480
|
+
set 1
|
|
481
|
+
STAT_MOTORDREHZAHL_WERT 812.5
|
|
482
|
+
JOB_STATUS OKAY
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
`--info` prints what the SGBD declares about the job -- its arguments, its
|
|
486
|
+
results and their comments -- instead of running it. It opens no port and
|
|
487
|
+
sends nothing, so it works with the cable unplugged and with the car
|
|
488
|
+
elsewhere; a job argument beside it is refused rather than quietly ignored.
|
|
489
|
+
|
|
490
|
+
```
|
|
491
|
+
$ bmweb job ms450ds0 AIF_LESEN --info
|
|
492
|
+
ms450ds0 AIF_LESEN
|
|
493
|
+
|
|
494
|
+
arguments (1)
|
|
495
|
+
AIF_NUMMER int ==0 : aktuelles AIF > 0 : Nummer des zu lesenden AIF default = 0 : aktuelles AIF
|
|
496
|
+
|
|
497
|
+
results (21)
|
|
498
|
+
AIF_ADRESSE_HIGH AIF Adresse des AIF, High-Word
|
|
499
|
+
AIF_ADRESSE_LOW AIF Adresse des AIF, Low-Word
|
|
500
|
+
AIF_FG_NR Fahrgestellnummer 7-stellig
|
|
501
|
+
AIF_FG_NR_LANG Fahrgestellnummer 17-stellig falls vorhanden, sonst 7-stellig
|
|
502
|
+
AIF_DATUM Datum der SG-Programmierung in der Form TT.MM.JJJJ
|
|
503
|
+
...
|
|
504
|
+
JOB_STATUS OKAY, wenn fehlerfrei
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
A job that writes is headed `[WRITE]` here too, and `bmweb sgbd jobs`
|
|
508
|
+
below lists every job of a module at once.
|
|
509
|
+
|
|
510
|
+
`--gateway <host:port>` runs the same job on a cable another machine is
|
|
511
|
+
serving (see [Gateway](#gateway) below). The write gate does not move: it
|
|
512
|
+
is asked here, on the machine you typed the command on.
|
|
513
|
+
|
|
514
|
+
### `bmweb scan <chassis> [--port p] [--gateway h:p] [--share] [--json]`
|
|
267
515
|
|
|
268
516
|
INPA's own whole-vehicle script (E46 E53 E65 E83 E85 E87 E89 E90 R50 R56):
|
|
269
517
|
the script is opened, its fault-memory menu's read key is pressed, and what
|
|
@@ -295,7 +543,9 @@ Share: https://bmweb.danner.ink/#report/...
|
|
|
295
543
|
The script's progress window (which module it is asking) goes to stderr;
|
|
296
544
|
a key that would write is declined, a prompt is cancelled: the scan reads.
|
|
297
545
|
|
|
298
|
-
|
|
546
|
+
`--gateway <host:port>` scans a car on a cable another machine is serving.
|
|
547
|
+
|
|
548
|
+
### `bmweb tui [<chassis> <sgbd>] [--port p] [--gateway h:p] [--menu m_x]`
|
|
299
549
|
|
|
300
550
|
INPA's screens in the terminal. With a chassis and a module (SGBD or INPA
|
|
301
551
|
code, or the chassis itself for its whole-vehicle script), that module's
|
|
@@ -335,6 +585,9 @@ performs.
|
|
|
335
585
|
The module data the script needs (its `.IPO`, the SGBD bytecode, the
|
|
336
586
|
tables) comes from the site's chassis archive, cached as described above.
|
|
337
587
|
|
|
588
|
+
`--gateway <host:port>` drives a cable another machine is serving. Every
|
|
589
|
+
confirmation still happens here, on your keyboard.
|
|
590
|
+
|
|
338
591
|
### Every command
|
|
339
592
|
|
|
340
593
|
`--json` prints machine-readable output instead of a table. Errors are one
|
|
@@ -350,8 +603,10 @@ to `dist/bmweb.js` with esbuild and type-checks with `tsc`; `npm test` runs
|
|
|
350
603
|
the `node:test` suites the build produced, every one of them offline: the
|
|
351
604
|
serial tests drive the app's bus over a fake cable, the job, scan and tui
|
|
352
605
|
tests drive the app's runtime against a fake car and a scripted terminal,
|
|
353
|
-
with a module script written for the tests in INPA's language
|
|
354
|
-
|
|
606
|
+
with a module script written for the tests in INPA's language, and the
|
|
607
|
+
gateway tests run `job`, `scan` and `tui` a second time through a real
|
|
608
|
+
gateway on a port the OS picks. The repository's `tools/check.sh` runs all
|
|
609
|
+
of it.
|
|
355
610
|
|
|
356
611
|
Set `BMWEB_VERBOSE=1` to see what the app's runtime logs: the wire trace
|
|
357
612
|
the bus dumps after an error, each variant probe's verdict, the cable
|