@emdzej/j2534-driver 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +53 -0
- package/dist/index.d.ts +100 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +648 -0
- package/dist/index.js.map +1 -0
- package/package.json +65 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Michał Jaskólski
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# @emdzej/j2534-driver
|
|
2
|
+
|
|
3
|
+
The `J2534Device` class — full SAE J2534 PassThru API implementation
|
|
4
|
+
for the Tactrix OpenPort 2.0. Supports CAN (11/29-bit), ISO 15765
|
|
5
|
+
(ISO-TP / UDS), ISO 9141 (K-line slow init), and ISO 14230 (KWP2000
|
|
6
|
+
fast init).
|
|
7
|
+
|
|
8
|
+
Transport-agnostic: pair with one of the `@emdzej/j2534-*-transport`
|
|
9
|
+
packages depending on runtime (Node serial / Node USB / Web Serial /
|
|
10
|
+
WebUSB).
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @emdzej/j2534-driver @emdzej/j2534-serial
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Use (Node.js, serial transport)
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import { J2534Device } from '@emdzej/j2534-driver';
|
|
22
|
+
import { createSerialTransport } from '@emdzej/j2534-serial';
|
|
23
|
+
import { Protocol, ConnectFlag } from '@emdzej/j2534-types';
|
|
24
|
+
|
|
25
|
+
const transport = await createSerialTransport(); // auto-detect OpenPort
|
|
26
|
+
const dev = new J2534Device(transport);
|
|
27
|
+
await dev.open();
|
|
28
|
+
|
|
29
|
+
const channel = await dev.connect(Protocol.ISO15765, 0, 500_000);
|
|
30
|
+
await dev.writeMsgs(channel, [{ data: Uint8Array.of(0x22, 0xf1, 0x90) }]);
|
|
31
|
+
const responses = await dev.readMsgs(channel, 1, 1000);
|
|
32
|
+
console.log(responses);
|
|
33
|
+
|
|
34
|
+
await dev.disconnect(channel);
|
|
35
|
+
await dev.close();
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## See also
|
|
39
|
+
|
|
40
|
+
- [Root README](https://github.com/emdzej/j2534#readme) — full
|
|
41
|
+
project overview, supported hardware (Tactrix OpenPort 2.0 VID
|
|
42
|
+
`0x0403` / PID `0xCC4D`), and end-to-end examples
|
|
43
|
+
- [`@emdzej/j2534-types`](https://www.npmjs.com/package/@emdzej/j2534-types) —
|
|
44
|
+
the enum/interface declarations
|
|
45
|
+
- Transports:
|
|
46
|
+
[`j2534-serial`](https://www.npmjs.com/package/@emdzej/j2534-serial),
|
|
47
|
+
[`j2534-usb`](https://www.npmjs.com/package/@emdzej/j2534-usb),
|
|
48
|
+
[`j2534-webserial`](https://www.npmjs.com/package/@emdzej/j2534-webserial),
|
|
49
|
+
[`j2534-webusb`](https://www.npmjs.com/package/@emdzej/j2534-webusb)
|
|
50
|
+
|
|
51
|
+
## License
|
|
52
|
+
|
|
53
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { type Transport, type PassThruMsg, type SConfig, type SByteArray, type VersionInfo, type FunctionalAddress, Protocol, FilterType, IoctlId, J2534Error } from "@emdzej/j2534-types";
|
|
2
|
+
import { MessageQueue } from "@emdzej/j2534-core";
|
|
3
|
+
export interface ChannelState {
|
|
4
|
+
id: number;
|
|
5
|
+
channelByte: number;
|
|
6
|
+
protocol: Protocol | number;
|
|
7
|
+
flags: number;
|
|
8
|
+
baudRate: number;
|
|
9
|
+
filters: Map<number, FilterState>;
|
|
10
|
+
rxQueue: MessageQueue;
|
|
11
|
+
functionalAddresses: FunctionalAddress[];
|
|
12
|
+
/**
|
|
13
|
+
* Pending K-line message being assembled across multiple packets.
|
|
14
|
+
* K-line messages arrive as: START_IND → NORM_MSG/LB_MSG (data) → END_IND (timestamp)
|
|
15
|
+
* Data is accumulated here until the END_IND arrives.
|
|
16
|
+
*/
|
|
17
|
+
pendingMsg: {
|
|
18
|
+
data: number[];
|
|
19
|
+
rxStatus: number;
|
|
20
|
+
} | null;
|
|
21
|
+
}
|
|
22
|
+
export interface FilterState {
|
|
23
|
+
type: FilterType;
|
|
24
|
+
mask: Uint8Array;
|
|
25
|
+
pattern: Uint8Array;
|
|
26
|
+
flowControl?: Uint8Array;
|
|
27
|
+
}
|
|
28
|
+
export interface J2534Options {
|
|
29
|
+
/** USB transport implementation (Node or WebUSB) */
|
|
30
|
+
transport: Transport;
|
|
31
|
+
/** Read polling interval in ms (default 10) */
|
|
32
|
+
pollInterval?: number;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* J2534 PassThru driver implementation.
|
|
36
|
+
*
|
|
37
|
+
* Supports J2534-1 and J2534-2 features available on the Tactrix OpenPort 2.0:
|
|
38
|
+
* - All standard protocols (CAN, ISO15765, ISO9141, ISO14230, J1850VPW, J1850PWM)
|
|
39
|
+
* - Multi-channel support (CAN + K-line + L-line + AUX simultaneously)
|
|
40
|
+
* - Periodic messages (software timer implementation)
|
|
41
|
+
* - Programming voltage control
|
|
42
|
+
* - 5-baud and fast initialization
|
|
43
|
+
* - Functional message lookup table (software filter)
|
|
44
|
+
* - ISO15765 extended addressing
|
|
45
|
+
*/
|
|
46
|
+
export declare class J2534Device {
|
|
47
|
+
private transport;
|
|
48
|
+
private deviceId;
|
|
49
|
+
private channels;
|
|
50
|
+
private periodicMsgs;
|
|
51
|
+
private nextChannelId;
|
|
52
|
+
private nextFilterId;
|
|
53
|
+
private nextPeriodicId;
|
|
54
|
+
private lastError;
|
|
55
|
+
private firmwareVersion;
|
|
56
|
+
private pollInterval;
|
|
57
|
+
constructor(options: J2534Options);
|
|
58
|
+
passThruOpen(): Promise<number>;
|
|
59
|
+
passThruClose(): Promise<void>;
|
|
60
|
+
passThruConnect(protocol: Protocol | number, flags: number, baudRate: number): Promise<number>;
|
|
61
|
+
passThruDisconnect(channelId: number): Promise<void>;
|
|
62
|
+
passThruReadMsgs(channelId: number, numMsgs: number, timeout: number): Promise<PassThruMsg[]>;
|
|
63
|
+
passThruWriteMsgs(channelId: number, msgs: PassThruMsg[], timeout: number): Promise<number>;
|
|
64
|
+
passThruStartPeriodicMsg(channelId: number, msg: PassThruMsg, intervalMs: number): Promise<number>;
|
|
65
|
+
passThruStopPeriodicMsg(channelId: number, msgId: number): Promise<void>;
|
|
66
|
+
passThruStartMsgFilter(channelId: number, filterType: FilterType, maskMsg: PassThruMsg, patternMsg: PassThruMsg, flowControlMsg?: PassThruMsg): Promise<number>;
|
|
67
|
+
passThruStopMsgFilter(channelId: number, filterId: number): Promise<void>;
|
|
68
|
+
passThruSetProgrammingVoltage(pin: number, voltage: number): Promise<void>;
|
|
69
|
+
/**
|
|
70
|
+
* Read the current voltage on a given OBD-II pin (in millivolts).
|
|
71
|
+
* Uses the Tactrix "atr <pin>" command.
|
|
72
|
+
*/
|
|
73
|
+
readPinVoltage(pin: number): Promise<number>;
|
|
74
|
+
passThruReadVersion(): Promise<VersionInfo>;
|
|
75
|
+
passThruGetLastError(): string;
|
|
76
|
+
passThruIoctl(channelId: number, ioctlId: IoctlId, input?: SConfig[] | PassThruMsg | SByteArray): Promise<SConfig[] | number | PassThruMsg | void>;
|
|
77
|
+
private assertOpen;
|
|
78
|
+
private getChannel;
|
|
79
|
+
private validateProtocol;
|
|
80
|
+
private setError;
|
|
81
|
+
private readResponse;
|
|
82
|
+
private isKLine;
|
|
83
|
+
private pollOnce;
|
|
84
|
+
private enqueueMsg;
|
|
85
|
+
private matchesFunctionalAddress;
|
|
86
|
+
private getAddressSize;
|
|
87
|
+
private stopPeriodicTimer;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* J2534 error with status code.
|
|
91
|
+
*/
|
|
92
|
+
export declare class J2534Exception extends Error {
|
|
93
|
+
readonly code: J2534Error;
|
|
94
|
+
constructor(code: J2534Error, message: string);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Helper to create a PassThruMsg for use in filter setup, writes, etc.
|
|
98
|
+
*/
|
|
99
|
+
export declare function createMsg(protocol: Protocol | number, data: number[], txFlags?: number): PassThruMsg;
|
|
100
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,648 @@
|
|
|
1
|
+
import { Protocol, FilterType, IoctlId, J2534Error, RxStatus, VOLTAGE_OFF, SHORT_TO_GROUND, } from "@emdzej/j2534-types";
|
|
2
|
+
import { protocolToChannelByte, encodeCommand, buildOpenChannelCmd, buildCloseChannelCmd, buildTransmitCmd, buildFilterCmd, buildStopFilterCmd, buildGetConfigCmd, buildSetConfigCmd, buildReadVoltageCmd, buildFastInitCmd, buildSetVoltageCmd, buildFiveBaudInitCmd, MessageQueue, parseResponse, parseAllPackets, } from "@emdzej/j2534-core";
|
|
3
|
+
// ─── Constants ──────────────────────────────────────────────────────
|
|
4
|
+
const MAX_PERIODIC_MSGS = 10;
|
|
5
|
+
const MAX_FILTERS_PER_CHANNEL = 10;
|
|
6
|
+
// ─── Driver ─────────────────────────────────────────────────────────
|
|
7
|
+
/**
|
|
8
|
+
* J2534 PassThru driver implementation.
|
|
9
|
+
*
|
|
10
|
+
* Supports J2534-1 and J2534-2 features available on the Tactrix OpenPort 2.0:
|
|
11
|
+
* - All standard protocols (CAN, ISO15765, ISO9141, ISO14230, J1850VPW, J1850PWM)
|
|
12
|
+
* - Multi-channel support (CAN + K-line + L-line + AUX simultaneously)
|
|
13
|
+
* - Periodic messages (software timer implementation)
|
|
14
|
+
* - Programming voltage control
|
|
15
|
+
* - 5-baud and fast initialization
|
|
16
|
+
* - Functional message lookup table (software filter)
|
|
17
|
+
* - ISO15765 extended addressing
|
|
18
|
+
*/
|
|
19
|
+
export class J2534Device {
|
|
20
|
+
transport;
|
|
21
|
+
deviceId = null;
|
|
22
|
+
channels = new Map();
|
|
23
|
+
periodicMsgs = new Map();
|
|
24
|
+
nextChannelId = 1;
|
|
25
|
+
nextFilterId = 1;
|
|
26
|
+
nextPeriodicId = 1;
|
|
27
|
+
lastError = "";
|
|
28
|
+
firmwareVersion = "";
|
|
29
|
+
pollInterval;
|
|
30
|
+
constructor(options) {
|
|
31
|
+
this.transport = options.transport;
|
|
32
|
+
this.pollInterval = options.pollInterval ?? 10;
|
|
33
|
+
}
|
|
34
|
+
// ─── PassThruOpen ───────────────────────────────────────────────
|
|
35
|
+
async passThruOpen() {
|
|
36
|
+
await this.transport.open();
|
|
37
|
+
// Send identification command with flush prefix (matches Tactrix SDK: "\r\n\r\nati\r\n")
|
|
38
|
+
const atiCmd = new TextEncoder().encode("\r\n\r\nati\r\n");
|
|
39
|
+
await this.transport.write(atiCmd);
|
|
40
|
+
// The flush prefix may produce extra responses; drain until we get the version
|
|
41
|
+
let resp;
|
|
42
|
+
do {
|
|
43
|
+
const raw = await this.transport.read(2000);
|
|
44
|
+
resp = parseResponse(raw, Protocol.CAN);
|
|
45
|
+
} while (resp.type !== "version" && resp.type !== "unknown");
|
|
46
|
+
if (resp.type === "version") {
|
|
47
|
+
this.firmwareVersion = resp.firmware;
|
|
48
|
+
}
|
|
49
|
+
// Attach
|
|
50
|
+
await this.transport.write(encodeCommand("ata"));
|
|
51
|
+
// Drain responses until we get the ack (may receive a stale version echo first)
|
|
52
|
+
let ack;
|
|
53
|
+
do {
|
|
54
|
+
const raw = await this.transport.read(2000);
|
|
55
|
+
ack = parseResponse(raw, Protocol.CAN);
|
|
56
|
+
} while (ack.type !== "ack" && ack.type !== "unknown");
|
|
57
|
+
if (ack.type !== "ack") {
|
|
58
|
+
throw this.setError(J2534Error.ERR_FAILED, "Device did not acknowledge open");
|
|
59
|
+
}
|
|
60
|
+
this.deviceId = 1;
|
|
61
|
+
return this.deviceId;
|
|
62
|
+
}
|
|
63
|
+
// ─── PassThruClose ──────────────────────────────────────────────
|
|
64
|
+
async passThruClose() {
|
|
65
|
+
this.assertOpen();
|
|
66
|
+
// Stop all periodic messages
|
|
67
|
+
for (const [id] of this.periodicMsgs) {
|
|
68
|
+
this.stopPeriodicTimer(id);
|
|
69
|
+
}
|
|
70
|
+
this.periodicMsgs.clear();
|
|
71
|
+
await this.transport.write(encodeCommand("atz"));
|
|
72
|
+
await this.transport.close();
|
|
73
|
+
this.deviceId = null;
|
|
74
|
+
this.channels.clear();
|
|
75
|
+
}
|
|
76
|
+
// ─── PassThruConnect ────────────────────────────────────────────
|
|
77
|
+
async passThruConnect(protocol, flags, baudRate) {
|
|
78
|
+
this.assertOpen();
|
|
79
|
+
this.validateProtocol(protocol);
|
|
80
|
+
const channelByte = protocolToChannelByte(protocol);
|
|
81
|
+
// Check if this channel byte is already in use
|
|
82
|
+
for (const [, ch] of this.channels) {
|
|
83
|
+
if (ch.channelByte === channelByte) {
|
|
84
|
+
throw this.setError(J2534Error.ERR_CHANNEL_IN_USE, `Channel 0x${channelByte.toString(16)} already connected`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const cmd = buildOpenChannelCmd(protocol, flags, baudRate);
|
|
88
|
+
await this.transport.write(cmd);
|
|
89
|
+
const resp = await this.readResponse();
|
|
90
|
+
if (resp.type !== "ack") {
|
|
91
|
+
throw this.setError(J2534Error.ERR_FAILED, "Connect failed");
|
|
92
|
+
}
|
|
93
|
+
const channelId = this.nextChannelId++;
|
|
94
|
+
this.channels.set(channelId, {
|
|
95
|
+
id: channelId,
|
|
96
|
+
channelByte,
|
|
97
|
+
protocol,
|
|
98
|
+
flags,
|
|
99
|
+
baudRate,
|
|
100
|
+
filters: new Map(),
|
|
101
|
+
rxQueue: new MessageQueue(),
|
|
102
|
+
functionalAddresses: [],
|
|
103
|
+
pendingMsg: null,
|
|
104
|
+
});
|
|
105
|
+
return channelId;
|
|
106
|
+
}
|
|
107
|
+
// ─── PassThruDisconnect ─────────────────────────────────────────
|
|
108
|
+
async passThruDisconnect(channelId) {
|
|
109
|
+
const ch = this.getChannel(channelId);
|
|
110
|
+
// Stop any periodic messages on this channel
|
|
111
|
+
for (const [id, pm] of this.periodicMsgs) {
|
|
112
|
+
if (pm.channelId === channelId) {
|
|
113
|
+
this.stopPeriodicTimer(id);
|
|
114
|
+
this.periodicMsgs.delete(id);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
await this.transport.write(buildCloseChannelCmd(ch.channelByte));
|
|
118
|
+
ch.rxQueue.clear();
|
|
119
|
+
this.channels.delete(channelId);
|
|
120
|
+
}
|
|
121
|
+
// ─── PassThruReadMsgs ───────────────────────────────────────────
|
|
122
|
+
async passThruReadMsgs(channelId, numMsgs, timeout) {
|
|
123
|
+
const ch = this.getChannel(channelId);
|
|
124
|
+
const deadline = Date.now() + timeout;
|
|
125
|
+
while (ch.rxQueue.length < numMsgs && Date.now() < deadline) {
|
|
126
|
+
const remaining = Math.max(1, deadline - Date.now());
|
|
127
|
+
await this.pollOnce(ch, Math.min(remaining, 50));
|
|
128
|
+
}
|
|
129
|
+
if (ch.rxQueue.isEmpty) {
|
|
130
|
+
throw this.setError(J2534Error.ERR_BUFFER_EMPTY, "No messages available");
|
|
131
|
+
}
|
|
132
|
+
return ch.rxQueue.drain(numMsgs);
|
|
133
|
+
}
|
|
134
|
+
// ─── PassThruWriteMsgs ──────────────────────────────────────────
|
|
135
|
+
async passThruWriteMsgs(channelId, msgs, timeout) {
|
|
136
|
+
const ch = this.getChannel(channelId);
|
|
137
|
+
let written = 0;
|
|
138
|
+
for (const msg of msgs) {
|
|
139
|
+
const cmd = buildTransmitCmd(ch.channelByte, msg);
|
|
140
|
+
await this.transport.write(cmd);
|
|
141
|
+
written++;
|
|
142
|
+
}
|
|
143
|
+
return written;
|
|
144
|
+
}
|
|
145
|
+
// ─── PassThruStartPeriodicMsg ───────────────────────────────────
|
|
146
|
+
async passThruStartPeriodicMsg(channelId, msg, intervalMs) {
|
|
147
|
+
this.assertOpen();
|
|
148
|
+
const ch = this.getChannel(channelId);
|
|
149
|
+
if (this.periodicMsgs.size >= MAX_PERIODIC_MSGS) {
|
|
150
|
+
throw this.setError(J2534Error.ERR_EXCEEDED_LIMIT, `Max ${MAX_PERIODIC_MSGS} periodic messages`);
|
|
151
|
+
}
|
|
152
|
+
if (intervalMs < 5 || intervalMs > 65535) {
|
|
153
|
+
throw this.setError(J2534Error.ERR_INVALID_TIME_INTERVAL, "Interval must be 5–65535 ms");
|
|
154
|
+
}
|
|
155
|
+
const id = this.nextPeriodicId++;
|
|
156
|
+
const state = {
|
|
157
|
+
id,
|
|
158
|
+
channelId,
|
|
159
|
+
msg: { ...msg, data: new Uint8Array(msg.data) },
|
|
160
|
+
intervalMs,
|
|
161
|
+
timer: null,
|
|
162
|
+
};
|
|
163
|
+
// Start the software timer
|
|
164
|
+
state.timer = setInterval(async () => {
|
|
165
|
+
try {
|
|
166
|
+
const cmd = buildTransmitCmd(ch.channelByte, state.msg);
|
|
167
|
+
await this.transport.write(cmd);
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
// If write fails, stop the timer
|
|
171
|
+
this.stopPeriodicTimer(id);
|
|
172
|
+
}
|
|
173
|
+
}, intervalMs);
|
|
174
|
+
this.periodicMsgs.set(id, state);
|
|
175
|
+
return id;
|
|
176
|
+
}
|
|
177
|
+
// ─── PassThruStopPeriodicMsg ────────────────────────────────────
|
|
178
|
+
async passThruStopPeriodicMsg(channelId, msgId) {
|
|
179
|
+
const pm = this.periodicMsgs.get(msgId);
|
|
180
|
+
if (!pm) {
|
|
181
|
+
throw this.setError(J2534Error.ERR_INVALID_MSG_ID, `Invalid periodic msg ID: ${msgId}`);
|
|
182
|
+
}
|
|
183
|
+
if (pm.channelId !== channelId) {
|
|
184
|
+
throw this.setError(J2534Error.ERR_INVALID_MSG_ID, "Periodic msg not on this channel");
|
|
185
|
+
}
|
|
186
|
+
this.stopPeriodicTimer(msgId);
|
|
187
|
+
this.periodicMsgs.delete(msgId);
|
|
188
|
+
}
|
|
189
|
+
// ─── PassThruStartMsgFilter ─────────────────────────────────────
|
|
190
|
+
async passThruStartMsgFilter(channelId, filterType, maskMsg, patternMsg, flowControlMsg) {
|
|
191
|
+
const ch = this.getChannel(channelId);
|
|
192
|
+
if (ch.filters.size >= MAX_FILTERS_PER_CHANNEL) {
|
|
193
|
+
throw this.setError(J2534Error.ERR_EXCEEDED_LIMIT, `Max ${MAX_FILTERS_PER_CHANNEL} filters per channel`);
|
|
194
|
+
}
|
|
195
|
+
// ISO15765 requires flow control filter before any other
|
|
196
|
+
if ((ch.protocol === Protocol.ISO15765 || ch.protocol === 0x00009040) &&
|
|
197
|
+
filterType !== FilterType.FLOW_CONTROL_FILTER &&
|
|
198
|
+
![...ch.filters.values()].some((f) => f.type === FilterType.FLOW_CONTROL_FILTER)) {
|
|
199
|
+
throw this.setError(J2534Error.ERR_NO_FLOW_CONTROL, "ISO15765 requires a flow control filter first");
|
|
200
|
+
}
|
|
201
|
+
const mask = maskMsg.data.subarray(0, maskMsg.dataSize);
|
|
202
|
+
const pattern = patternMsg.data.subarray(0, patternMsg.dataSize);
|
|
203
|
+
const flow = flowControlMsg
|
|
204
|
+
? flowControlMsg.data.subarray(0, flowControlMsg.dataSize)
|
|
205
|
+
: undefined;
|
|
206
|
+
const cmd = buildFilterCmd(ch.channelByte, filterType, maskMsg.txFlags, mask, pattern, flow);
|
|
207
|
+
await this.transport.write(cmd);
|
|
208
|
+
const resp = await this.readResponse();
|
|
209
|
+
let filterId;
|
|
210
|
+
if (resp.type === "filter_id") {
|
|
211
|
+
filterId = resp.id;
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
filterId = this.nextFilterId++;
|
|
215
|
+
}
|
|
216
|
+
ch.filters.set(filterId, {
|
|
217
|
+
type: filterType,
|
|
218
|
+
mask: new Uint8Array(mask),
|
|
219
|
+
pattern: new Uint8Array(pattern),
|
|
220
|
+
flowControl: flow ? new Uint8Array(flow) : undefined,
|
|
221
|
+
});
|
|
222
|
+
return filterId;
|
|
223
|
+
}
|
|
224
|
+
// ─── PassThruStopMsgFilter ──────────────────────────────────────
|
|
225
|
+
async passThruStopMsgFilter(channelId, filterId) {
|
|
226
|
+
const ch = this.getChannel(channelId);
|
|
227
|
+
if (!ch.filters.has(filterId)) {
|
|
228
|
+
throw this.setError(J2534Error.ERR_INVALID_FILTER_ID, `Invalid filter ID: ${filterId}`);
|
|
229
|
+
}
|
|
230
|
+
await this.transport.write(buildStopFilterCmd(ch.channelByte, filterId));
|
|
231
|
+
ch.filters.delete(filterId);
|
|
232
|
+
}
|
|
233
|
+
// ─── PassThruSetProgrammingVoltage ──────────────────────────────
|
|
234
|
+
async passThruSetProgrammingVoltage(pin, voltage) {
|
|
235
|
+
this.assertOpen();
|
|
236
|
+
// Validate pin
|
|
237
|
+
const validPins = [0, 1, 2, 3, 6, 7, 9, 10, 11, 12, 13, 14, 15, 16];
|
|
238
|
+
if (!validPins.includes(pin)) {
|
|
239
|
+
throw this.setError(J2534Error.ERR_PIN_INVALID, `Invalid pin: ${pin}`);
|
|
240
|
+
}
|
|
241
|
+
let millivolts;
|
|
242
|
+
if (voltage === VOLTAGE_OFF) {
|
|
243
|
+
millivolts = 0; // Turn off voltage
|
|
244
|
+
}
|
|
245
|
+
else if (voltage === SHORT_TO_GROUND) {
|
|
246
|
+
millivolts = -1; // Signal ground to firmware
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
millivolts = voltage; // Already in millivolts per J2534 spec
|
|
250
|
+
}
|
|
251
|
+
await this.transport.write(buildSetVoltageCmd(pin, millivolts));
|
|
252
|
+
const resp = await this.readResponse();
|
|
253
|
+
if (resp.type === "error") {
|
|
254
|
+
throw this.setError(J2534Error.ERR_FAILED, "Failed to set programming voltage");
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
// ─── readPinVoltage ────────────────────────────────────────────────
|
|
258
|
+
/**
|
|
259
|
+
* Read the current voltage on a given OBD-II pin (in millivolts).
|
|
260
|
+
* Uses the Tactrix "atr <pin>" command.
|
|
261
|
+
*/
|
|
262
|
+
async readPinVoltage(pin) {
|
|
263
|
+
this.assertOpen();
|
|
264
|
+
await this.transport.write(buildReadVoltageCmd(pin));
|
|
265
|
+
const resp = await this.readResponse();
|
|
266
|
+
if (resp.type === "voltage") {
|
|
267
|
+
return resp.millivolts;
|
|
268
|
+
}
|
|
269
|
+
throw this.setError(J2534Error.ERR_FAILED, `Failed to read voltage on pin ${pin}`);
|
|
270
|
+
}
|
|
271
|
+
// ─── PassThruReadVersion ────────────────────────────────────────
|
|
272
|
+
async passThruReadVersion() {
|
|
273
|
+
this.assertOpen();
|
|
274
|
+
return {
|
|
275
|
+
firmwareVersion: this.firmwareVersion,
|
|
276
|
+
dllVersion: "3.0.0",
|
|
277
|
+
apiVersion: "04.04",
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
// ─── PassThruGetLastError ───────────────────────────────────────
|
|
281
|
+
passThruGetLastError() {
|
|
282
|
+
return this.lastError;
|
|
283
|
+
}
|
|
284
|
+
// ─── PassThruIoctl ──────────────────────────────────────────────
|
|
285
|
+
async passThruIoctl(channelId, ioctlId, input) {
|
|
286
|
+
switch (ioctlId) {
|
|
287
|
+
case IoctlId.GET_CONFIG: {
|
|
288
|
+
const ch = this.getChannel(channelId);
|
|
289
|
+
const configs = input;
|
|
290
|
+
const results = [];
|
|
291
|
+
for (const cfg of configs) {
|
|
292
|
+
await this.transport.write(buildGetConfigCmd(ch.channelByte, cfg.parameter));
|
|
293
|
+
const resp = await this.readResponse();
|
|
294
|
+
if (resp.type === "config") {
|
|
295
|
+
results.push({ parameter: cfg.parameter, value: resp.value });
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return results;
|
|
299
|
+
}
|
|
300
|
+
case IoctlId.SET_CONFIG: {
|
|
301
|
+
const ch = this.getChannel(channelId);
|
|
302
|
+
const configs = input;
|
|
303
|
+
for (const cfg of configs) {
|
|
304
|
+
await this.transport.write(buildSetConfigCmd(ch.channelByte, cfg.parameter, cfg.value));
|
|
305
|
+
// Consume the ack so it doesn't pollute the rx buffer
|
|
306
|
+
await this.readResponse();
|
|
307
|
+
}
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
case IoctlId.READ_VBATT: {
|
|
311
|
+
await this.transport.write(buildReadVoltageCmd(16));
|
|
312
|
+
const resp = await this.readResponse();
|
|
313
|
+
if (resp.type === "voltage") {
|
|
314
|
+
return resp.millivolts;
|
|
315
|
+
}
|
|
316
|
+
throw this.setError(J2534Error.ERR_FAILED, "Failed to read voltage");
|
|
317
|
+
}
|
|
318
|
+
case IoctlId.FIVE_BAUD_INIT: {
|
|
319
|
+
const ch = this.getChannel(channelId);
|
|
320
|
+
const msg = input;
|
|
321
|
+
if (!msg || msg.dataSize < 1) {
|
|
322
|
+
throw this.setError(J2534Error.ERR_INVALID_MSG, "5-baud init requires target address byte");
|
|
323
|
+
}
|
|
324
|
+
const targetAddress = msg.data[0];
|
|
325
|
+
await this.transport.write(buildFiveBaudInitCmd(ch.channelByte, targetAddress));
|
|
326
|
+
// 5-baud init takes ~2 seconds (9 bits at 5 baud = 1800ms + response)
|
|
327
|
+
const debug = !!process.env.J2534_DEBUG;
|
|
328
|
+
let resp;
|
|
329
|
+
try {
|
|
330
|
+
const buf = await this.transport.read(5000);
|
|
331
|
+
if (debug) {
|
|
332
|
+
const hex = Array.from(buf).map((b) => b.toString(16).padStart(2, "0")).join(" ");
|
|
333
|
+
console.error(`[5baud] raw firmware response (${buf.length} bytes): ${hex}`);
|
|
334
|
+
}
|
|
335
|
+
resp = parseResponse(buf, ch.protocol);
|
|
336
|
+
}
|
|
337
|
+
catch (err) {
|
|
338
|
+
if (debug)
|
|
339
|
+
console.error(`[5baud] read timed out: ${err.message}`);
|
|
340
|
+
throw this.setError(J2534Error.ERR_FAILED, "5-baud init: no response from firmware (timeout)");
|
|
341
|
+
}
|
|
342
|
+
if (debug)
|
|
343
|
+
console.error(`[5baud] parsed:`, resp);
|
|
344
|
+
if (resp.type === "fast_init") {
|
|
345
|
+
return {
|
|
346
|
+
protocolId: ch.protocol,
|
|
347
|
+
rxStatus: 0,
|
|
348
|
+
txFlags: 0,
|
|
349
|
+
timestamp: 0,
|
|
350
|
+
dataSize: resp.data.length,
|
|
351
|
+
extraDataIndex: resp.data.length,
|
|
352
|
+
data: resp.data,
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
if (resp.type === "error") {
|
|
356
|
+
throw this.setError(J2534Error.ERR_FAILED, `5-baud init: firmware returned error code ${resp.code}`);
|
|
357
|
+
}
|
|
358
|
+
throw this.setError(J2534Error.ERR_FAILED, `5-baud init: unexpected response type "${resp.type}"`);
|
|
359
|
+
}
|
|
360
|
+
case IoctlId.FAST_INIT: {
|
|
361
|
+
const ch = this.getChannel(channelId);
|
|
362
|
+
const msg = input;
|
|
363
|
+
await this.transport.write(buildFastInitCmd(ch.channelByte, msg.data.subarray(0, msg.dataSize)));
|
|
364
|
+
const resp = await this.readResponse();
|
|
365
|
+
if (resp.type === "fast_init") {
|
|
366
|
+
return {
|
|
367
|
+
protocolId: ch.protocol,
|
|
368
|
+
rxStatus: 0,
|
|
369
|
+
txFlags: 0,
|
|
370
|
+
timestamp: 0,
|
|
371
|
+
dataSize: resp.data.length,
|
|
372
|
+
extraDataIndex: resp.data.length,
|
|
373
|
+
data: resp.data,
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
throw this.setError(J2534Error.ERR_FAILED, "Fast init failed");
|
|
377
|
+
}
|
|
378
|
+
case IoctlId.CLEAR_TX_BUFFER:
|
|
379
|
+
return; // no-op
|
|
380
|
+
case IoctlId.CLEAR_RX_BUFFER: {
|
|
381
|
+
const ch = this.getChannel(channelId);
|
|
382
|
+
ch.rxQueue.clear();
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
case IoctlId.CLEAR_PERIODIC_MSGS: {
|
|
386
|
+
for (const [id, pm] of this.periodicMsgs) {
|
|
387
|
+
if (pm.channelId === channelId) {
|
|
388
|
+
this.stopPeriodicTimer(id);
|
|
389
|
+
this.periodicMsgs.delete(id);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
case IoctlId.CLEAR_MSG_FILTERS: {
|
|
395
|
+
const ch = this.getChannel(channelId);
|
|
396
|
+
for (const [fid] of ch.filters) {
|
|
397
|
+
await this.transport.write(buildStopFilterCmd(ch.channelByte, fid));
|
|
398
|
+
}
|
|
399
|
+
ch.filters.clear();
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
case IoctlId.CLEAR_FUNCT_MSG_LOOKUP_TABLE: {
|
|
403
|
+
const ch = this.getChannel(channelId);
|
|
404
|
+
ch.functionalAddresses = [];
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
case IoctlId.ADD_TO_FUNCT_MSG_LOOKUP_TABLE: {
|
|
408
|
+
const ch = this.getChannel(channelId);
|
|
409
|
+
const byteArray = input;
|
|
410
|
+
if (!byteArray || !byteArray.data) {
|
|
411
|
+
throw this.setError(J2534Error.ERR_NULL_PARAMETER, "Byte array required");
|
|
412
|
+
}
|
|
413
|
+
// Each address is protocol-dependent size (4 bytes for CAN/ISO15765)
|
|
414
|
+
const addrSize = this.getAddressSize(ch.protocol);
|
|
415
|
+
for (let i = 0; i + addrSize <= byteArray.numOfBytes; i += addrSize) {
|
|
416
|
+
ch.functionalAddresses.push({
|
|
417
|
+
address: new Uint8Array(byteArray.data.slice(i, i + addrSize)),
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
case IoctlId.DELETE_FROM_FUNCT_MSG_LOOKUP_TABLE: {
|
|
423
|
+
const ch = this.getChannel(channelId);
|
|
424
|
+
const byteArray = input;
|
|
425
|
+
if (!byteArray || !byteArray.data) {
|
|
426
|
+
throw this.setError(J2534Error.ERR_NULL_PARAMETER, "Byte array required");
|
|
427
|
+
}
|
|
428
|
+
const addrSize = this.getAddressSize(ch.protocol);
|
|
429
|
+
for (let i = 0; i + addrSize <= byteArray.numOfBytes; i += addrSize) {
|
|
430
|
+
const toRemove = byteArray.data.slice(i, i + addrSize);
|
|
431
|
+
ch.functionalAddresses = ch.functionalAddresses.filter((fa) => !arraysEqual(fa.address, toRemove));
|
|
432
|
+
}
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
case IoctlId.READ_PROG_VOLTAGE: {
|
|
436
|
+
// Read voltage on the programming pin (same as VBATT but configurable)
|
|
437
|
+
await this.transport.write(buildReadVoltageCmd(2)); // Pin 2 (J1850P) typical
|
|
438
|
+
const resp = await this.readResponse();
|
|
439
|
+
if (resp.type === "voltage") {
|
|
440
|
+
return resp.millivolts;
|
|
441
|
+
}
|
|
442
|
+
throw this.setError(J2534Error.ERR_FAILED, "Failed to read programming voltage");
|
|
443
|
+
}
|
|
444
|
+
default:
|
|
445
|
+
throw this.setError(J2534Error.ERR_INVALID_IOCTL_ID, `Unknown IOCTL ID: ${ioctlId}`);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
// ─── Internal helpers ───────────────────────────────────────────
|
|
449
|
+
assertOpen() {
|
|
450
|
+
if (this.deviceId === null) {
|
|
451
|
+
throw this.setError(J2534Error.ERR_DEVICE_NOT_CONNECTED, "Device not open");
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
getChannel(channelId) {
|
|
455
|
+
const ch = this.channels.get(channelId);
|
|
456
|
+
if (!ch) {
|
|
457
|
+
throw this.setError(J2534Error.ERR_INVALID_CHANNEL_ID, `Invalid channel: ${channelId}`);
|
|
458
|
+
}
|
|
459
|
+
return ch;
|
|
460
|
+
}
|
|
461
|
+
validateProtocol(protocol) {
|
|
462
|
+
// SCI protocols are not supported by hardware
|
|
463
|
+
if (protocol === Protocol.SCI_A_ENGINE ||
|
|
464
|
+
protocol === Protocol.SCI_A_TRANS ||
|
|
465
|
+
protocol === Protocol.SCI_B_ENGINE ||
|
|
466
|
+
protocol === Protocol.SCI_B_TRANS) {
|
|
467
|
+
throw this.setError(J2534Error.ERR_INVALID_PROTOCOL_ID, "SCI protocols not supported by OpenPort 2.0 hardware");
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
setError(code, message) {
|
|
471
|
+
this.lastError = message;
|
|
472
|
+
return new J2534Exception(code, message);
|
|
473
|
+
}
|
|
474
|
+
async readResponse(timeout = 2000) {
|
|
475
|
+
try {
|
|
476
|
+
const buf = await this.transport.read(timeout);
|
|
477
|
+
const protocol = this.channels.size > 0
|
|
478
|
+
? this.channels.values().next().value.protocol
|
|
479
|
+
: Protocol.CAN;
|
|
480
|
+
return parseResponse(buf, protocol);
|
|
481
|
+
}
|
|
482
|
+
catch {
|
|
483
|
+
return { type: "unknown", raw: new Uint8Array(0) };
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
isKLine(protocol) {
|
|
487
|
+
return protocol === Protocol.ISO9141 || protocol === Protocol.ISO14230;
|
|
488
|
+
}
|
|
489
|
+
async pollOnce(ch, readTimeout = 1) {
|
|
490
|
+
try {
|
|
491
|
+
const buf = await this.transport.read(readTimeout);
|
|
492
|
+
if (buf.length === 0)
|
|
493
|
+
return;
|
|
494
|
+
const responses = parseAllPackets(buf, ch.protocol);
|
|
495
|
+
for (const resp of responses) {
|
|
496
|
+
if (resp.type !== "message")
|
|
497
|
+
continue;
|
|
498
|
+
const msg = resp.msg;
|
|
499
|
+
const kLine = this.isKLine(ch.protocol);
|
|
500
|
+
if (kLine) {
|
|
501
|
+
// K-line multi-packet assembly (matches C driver logic):
|
|
502
|
+
//
|
|
503
|
+
// NORM_MSG_START_IND (0x80) / TX_LB_START_IND (0xA0):
|
|
504
|
+
// Start indication — resets the pending accumulator.
|
|
505
|
+
// Not delivered to rxQueue (internal framing only).
|
|
506
|
+
//
|
|
507
|
+
// NORM_MSG (0x00) / TX_LB_MSG (0x20):
|
|
508
|
+
// Data packet — accumulate bytes into pending message.
|
|
509
|
+
// No timestamp on K-line data packets.
|
|
510
|
+
//
|
|
511
|
+
// RX_MSG_END_IND (0x40) / LB_MSG_END_IND (0x60):
|
|
512
|
+
// End indication — finalize pending message with timestamp
|
|
513
|
+
// and deliver the assembled message to rxQueue.
|
|
514
|
+
//
|
|
515
|
+
// TX_DONE (0x10):
|
|
516
|
+
// TX confirmation — not delivered (internal framing only).
|
|
517
|
+
// Determine packet type from rxStatus flags
|
|
518
|
+
const isTx = (msg.rxStatus & RxStatus.TX_MSG_TYPE) !== 0;
|
|
519
|
+
const isStart = (msg.rxStatus & RxStatus.START_OF_MESSAGE) !== 0;
|
|
520
|
+
if (isStart) {
|
|
521
|
+
// Start indication — reset accumulator, do NOT enqueue
|
|
522
|
+
ch.pendingMsg = {
|
|
523
|
+
data: [],
|
|
524
|
+
rxStatus: isTx ? RxStatus.TX_MSG_TYPE : 0,
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
else if (msg.dataSize > 0 && msg.timestamp === 0) {
|
|
528
|
+
// Data packet (NORM_MSG or TX_LB_MSG) — accumulate
|
|
529
|
+
if (!ch.pendingMsg) {
|
|
530
|
+
ch.pendingMsg = {
|
|
531
|
+
data: [],
|
|
532
|
+
rxStatus: isTx ? RxStatus.TX_MSG_TYPE : 0,
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
for (let i = 0; i < msg.dataSize; i++) {
|
|
536
|
+
ch.pendingMsg.data.push(msg.data[i]);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
else if (msg.dataSize === 0 && msg.timestamp !== 0 && !isStart) {
|
|
540
|
+
// End indication (RX_MSG_END_IND or LB_MSG_END_IND or TX_DONE)
|
|
541
|
+
// Finalize the pending message
|
|
542
|
+
if (ch.pendingMsg && ch.pendingMsg.data.length > 0) {
|
|
543
|
+
const finalData = new Uint8Array(ch.pendingMsg.data);
|
|
544
|
+
this.enqueueMsg(ch, {
|
|
545
|
+
protocolId: ch.protocol,
|
|
546
|
+
rxStatus: ch.pendingMsg.rxStatus,
|
|
547
|
+
txFlags: 0,
|
|
548
|
+
timestamp: msg.timestamp,
|
|
549
|
+
dataSize: finalData.length,
|
|
550
|
+
extraDataIndex: finalData.length,
|
|
551
|
+
data: finalData,
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
ch.pendingMsg = null;
|
|
555
|
+
}
|
|
556
|
+
else {
|
|
557
|
+
// Fallback — deliver as-is
|
|
558
|
+
this.enqueueMsg(ch, msg);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
else {
|
|
562
|
+
// CAN/ISO15765: each packet is self-contained with timestamp
|
|
563
|
+
this.enqueueMsg(ch, msg);
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
catch {
|
|
568
|
+
// timeout or no data — expected
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
enqueueMsg(ch, msg) {
|
|
572
|
+
if (ch.functionalAddresses.length > 0) {
|
|
573
|
+
if (this.matchesFunctionalAddress(ch, msg)) {
|
|
574
|
+
ch.rxQueue.push(msg);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
else {
|
|
578
|
+
ch.rxQueue.push(msg);
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
matchesFunctionalAddress(ch, msg) {
|
|
582
|
+
const addrSize = this.getAddressSize(ch.protocol);
|
|
583
|
+
if (msg.dataSize < addrSize)
|
|
584
|
+
return false;
|
|
585
|
+
const msgAddr = msg.data.subarray(0, addrSize);
|
|
586
|
+
return ch.functionalAddresses.some((fa) => arraysEqual(fa.address, msgAddr));
|
|
587
|
+
}
|
|
588
|
+
getAddressSize(protocol) {
|
|
589
|
+
switch (protocol) {
|
|
590
|
+
case Protocol.CAN:
|
|
591
|
+
case Protocol.ISO15765:
|
|
592
|
+
case 0x00009000: // CAN_CH1
|
|
593
|
+
case 0x00009040: // ISO15765_CH1
|
|
594
|
+
return 4;
|
|
595
|
+
default:
|
|
596
|
+
return 1;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
stopPeriodicTimer(id) {
|
|
600
|
+
const pm = this.periodicMsgs.get(id);
|
|
601
|
+
if (pm?.timer) {
|
|
602
|
+
clearInterval(pm.timer);
|
|
603
|
+
pm.timer = null;
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
// ─── Exception ──────────────────────────────────────────────────────
|
|
608
|
+
/**
|
|
609
|
+
* J2534 error with status code.
|
|
610
|
+
*/
|
|
611
|
+
export class J2534Exception extends Error {
|
|
612
|
+
code;
|
|
613
|
+
constructor(code, message) {
|
|
614
|
+
super(message);
|
|
615
|
+
this.code = code;
|
|
616
|
+
this.name = "J2534Exception";
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
// ─── Utilities ──────────────────────────────────────────────────────
|
|
620
|
+
function sleep(ms) {
|
|
621
|
+
return new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
|
|
622
|
+
}
|
|
623
|
+
function arraysEqual(a, b) {
|
|
624
|
+
if (a.length !== b.length)
|
|
625
|
+
return false;
|
|
626
|
+
for (let i = 0; i < a.length; i++) {
|
|
627
|
+
if (a[i] !== b[i])
|
|
628
|
+
return false;
|
|
629
|
+
}
|
|
630
|
+
return true;
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* Helper to create a PassThruMsg for use in filter setup, writes, etc.
|
|
634
|
+
*/
|
|
635
|
+
export function createMsg(protocol, data, txFlags = 0) {
|
|
636
|
+
const buf = new Uint8Array(4128);
|
|
637
|
+
buf.set(data);
|
|
638
|
+
return {
|
|
639
|
+
protocolId: protocol,
|
|
640
|
+
rxStatus: 0,
|
|
641
|
+
txFlags,
|
|
642
|
+
timestamp: 0,
|
|
643
|
+
dataSize: data.length,
|
|
644
|
+
extraDataIndex: data.length,
|
|
645
|
+
data: buf,
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@emdzej/j2534-driver",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "J2534Device — full SAE J2534 PassThru API implementation for Tactrix OpenPort 2.0. Supports CAN (11/29-bit), ISO 15765 (ISO-TP / UDS), ISO 9141 (K-line slow init) and ISO 14230 (KWP2000 fast init). Transport-agnostic — pair with @emdzej/j2534-serial, @emdzej/j2534-usb, @emdzej/j2534-webserial or @emdzej/j2534-webusb.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"j2534",
|
|
7
|
+
"passthru",
|
|
8
|
+
"obd",
|
|
9
|
+
"obd-ii",
|
|
10
|
+
"tactrix",
|
|
11
|
+
"openport",
|
|
12
|
+
"diagnostics",
|
|
13
|
+
"kwp2000",
|
|
14
|
+
"can",
|
|
15
|
+
"iso15765",
|
|
16
|
+
"iso9141",
|
|
17
|
+
"iso14230",
|
|
18
|
+
"uds",
|
|
19
|
+
"iso-tp",
|
|
20
|
+
"k-line",
|
|
21
|
+
"typescript"
|
|
22
|
+
],
|
|
23
|
+
"homepage": "https://github.com/emdzej/j2534#readme",
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/emdzej/j2534.git",
|
|
27
|
+
"directory": "packages/driver"
|
|
28
|
+
},
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/emdzej/j2534/issues"
|
|
31
|
+
},
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"author": "Michał Jaskólski",
|
|
34
|
+
"type": "module",
|
|
35
|
+
"main": "./dist/index.js",
|
|
36
|
+
"types": "./dist/index.d.ts",
|
|
37
|
+
"exports": {
|
|
38
|
+
".": {
|
|
39
|
+
"types": "./dist/index.d.ts",
|
|
40
|
+
"import": "./dist/index.js"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"files": [
|
|
44
|
+
"dist",
|
|
45
|
+
"README.md",
|
|
46
|
+
"LICENSE"
|
|
47
|
+
],
|
|
48
|
+
"sideEffects": false,
|
|
49
|
+
"publishConfig": {
|
|
50
|
+
"access": "public"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"@emdzej/j2534-types": "0.1.0",
|
|
54
|
+
"@emdzej/j2534-core": "0.1.0"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@types/node": "^25.6.0",
|
|
58
|
+
"typescript": "^5.7.0"
|
|
59
|
+
},
|
|
60
|
+
"scripts": {
|
|
61
|
+
"build": "tsc",
|
|
62
|
+
"dev": "tsc --watch",
|
|
63
|
+
"clean": "rm -rf dist"
|
|
64
|
+
}
|
|
65
|
+
}
|