@kb1rma/libcomm14cux-ts 0.0.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 (134) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +154 -0
  3. package/dist/bytes.d.ts +9 -0
  4. package/dist/bytes.d.ts.map +1 -0
  5. package/dist/bytes.js +13 -0
  6. package/dist/bytes.js.map +1 -0
  7. package/dist/constants.d.ts +174 -0
  8. package/dist/constants.d.ts.map +1 -0
  9. package/dist/constants.js +122 -0
  10. package/dist/constants.js.map +1 -0
  11. package/dist/decoders/airflow.d.ts +19 -0
  12. package/dist/decoders/airflow.d.ts.map +1 -0
  13. package/dist/decoders/airflow.js +36 -0
  14. package/dist/decoders/airflow.js.map +1 -0
  15. package/dist/decoders/engineSpeed.d.ts +20 -0
  16. package/dist/decoders/engineSpeed.d.ts.map +1 -0
  17. package/dist/decoders/engineSpeed.js +33 -0
  18. package/dist/decoders/engineSpeed.js.map +1 -0
  19. package/dist/decoders/faultCodes.d.ts +19 -0
  20. package/dist/decoders/faultCodes.d.ts.map +1 -0
  21. package/dist/decoders/faultCodes.js +48 -0
  22. package/dist/decoders/faultCodes.js.map +1 -0
  23. package/dist/decoders/flags.d.ts +45 -0
  24. package/dist/decoders/flags.d.ts.map +1 -0
  25. package/dist/decoders/flags.js +54 -0
  26. package/dist/decoders/flags.js.map +1 -0
  27. package/dist/decoders/fuelMap.d.ts +89 -0
  28. package/dist/decoders/fuelMap.d.ts.map +1 -0
  29. package/dist/decoders/fuelMap.js +109 -0
  30. package/dist/decoders/fuelMap.js.map +1 -0
  31. package/dist/decoders/gear.d.ts +10 -0
  32. package/dist/decoders/gear.d.ts.map +1 -0
  33. package/dist/decoders/gear.js +23 -0
  34. package/dist/decoders/gear.js.map +1 -0
  35. package/dist/decoders/idleBypass.d.ts +8 -0
  36. package/dist/decoders/idleBypass.d.ts.map +1 -0
  37. package/dist/decoders/idleBypass.js +15 -0
  38. package/dist/decoders/idleBypass.js.map +1 -0
  39. package/dist/decoders/lambdaTrim.d.ts +15 -0
  40. package/dist/decoders/lambdaTrim.d.ts.map +1 -0
  41. package/dist/decoders/lambdaTrim.js +23 -0
  42. package/dist/decoders/lambdaTrim.js.map +1 -0
  43. package/dist/decoders/mainVoltage.d.ts +14 -0
  44. package/dist/decoders/mainVoltage.d.ts.map +1 -0
  45. package/dist/decoders/mainVoltage.js +26 -0
  46. package/dist/decoders/mainVoltage.js.map +1 -0
  47. package/dist/decoders/roadSpeed.d.ts +8 -0
  48. package/dist/decoders/roadSpeed.d.ts.map +1 -0
  49. package/dist/decoders/roadSpeed.js +14 -0
  50. package/dist/decoders/roadSpeed.js.map +1 -0
  51. package/dist/decoders/romRevision.d.ts +18 -0
  52. package/dist/decoders/romRevision.d.ts.map +1 -0
  53. package/dist/decoders/romRevision.js +26 -0
  54. package/dist/decoders/romRevision.js.map +1 -0
  55. package/dist/decoders/temperature.d.ts +12 -0
  56. package/dist/decoders/temperature.d.ts.map +1 -0
  57. package/dist/decoders/temperature.js +39 -0
  58. package/dist/decoders/temperature.js.map +1 -0
  59. package/dist/decoders/throttle.d.ts +18 -0
  60. package/dist/decoders/throttle.d.ts.map +1 -0
  61. package/dist/decoders/throttle.js +33 -0
  62. package/dist/decoders/throttle.js.map +1 -0
  63. package/dist/decoders/tuneRevision.d.ts +25 -0
  64. package/dist/decoders/tuneRevision.d.ts.map +1 -0
  65. package/dist/decoders/tuneRevision.js +22 -0
  66. package/dist/decoders/tuneRevision.js.map +1 -0
  67. package/dist/ecu.d.ts +473 -0
  68. package/dist/ecu.d.ts.map +1 -0
  69. package/dist/ecu.js +700 -0
  70. package/dist/ecu.js.map +1 -0
  71. package/dist/errors.d.ts +31 -0
  72. package/dist/errors.d.ts.map +1 -0
  73. package/dist/errors.js +33 -0
  74. package/dist/errors.js.map +1 -0
  75. package/dist/index.d.ts +11 -0
  76. package/dist/index.d.ts.map +1 -0
  77. package/dist/index.js +8 -0
  78. package/dist/index.js.map +1 -0
  79. package/dist/protocol/protocol.d.ts +57 -0
  80. package/dist/protocol/protocol.d.ts.map +1 -0
  81. package/dist/protocol/protocol.js +137 -0
  82. package/dist/protocol/protocol.js.map +1 -0
  83. package/dist/protocol/readCount.d.ts +21 -0
  84. package/dist/protocol/readCount.d.ts.map +1 -0
  85. package/dist/protocol/readCount.js +30 -0
  86. package/dist/protocol/readCount.js.map +1 -0
  87. package/dist/queue.d.ts +15 -0
  88. package/dist/queue.d.ts.map +1 -0
  89. package/dist/queue.js +21 -0
  90. package/dist/queue.js.map +1 -0
  91. package/dist/transport/simulated.d.ts +65 -0
  92. package/dist/transport/simulated.d.ts.map +1 -0
  93. package/dist/transport/simulated.js +190 -0
  94. package/dist/transport/simulated.js.map +1 -0
  95. package/dist/transport/types.d.ts +9 -0
  96. package/dist/transport/types.d.ts.map +1 -0
  97. package/dist/transport/types.js +4 -0
  98. package/dist/transport/types.js.map +1 -0
  99. package/dist/transport/webSerial.d.ts +49 -0
  100. package/dist/transport/webSerial.d.ts.map +1 -0
  101. package/dist/transport/webSerial.js +129 -0
  102. package/dist/transport/webSerial.js.map +1 -0
  103. package/dist/version.d.ts +18 -0
  104. package/dist/version.d.ts.map +1 -0
  105. package/dist/version.js +5 -0
  106. package/dist/version.js.map +1 -0
  107. package/package.json +58 -0
  108. package/src/bytes.ts +13 -0
  109. package/src/constants.ts +175 -0
  110. package/src/decoders/airflow.ts +41 -0
  111. package/src/decoders/engineSpeed.ts +36 -0
  112. package/src/decoders/faultCodes.ts +61 -0
  113. package/src/decoders/flags.ts +64 -0
  114. package/src/decoders/fuelMap.ts +167 -0
  115. package/src/decoders/gear.ts +26 -0
  116. package/src/decoders/idleBypass.ts +16 -0
  117. package/src/decoders/lambdaTrim.ts +24 -0
  118. package/src/decoders/mainVoltage.ts +37 -0
  119. package/src/decoders/roadSpeed.ts +14 -0
  120. package/src/decoders/romRevision.ts +30 -0
  121. package/src/decoders/temperature.ts +42 -0
  122. package/src/decoders/throttle.ts +37 -0
  123. package/src/decoders/tuneRevision.ts +42 -0
  124. package/src/ecu.ts +948 -0
  125. package/src/errors.ts +38 -0
  126. package/src/index.ts +16 -0
  127. package/src/protocol/protocol.ts +167 -0
  128. package/src/protocol/readCount.ts +45 -0
  129. package/src/queue.ts +24 -0
  130. package/src/test-support/ecu.ts +126 -0
  131. package/src/transport/simulated.ts +220 -0
  132. package/src/transport/types.ts +11 -0
  133. package/src/transport/webSerial.ts +163 -0
  134. package/src/version.ts +21 -0
package/README.md ADDED
@@ -0,0 +1,154 @@
1
+ # comm14cux-ts
2
+
3
+ TypeScript library for communicating with the Lucas 14CUX engine ECU over its serial diagnostic port, using the Web Serial API.
4
+
5
+ > **Status:** pre-release. The v1 goal is to mirror the public surface of libcomm14cux as closely as possible; every function of the C library has a corresponding method on `Ecu`.
6
+
7
+ ## Purpose
8
+
9
+ The Lucas 14CUX was fitted to Rover V8 engines in Land Rover vehicles from 1990 to 1995, and to low-volume sports cars (TVR, Morgan, etc.) through the 1990s. Its diagnostic serial port gives direct access to the ECU's memory, which exposes live engine data, fault codes, fuel maps and the firmware ROM.
10
+
11
+ The existing tool for this is [RoverGauge](https://github.com/colinbourassa/rovergauge), a Qt desktop app built on the C library [libcomm14cux](https://github.com/colinbourassa/libcomm14cux), both by Colin Bourassa. This project ports the library's protocol and data-decoding logic to TypeScript.
12
+
13
+ This project is not affiliated with or endorsed by the author of libcomm14cux or RoverGauge.
14
+
15
+ ## Usage
16
+
17
+ ```ts
18
+ import { Ecu, WebSerialTransport, AirflowType } from 'comm14cux-ts';
19
+
20
+ const port = await navigator.serial.requestPort();
21
+ const ecu = new Ecu(new WebSerialTransport(port));
22
+
23
+ await ecu.connect();
24
+ console.log(await ecu.getEngineRPM());
25
+ console.log(await ecu.getMAFReading(AirflowType.Linearized));
26
+ await ecu.disconnect();
27
+ ```
28
+
29
+ Methods are named after the `c14cux_*` functions (`getCoolantTemp`, `getFuelMap`, `clearFaultCodes`, …). Where the C functions return `false`, these methods reject with an error from the `Comm14cuxError` family.
30
+
31
+ ## Scope
32
+
33
+ Capabilities, matching what libcomm14cux provides:
34
+
35
+ - **Live data:** engine RPM, road speed, coolant and fuel temperature, MAF reading, throttle position, short- and long-term lambda trims, main voltage, idle bypass motor position, target idle, injector pulse width, gear selection, CO trim voltage, MIL, fuel pump relay, purge valve and other output states
36
+ - **Fault codes:** read and clear
37
+ - **Fuel maps:** read any of the maps, the RPM table and the current map row/column indices
38
+ - **ROM:** dump the 16 KB firmware image, read tune revision and ident
39
+ - **Tests:** run the fuel pump; drive the idle air control motor
40
+ - **Raw access:** read and write arbitrary memory addresses
41
+
42
+ ## Hardware
43
+
44
+ The library needs the same interface cable as RoverGauge: a 5 V FTDI USB-to-serial cable with its Rx line inverted in the FTDI EEPROM and a ~390 Ω resistor between Rx and GND. See the [RoverGauge README](https://github.com/colinbourassa/rovergauge#building-interface-cable) for build instructions.
45
+
46
+ **Recommended:** while programming the Rx inversion with FT_PROG (or `ft232r_prog` on Linux), also set the FTDI **latency timer to 1–2 ms**. The protocol waits for an echo of almost every command byte, and the default 16 ms latency timer delays each one. Web Serial cannot change this setting, so it has to be stored in the cable's EEPROM.
47
+
48
+ ## Design
49
+
50
+ ```
51
+ ┌─────────────────────────────────────────────┐
52
+ │ Ecu high-level, typed readings │ getEngineRpm(), getFaultCodes(), dumpRom() …
53
+ ├─────────────────────────────────────────────┤
54
+ │ Decoders pure functions, no I/O │ raw bytes → engineering units
55
+ ├─────────────────────────────────────────────┤
56
+ │ Protocol readMem / writeMem │ command framing, echo checks, coarse-address cache
57
+ ├─────────────────────────────────────────────┤
58
+ │ CommandQueue one operation at a time │ replaces libcomm14cux's mutex
59
+ ├─────────────────────────────────────────────┤
60
+ │ Transport bytes in / bytes out │ WebSerialTransport │ SimulatedTransport
61
+ └─────────────────────────────────────────────┘
62
+ ```
63
+
64
+ ### Transport
65
+
66
+ A minimal interface so the protocol code never touches a platform API directly:
67
+
68
+ ```ts
69
+ interface Transport {
70
+ open(): Promise<void>;
71
+ close(): Promise<void>;
72
+ write(data: Uint8Array): Promise<void>;
73
+ /** Resolves with exactly `length` bytes, or rejects with a TimeoutError. */
74
+ read(length: number, timeoutMs: number): Promise<Uint8Array>;
75
+ }
76
+ ```
77
+
78
+ - **`WebSerialTransport`** wraps a `SerialPort` and opens it at **7812 baud, 8N1, no flow control**. An option allows 15625 baud for ECUs running modified double-speed firmware. The default read timeout is 100 ms of silence, matching libcomm14cux.
79
+ - **`SimulatedTransport`** emulates the ECU's side of the protocol over an in-memory address space. It is used for tests and for developing the UI without a car.
80
+
81
+ Electron apps use `WebSerialTransport` as-is. Other transports (for example Node's `serialport`) can be added without changing the layers above.
82
+
83
+ ### Protocol
84
+
85
+ All ECU access is memory reads and writes:
86
+
87
+ | Step | Bytes sent | ECU response |
88
+ |---|---|---|
89
+ | Set coarse address | `(lenCode << 2) \| (addr >> 14)`, then `(addr >> 6) & 0xFF` | Echoes each byte |
90
+ | Read | `0xC0 \| (addr & 0x3F)` | Streams the requested bytes (no echo) |
91
+ | Write | `0x80 \| (addr & 0x3F)`, then the value | Echoes each byte |
92
+
93
+ - A single read returns 1–16, 80, 100, 400 or 512 bytes. Longer reads are split into chunks.
94
+ - When the next read uses the same length and falls in the same 64-byte block as the last coarse address, the coarse-address step is skipped. libcomm14cux compares a 64-byte window starting at the last (unaligned) address instead, which can read from the wrong block; this library deliberately does not.
95
+ - Any echo mismatch or timeout fails the operation and clears the coarse-address cache.
96
+ - Long reads (such as a ROM dump) can be stopped with `ecu.cancelRead()`, as in libcomm14cux.
97
+
98
+ ### CommandQueue
99
+
100
+ The ECU can only handle one command sequence at a time. The queue serialises every public `Ecu` call, so a UI can poll live data and request a fuel map without interleaving bytes on the wire.
101
+
102
+ ### Decoders and Ecu
103
+
104
+ Decoders are pure functions that turn raw memory into values (°F/°C, mph/kph, volts, percentages). They include the ROM revision detection that selects memory offsets for older and newer firmware. `Ecu` combines the queue, protocol and decoders into the public API.
105
+
106
+ ### Layout
107
+
108
+ ```
109
+ src/
110
+ transport/ Transport interface, WebSerialTransport, SimulatedTransport
111
+ protocol/ Protocol (readMem / writeMem), read chunking
112
+ queue.ts CommandQueue
113
+ decoders/ per-reading conversion functions (pure)
114
+ constants.ts memory addresses, enums, ROM-revision tables
115
+ ecu.ts public API
116
+ index.ts
117
+ ecu.*.test.ts tests, by feature, through the public API
118
+ test-support/ shared test helpers (not published)
119
+ ```
120
+
121
+ Tests import only from `src/index.ts`, as a user of the library would, and drive the `Ecu` against `SimulatedTransport` (or `WebSerialTransport` against a fake `SerialPort`). Wire-level behaviour is checked through `SimulatedTransport.written`.
122
+
123
+ ## Platform support
124
+
125
+ Web Serial works in Chromium-based desktop browsers (Chrome, Edge, Opera), Firefox 151+ on desktop, and Chrome 148+ on Android. It does **not** work in Safari or any browser on iOS/iPadOS. The page must be served over HTTPS or from `localhost`.
126
+
127
+ On Linux, the user needs permission to access the serial device (usually membership in the `dialout` group).
128
+
129
+ ## Safety
130
+
131
+ Writing to ECU memory, running the fuel pump or driving the idle air control motor can affect a running engine. These functions are exposed deliberately and should be used with care. This software is provided with absolutely no warranty.
132
+
133
+ ## Credits and licence
134
+
135
+ The protocol and decoding logic are derived from [libcomm14cux](https://github.com/colinbourassa/libcomm14cux) © Colin Bourassa, licensed under the GNU GPL v3.
136
+
137
+ This project is therefore licensed under the **GNU General Public License v3.0 only** (`GPL-3.0-only`). Any application that includes this library must also be distributed under GPL-3.0-compatible terms, with its source code available.
138
+
139
+ Parts of this project were written with the help of an AI assistant. The original libcomm14cux and RoverGauge projects do not accept AI-generated contributions, so nothing from this repository will be submitted to them.
140
+
141
+ ## Development
142
+
143
+ Requires Node.js (see `.nvmrc`).
144
+
145
+ ```sh
146
+ npm ci
147
+ npm run lint # ESLint + Prettier
148
+ npm run type:check # tsc --noEmit, strict
149
+ npm test # Vitest watch mode
150
+ npm run test:coverage # enforces the coverage thresholds in vitest.config.ts
151
+ npm run build # emits dist/ with declarations and source maps
152
+ ```
153
+
154
+ The behavioural specification, derived from libcomm14cux, is in [docs/test-specification.md](docs/test-specification.md).
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Reads an unsigned big-endian 16-bit value, the ECU's byte order.
3
+ *
4
+ * @param bytes - Buffer to read from.
5
+ * @param offset - Index of the high byte. Defaults to 0.
6
+ * @returns The value, 0 to 65535. A missing byte is treated as 0.
7
+ */
8
+ export declare function be16(bytes: Uint8Array, offset?: number): number;
9
+ //# sourceMappingURL=bytes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bytes.d.ts","sourceRoot":"","sources":["../src/bytes.ts"],"names":[],"mappings":"AAGA;;;;;;GAMG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,SAAI,GAAG,MAAM,CAE1D"}
package/dist/bytes.js ADDED
@@ -0,0 +1,13 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ // Copyright (C) 2026 comm14cux-ts contributors
3
+ /**
4
+ * Reads an unsigned big-endian 16-bit value, the ECU's byte order.
5
+ *
6
+ * @param bytes - Buffer to read from.
7
+ * @param offset - Index of the high byte. Defaults to 0.
8
+ * @returns The value, 0 to 65535. A missing byte is treated as 0.
9
+ */
10
+ export function be16(bytes, offset = 0) {
11
+ return ((bytes[offset] ?? 0) << 8) | (bytes[offset + 1] ?? 0);
12
+ }
13
+ //# sourceMappingURL=bytes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bytes.js","sourceRoot":"","sources":["../src/bytes.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,+CAA+C;AAE/C;;;;;;GAMG;AACH,MAAM,UAAU,IAAI,CAAC,KAAiB,EAAE,MAAM,GAAG,CAAC;IAChD,OAAO,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAChE,CAAC","sourcesContent":["// SPDX-License-Identifier: GPL-3.0-only\n// Copyright (C) 2026 comm14cux-ts contributors\n\n/**\n * Reads an unsigned big-endian 16-bit value, the ECU's byte order.\n *\n * @param bytes - Buffer to read from.\n * @param offset - Index of the high byte. Defaults to 0.\n * @returns The value, 0 to 65535. A missing byte is treated as 0.\n */\nexport function be16(bytes: Uint8Array, offset = 0): number {\n return ((bytes[offset] ?? 0) << 8) | (bytes[offset + 1] ?? 0);\n}\n"]}
@@ -0,0 +1,174 @@
1
+ /** Baud rate of the 14CUX serial port. */
2
+ export declare const BAUD = 7812;
3
+ /** Baud rate used by ECUs running modified double-speed firmware. */
4
+ export declare const BAUD_DOUBLE_SPEED = 15625;
5
+ /** Number of engine speed ranges in the fuel maps. */
6
+ export declare const FUEL_MAP_COLUMNS = 16;
7
+ /** Number of engine load ranges in the fuel maps. */
8
+ export declare const FUEL_MAP_ROWS = 8;
9
+ /** Byte quantities that may be requested in a single read (`c14cux_readcount`). */
10
+ export declare const ReadCount: {
11
+ readonly Count0: 16;
12
+ readonly Count1: 80;
13
+ readonly Count2: 100;
14
+ readonly Count3: 400;
15
+ readonly Count4: 512;
16
+ };
17
+ /** Length codes sent to the ECU for the fixed read quantities. */
18
+ export declare const ReadCountValue: {
19
+ readonly Count1: 16;
20
+ readonly Count2: 17;
21
+ readonly Count3: 18;
22
+ readonly Count4: 19;
23
+ };
24
+ /** Sizes in bytes of fixed-size structures within the ROM. */
25
+ export declare const DataSize: {
26
+ readonly ROM: 16384;
27
+ readonly FuelMap: 128;
28
+ };
29
+ /** Important memory offsets in the ECU's address space (`c14cux_memory_offset`). */
30
+ export declare const MemoryOffset: {
31
+ readonly ROMAddress: 49152;
32
+ readonly RPMTable: 51200;
33
+ readonly Port1: 2;
34
+ readonly LongTermLambdaFuelingTrimOdd: 66;
35
+ readonly LongTermLambdaFuelingTrimEven: 70;
36
+ readonly ShortTermLambdaFuelingTrimOdd: 101;
37
+ readonly ShortTermLambdaFuelingTrimEven: 103;
38
+ readonly FaultCodes: 73;
39
+ readonly ThrottleMinimumPosition: 81;
40
+ readonly MainVoltage: 85;
41
+ readonly MassAirflowDirect: 87;
42
+ readonly ThrottlePosition: 95;
43
+ readonly CoolantTemp: 106;
44
+ readonly IdleBypassPosition: 109;
45
+ readonly EngineSpeedInstantaneous: 122;
46
+ readonly EngineSpeedFiltered: 124;
47
+ readonly InjectorPulseWidth: 130;
48
+ readonly Bits008A: 138;
49
+ readonly PurgeValveState: 150;
50
+ readonly Bits00DD: 221;
51
+ readonly TransmissionGear: 8192;
52
+ readonly RoadSpeed: 8195;
53
+ readonly FuelTemp: 8198;
54
+ readonly RowScaler: 8202;
55
+ readonly RPMLimit: 8204;
56
+ readonly IdleMode: 8263;
57
+ readonly MassAirflowLinear: 8269;
58
+ readonly TargetIdleSpeed: 8273;
59
+ readonly RevBMainVoltageFactorA: 51099;
60
+ readonly RevBMainVoltageFactorB: 51100;
61
+ readonly RevBMainVoltageFactorC: 51101;
62
+ readonly RevCMainVoltageFactorA: 51139;
63
+ readonly RevCMainVoltageFactorB: 51140;
64
+ readonly RevCMainVoltageFactorC: 51141;
65
+ readonly MAFRowScaler: 49607;
66
+ readonly Map0RowScalerInitValue: 49609;
67
+ readonly FuelMap0: 49152;
68
+ readonly NewFuelMap1: 49767;
69
+ readonly NewFuelMap2: 50041;
70
+ readonly NewFuelMap3: 50315;
71
+ readonly NewFuelMap4: 50589;
72
+ readonly NewFuelMap5: 50863;
73
+ readonly OldFuelMap1: 49727;
74
+ readonly OldFuelMap2: 50001;
75
+ readonly OldFuelMap3: 50275;
76
+ readonly OldFuelMap4: 50549;
77
+ readonly OldFuelMap5: 50823;
78
+ readonly TuneRevision: 65513;
79
+ readonly ChecksumFixer: 65515;
80
+ readonly TuneIdent: 65516;
81
+ readonly CurrentFuelMapId: 8236;
82
+ readonly FuelMapRowIndex: 91;
83
+ readonly FuelMapColumnIndex: 92;
84
+ readonly IdleAirControlStepCount: 117;
85
+ readonly FuelPumpTimer: 175;
86
+ };
87
+ /** Offset from the start of a fuel map to its row scaler. */
88
+ export declare const FUEL_MAP_ROW_SCALER_OFFSET = 266;
89
+ /** Fixed main-voltage coefficients for very old ECUs (1990 and earlier). */
90
+ export declare const RevAMainVoltageFactor: {
91
+ readonly A: 100;
92
+ readonly B: 189;
93
+ readonly C: 24960;
94
+ };
95
+ /** Transmission gear selections. */
96
+ export declare const Gear: {
97
+ readonly NoReading: 0;
98
+ readonly ParkOrNeutral: 1;
99
+ readonly DriveOrReverse: 2;
100
+ readonly ManualGearbox: 3;
101
+ };
102
+ /**
103
+ * Union of the {@link Gear} values.
104
+ */
105
+ export type Gear = (typeof Gear)[keyof typeof Gear];
106
+ /** The two engine banks. */
107
+ export declare const Bank: {
108
+ readonly Odd: 0;
109
+ readonly Even: 1;
110
+ };
111
+ /**
112
+ * Union of the {@link Bank} values.
113
+ */
114
+ export type Bank = (typeof Bank)[keyof typeof Bank];
115
+ /** Types of lambda trim for fueling. */
116
+ export declare const LambdaTrimType: {
117
+ readonly ShortTerm: 0;
118
+ readonly LongTerm: 1;
119
+ };
120
+ /**
121
+ * Union of the {@link LambdaTrimType} values.
122
+ */
123
+ export type LambdaTrimType = (typeof LambdaTrimType)[keyof typeof LambdaTrimType];
124
+ /** Fueling feedback modes. */
125
+ export declare const FeedbackMode: {
126
+ readonly ClosedLoop: 0;
127
+ readonly OpenLoop: 1;
128
+ };
129
+ /**
130
+ * Union of the {@link FeedbackMode} values.
131
+ */
132
+ export type FeedbackMode = (typeof FeedbackMode)[keyof typeof FeedbackMode];
133
+ /** The two means of reading a value from the MAF. */
134
+ export declare const AirflowType: {
135
+ readonly Direct: 0;
136
+ readonly Linearized: 1;
137
+ };
138
+ /**
139
+ * Union of the {@link AirflowType} values.
140
+ */
141
+ export type AirflowType = (typeof AirflowType)[keyof typeof AirflowType];
142
+ /** The two methods of interpreting a throttle position. */
143
+ export declare const ThrottlePosType: {
144
+ readonly Absolute: 0;
145
+ readonly Corrected: 1;
146
+ };
147
+ /**
148
+ * Union of the {@link ThrottlePosType} values.
149
+ */
150
+ export type ThrottlePosType = (typeof ThrottlePosType)[keyof typeof ThrottlePosType];
151
+ /** Revisions of the ROM data layout (`c14cux_data_offset_rev`). */
152
+ export declare const DataOffsetRev: {
153
+ readonly Unset: 0;
154
+ readonly RevA: 1;
155
+ readonly RevB: 2;
156
+ readonly RevC: 3;
157
+ };
158
+ /**
159
+ * Union of the {@link DataOffsetRev} values.
160
+ */
161
+ export type DataOffsetRev = (typeof DataOffsetRev)[keyof typeof DataOffsetRev];
162
+ /** States of the carbon canister purge valve. */
163
+ export declare const PurgeValveState: {
164
+ readonly Closed: 0;
165
+ readonly Toggling: 1;
166
+ readonly Open: 2;
167
+ };
168
+ /**
169
+ * Union of the {@link PurgeValveState} values.
170
+ */
171
+ export type PurgeValveState = (typeof PurgeValveState)[keyof typeof PurgeValveState];
172
+ /** Default per-read silence timeout, matching libcomm14cux (100 ms). */
173
+ export declare const DEFAULT_READ_TIMEOUT_MS = 100;
174
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAKA,0CAA0C;AAC1C,eAAO,MAAM,IAAI,OAAO,CAAC;AAEzB,qEAAqE;AACrE,eAAO,MAAM,iBAAiB,QAAQ,CAAC;AAEvC,sDAAsD;AACtD,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAEnC,qDAAqD;AACrD,eAAO,MAAM,aAAa,IAAI,CAAC;AAE/B,mFAAmF;AACnF,eAAO,MAAM,SAAS;;;;;;CAMZ,CAAC;AAEX,kEAAkE;AAClE,eAAO,MAAM,cAAc;;;;;CAKjB,CAAC;AAEX,8DAA8D;AAC9D,eAAO,MAAM,QAAQ;;;CAGX,CAAC;AAEX,oFAAoF;AACpF,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwDf,CAAC;AAEX,6DAA6D;AAC7D,eAAO,MAAM,0BAA0B,MAAQ,CAAC;AAEhD,4EAA4E;AAC5E,eAAO,MAAM,qBAAqB;;;;CAIxB,CAAC;AAEX,oCAAoC;AACpC,eAAO,MAAM,IAAI;;;;;CAKP,CAAC;AACX;;GAEG;AACH,MAAM,MAAM,IAAI,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM,OAAO,IAAI,CAAC,CAAC;AAEpD,4BAA4B;AAC5B,eAAO,MAAM,IAAI;;;CAA+B,CAAC;AACjD;;GAEG;AACH,MAAM,MAAM,IAAI,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM,OAAO,IAAI,CAAC,CAAC;AAEpD,wCAAwC;AACxC,eAAO,MAAM,cAAc;;;CAAyC,CAAC;AACrE;;GAEG;AACH,MAAM,MAAM,cAAc,GACxB,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,OAAO,cAAc,CAAC,CAAC;AAEvD,8BAA8B;AAC9B,eAAO,MAAM,YAAY;;;CAA0C,CAAC;AACpE;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC;AAE5E,qDAAqD;AACrD,eAAO,MAAM,WAAW;;;CAAwC,CAAC;AACjE;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,OAAO,WAAW,CAAC,CAAC;AAEzE,2DAA2D;AAC3D,eAAO,MAAM,eAAe;;;CAAyC,CAAC;AACtE;;GAEG;AACH,MAAM,MAAM,eAAe,GACzB,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,OAAO,eAAe,CAAC,CAAC;AAEzD,mEAAmE;AACnE,eAAO,MAAM,aAAa;;;;;CAAmD,CAAC;AAC9E;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,OAAO,aAAa,CAAC,CAAC;AAE/E,iDAAiD;AACjD,eAAO,MAAM,eAAe;;;;CAA+C,CAAC;AAC5E;;GAEG;AACH,MAAM,MAAM,eAAe,GACzB,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,OAAO,eAAe,CAAC,CAAC;AAEzD,wEAAwE;AACxE,eAAO,MAAM,uBAAuB,MAAM,CAAC"}
@@ -0,0 +1,122 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ // Derived from libcomm14cux (https://github.com/colinbourassa/libcomm14cux)
3
+ // Copyright (C) Colin Bourassa. Licensed under the GNU GPL v3.
4
+ // Ported to TypeScript and modified for comm14cux-ts, 2026.
5
+ /** Baud rate of the 14CUX serial port. */
6
+ export const BAUD = 7812;
7
+ /** Baud rate used by ECUs running modified double-speed firmware. */
8
+ export const BAUD_DOUBLE_SPEED = 15625;
9
+ /** Number of engine speed ranges in the fuel maps. */
10
+ export const FUEL_MAP_COLUMNS = 16;
11
+ /** Number of engine load ranges in the fuel maps. */
12
+ export const FUEL_MAP_ROWS = 8;
13
+ /** Byte quantities that may be requested in a single read (`c14cux_readcount`). */
14
+ export const ReadCount = {
15
+ Count0: 0x0010,
16
+ Count1: 0x0050,
17
+ Count2: 0x0064,
18
+ Count3: 0x0190,
19
+ Count4: 0x0200,
20
+ };
21
+ /** Length codes sent to the ECU for the fixed read quantities. */
22
+ export const ReadCountValue = {
23
+ Count1: 0x10,
24
+ Count2: 0x11,
25
+ Count3: 0x12,
26
+ Count4: 0x13,
27
+ };
28
+ /** Sizes in bytes of fixed-size structures within the ROM. */
29
+ export const DataSize = {
30
+ ROM: 0x4000,
31
+ FuelMap: 0x80,
32
+ };
33
+ /** Important memory offsets in the ECU's address space (`c14cux_memory_offset`). */
34
+ export const MemoryOffset = {
35
+ ROMAddress: 0xc000,
36
+ RPMTable: 0xc800,
37
+ Port1: 0x0002,
38
+ LongTermLambdaFuelingTrimOdd: 0x0042,
39
+ LongTermLambdaFuelingTrimEven: 0x0046,
40
+ ShortTermLambdaFuelingTrimOdd: 0x0065,
41
+ ShortTermLambdaFuelingTrimEven: 0x0067,
42
+ FaultCodes: 0x0049,
43
+ ThrottleMinimumPosition: 0x0051,
44
+ MainVoltage: 0x0055,
45
+ MassAirflowDirect: 0x0057,
46
+ ThrottlePosition: 0x005f,
47
+ CoolantTemp: 0x006a,
48
+ IdleBypassPosition: 0x006d,
49
+ EngineSpeedInstantaneous: 0x007a,
50
+ EngineSpeedFiltered: 0x007c,
51
+ InjectorPulseWidth: 0x0082,
52
+ Bits008A: 0x008a,
53
+ PurgeValveState: 0x0096,
54
+ Bits00DD: 0x00dd,
55
+ TransmissionGear: 0x2000,
56
+ RoadSpeed: 0x2003,
57
+ FuelTemp: 0x2006,
58
+ RowScaler: 0x200a,
59
+ RPMLimit: 0x200c,
60
+ IdleMode: 0x2047,
61
+ MassAirflowLinear: 0x204d,
62
+ TargetIdleSpeed: 0x2051,
63
+ RevBMainVoltageFactorA: 0xc79b,
64
+ RevBMainVoltageFactorB: 0xc79c,
65
+ RevBMainVoltageFactorC: 0xc79d,
66
+ RevCMainVoltageFactorA: 0xc7c3,
67
+ RevCMainVoltageFactorB: 0xc7c4,
68
+ RevCMainVoltageFactorC: 0xc7c5,
69
+ MAFRowScaler: 0xc1c7,
70
+ Map0RowScalerInitValue: 0xc1c9,
71
+ FuelMap0: 0xc000,
72
+ NewFuelMap1: 0xc267,
73
+ NewFuelMap2: 0xc379,
74
+ NewFuelMap3: 0xc48b,
75
+ NewFuelMap4: 0xc59d,
76
+ NewFuelMap5: 0xc6af,
77
+ OldFuelMap1: 0xc23f,
78
+ OldFuelMap2: 0xc351,
79
+ OldFuelMap3: 0xc463,
80
+ OldFuelMap4: 0xc575,
81
+ OldFuelMap5: 0xc687,
82
+ TuneRevision: 0xffe9,
83
+ ChecksumFixer: 0xffeb,
84
+ TuneIdent: 0xffec,
85
+ CurrentFuelMapId: 0x202c,
86
+ FuelMapRowIndex: 0x005b,
87
+ FuelMapColumnIndex: 0x005c,
88
+ IdleAirControlStepCount: 0x0075,
89
+ FuelPumpTimer: 0x00af,
90
+ };
91
+ /** Offset from the start of a fuel map to its row scaler. */
92
+ export const FUEL_MAP_ROW_SCALER_OFFSET = 0x10a;
93
+ /** Fixed main-voltage coefficients for very old ECUs (1990 and earlier). */
94
+ export const RevAMainVoltageFactor = {
95
+ A: 0x64,
96
+ B: 0xbd,
97
+ C: 0x6180,
98
+ };
99
+ /** Transmission gear selections. */
100
+ export const Gear = {
101
+ NoReading: 0,
102
+ ParkOrNeutral: 1,
103
+ DriveOrReverse: 2,
104
+ ManualGearbox: 3,
105
+ };
106
+ /** The two engine banks. */
107
+ export const Bank = { Odd: 0, Even: 1 };
108
+ /** Types of lambda trim for fueling. */
109
+ export const LambdaTrimType = { ShortTerm: 0, LongTerm: 1 };
110
+ /** Fueling feedback modes. */
111
+ export const FeedbackMode = { ClosedLoop: 0, OpenLoop: 1 };
112
+ /** The two means of reading a value from the MAF. */
113
+ export const AirflowType = { Direct: 0, Linearized: 1 };
114
+ /** The two methods of interpreting a throttle position. */
115
+ export const ThrottlePosType = { Absolute: 0, Corrected: 1 };
116
+ /** Revisions of the ROM data layout (`c14cux_data_offset_rev`). */
117
+ export const DataOffsetRev = { Unset: 0, RevA: 1, RevB: 2, RevC: 3 };
118
+ /** States of the carbon canister purge valve. */
119
+ export const PurgeValveState = { Closed: 0, Toggling: 1, Open: 2 };
120
+ /** Default per-read silence timeout, matching libcomm14cux (100 ms). */
121
+ export const DEFAULT_READ_TIMEOUT_MS = 100;
122
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: GPL-3.0-only\n// Derived from libcomm14cux (https://github.com/colinbourassa/libcomm14cux)\n// Copyright (C) Colin Bourassa. Licensed under the GNU GPL v3.\n// Ported to TypeScript and modified for comm14cux-ts, 2026.\n\n/** Baud rate of the 14CUX serial port. */\nexport const BAUD = 7812;\n\n/** Baud rate used by ECUs running modified double-speed firmware. */\nexport const BAUD_DOUBLE_SPEED = 15625;\n\n/** Number of engine speed ranges in the fuel maps. */\nexport const FUEL_MAP_COLUMNS = 16;\n\n/** Number of engine load ranges in the fuel maps. */\nexport const FUEL_MAP_ROWS = 8;\n\n/** Byte quantities that may be requested in a single read (`c14cux_readcount`). */\nexport const ReadCount = {\n Count0: 0x0010,\n Count1: 0x0050,\n Count2: 0x0064,\n Count3: 0x0190,\n Count4: 0x0200,\n} as const;\n\n/** Length codes sent to the ECU for the fixed read quantities. */\nexport const ReadCountValue = {\n Count1: 0x10,\n Count2: 0x11,\n Count3: 0x12,\n Count4: 0x13,\n} as const;\n\n/** Sizes in bytes of fixed-size structures within the ROM. */\nexport const DataSize = {\n ROM: 0x4000,\n FuelMap: 0x80,\n} as const;\n\n/** Important memory offsets in the ECU's address space (`c14cux_memory_offset`). */\nexport const MemoryOffset = {\n ROMAddress: 0xc000,\n RPMTable: 0xc800,\n Port1: 0x0002,\n LongTermLambdaFuelingTrimOdd: 0x0042,\n LongTermLambdaFuelingTrimEven: 0x0046,\n ShortTermLambdaFuelingTrimOdd: 0x0065,\n ShortTermLambdaFuelingTrimEven: 0x0067,\n FaultCodes: 0x0049,\n ThrottleMinimumPosition: 0x0051,\n MainVoltage: 0x0055,\n MassAirflowDirect: 0x0057,\n ThrottlePosition: 0x005f,\n CoolantTemp: 0x006a,\n IdleBypassPosition: 0x006d,\n EngineSpeedInstantaneous: 0x007a,\n EngineSpeedFiltered: 0x007c,\n InjectorPulseWidth: 0x0082,\n Bits008A: 0x008a,\n PurgeValveState: 0x0096,\n Bits00DD: 0x00dd,\n TransmissionGear: 0x2000,\n RoadSpeed: 0x2003,\n FuelTemp: 0x2006,\n RowScaler: 0x200a,\n RPMLimit: 0x200c,\n IdleMode: 0x2047,\n MassAirflowLinear: 0x204d,\n TargetIdleSpeed: 0x2051,\n RevBMainVoltageFactorA: 0xc79b,\n RevBMainVoltageFactorB: 0xc79c,\n RevBMainVoltageFactorC: 0xc79d,\n RevCMainVoltageFactorA: 0xc7c3,\n RevCMainVoltageFactorB: 0xc7c4,\n RevCMainVoltageFactorC: 0xc7c5,\n MAFRowScaler: 0xc1c7,\n Map0RowScalerInitValue: 0xc1c9,\n FuelMap0: 0xc000,\n NewFuelMap1: 0xc267,\n NewFuelMap2: 0xc379,\n NewFuelMap3: 0xc48b,\n NewFuelMap4: 0xc59d,\n NewFuelMap5: 0xc6af,\n OldFuelMap1: 0xc23f,\n OldFuelMap2: 0xc351,\n OldFuelMap3: 0xc463,\n OldFuelMap4: 0xc575,\n OldFuelMap5: 0xc687,\n TuneRevision: 0xffe9,\n ChecksumFixer: 0xffeb,\n TuneIdent: 0xffec,\n CurrentFuelMapId: 0x202c,\n FuelMapRowIndex: 0x005b,\n FuelMapColumnIndex: 0x005c,\n IdleAirControlStepCount: 0x0075,\n FuelPumpTimer: 0x00af,\n} as const;\n\n/** Offset from the start of a fuel map to its row scaler. */\nexport const FUEL_MAP_ROW_SCALER_OFFSET = 0x10a;\n\n/** Fixed main-voltage coefficients for very old ECUs (1990 and earlier). */\nexport const RevAMainVoltageFactor = {\n A: 0x64,\n B: 0xbd,\n C: 0x6180,\n} as const;\n\n/** Transmission gear selections. */\nexport const Gear = {\n NoReading: 0,\n ParkOrNeutral: 1,\n DriveOrReverse: 2,\n ManualGearbox: 3,\n} as const;\n/**\n * Union of the {@link Gear} values.\n */\nexport type Gear = (typeof Gear)[keyof typeof Gear];\n\n/** The two engine banks. */\nexport const Bank = { Odd: 0, Even: 1 } as const;\n/**\n * Union of the {@link Bank} values.\n */\nexport type Bank = (typeof Bank)[keyof typeof Bank];\n\n/** Types of lambda trim for fueling. */\nexport const LambdaTrimType = { ShortTerm: 0, LongTerm: 1 } as const;\n/**\n * Union of the {@link LambdaTrimType} values.\n */\nexport type LambdaTrimType =\n (typeof LambdaTrimType)[keyof typeof LambdaTrimType];\n\n/** Fueling feedback modes. */\nexport const FeedbackMode = { ClosedLoop: 0, OpenLoop: 1 } as const;\n/**\n * Union of the {@link FeedbackMode} values.\n */\nexport type FeedbackMode = (typeof FeedbackMode)[keyof typeof FeedbackMode];\n\n/** The two means of reading a value from the MAF. */\nexport const AirflowType = { Direct: 0, Linearized: 1 } as const;\n/**\n * Union of the {@link AirflowType} values.\n */\nexport type AirflowType = (typeof AirflowType)[keyof typeof AirflowType];\n\n/** The two methods of interpreting a throttle position. */\nexport const ThrottlePosType = { Absolute: 0, Corrected: 1 } as const;\n/**\n * Union of the {@link ThrottlePosType} values.\n */\nexport type ThrottlePosType =\n (typeof ThrottlePosType)[keyof typeof ThrottlePosType];\n\n/** Revisions of the ROM data layout (`c14cux_data_offset_rev`). */\nexport const DataOffsetRev = { Unset: 0, RevA: 1, RevB: 2, RevC: 3 } as const;\n/**\n * Union of the {@link DataOffsetRev} values.\n */\nexport type DataOffsetRev = (typeof DataOffsetRev)[keyof typeof DataOffsetRev];\n\n/** States of the carbon canister purge valve. */\nexport const PurgeValveState = { Closed: 0, Toggling: 1, Open: 2 } as const;\n/**\n * Union of the {@link PurgeValveState} values.\n */\nexport type PurgeValveState =\n (typeof PurgeValveState)[keyof typeof PurgeValveState];\n\n/** Default per-read silence timeout, matching libcomm14cux (100 ms). */\nexport const DEFAULT_READ_TIMEOUT_MS = 100;\n"]}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Decodes the "direct" mass airflow reading, which changes linearly with
3
+ * sensor voltage but logarithmically with airflow.
4
+ *
5
+ * @param raw - The 10-bit reading, 0 to 1023.
6
+ * @returns Airflow as a fraction from 0 to 1 of the highest measurement.
7
+ * @throws {@link InvalidReadingError} if `raw` is above 1023.
8
+ */
9
+ export declare function decodeMafDirect(raw: number): number;
10
+ /**
11
+ * Decodes the "linearized" mass airflow reading, which changes linearly with
12
+ * airflow.
13
+ *
14
+ * @param raw - The reading, 0 to 17290.
15
+ * @returns Airflow as a fraction from 0 to 1 of the highest measurement.
16
+ * @throws {@link InvalidReadingError} if `raw` is above 17290.
17
+ */
18
+ export declare function decodeMafLinear(raw: number): number;
19
+ //# sourceMappingURL=airflow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"airflow.d.ts","sourceRoot":"","sources":["../../src/decoders/airflow.ts"],"names":[],"mappings":"AAUA;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMnD;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMnD"}
@@ -0,0 +1,36 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ // Derived from libcomm14cux (https://github.com/colinbourassa/libcomm14cux)
3
+ // Copyright (C) Colin Bourassa. Licensed under the GNU GPL v3.
4
+ // Ported to TypeScript and modified for comm14cux-ts, 2026.
5
+ import { InvalidReadingError } from '../errors.js';
6
+ const DIRECT_MAX = 1023;
7
+ const LINEAR_MAX = 17290;
8
+ /**
9
+ * Decodes the "direct" mass airflow reading, which changes linearly with
10
+ * sensor voltage but logarithmically with airflow.
11
+ *
12
+ * @param raw - The 10-bit reading, 0 to 1023.
13
+ * @returns Airflow as a fraction from 0 to 1 of the highest measurement.
14
+ * @throws {@link InvalidReadingError} if `raw` is above 1023.
15
+ */
16
+ export function decodeMafDirect(raw) {
17
+ if (raw > DIRECT_MAX) {
18
+ throw new InvalidReadingError(`MAF direct reading out of range: ${raw}`);
19
+ }
20
+ return raw / DIRECT_MAX;
21
+ }
22
+ /**
23
+ * Decodes the "linearized" mass airflow reading, which changes linearly with
24
+ * airflow.
25
+ *
26
+ * @param raw - The reading, 0 to 17290.
27
+ * @returns Airflow as a fraction from 0 to 1 of the highest measurement.
28
+ * @throws {@link InvalidReadingError} if `raw` is above 17290.
29
+ */
30
+ export function decodeMafLinear(raw) {
31
+ if (raw > LINEAR_MAX) {
32
+ throw new InvalidReadingError(`MAF linear reading out of range: ${raw}`);
33
+ }
34
+ return raw / LINEAR_MAX;
35
+ }
36
+ //# sourceMappingURL=airflow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"airflow.js","sourceRoot":"","sources":["../../src/decoders/airflow.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,4EAA4E;AAC5E,+DAA+D;AAC/D,4DAA4D;AAE5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAEnD,MAAM,UAAU,GAAG,IAAI,CAAC;AACxB,MAAM,UAAU,GAAG,KAAK,CAAC;AAEzB;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,IAAI,GAAG,GAAG,UAAU,EAAE,CAAC;QACrB,MAAM,IAAI,mBAAmB,CAAC,oCAAoC,GAAG,EAAE,CAAC,CAAC;IAC3E,CAAC;IAED,OAAO,GAAG,GAAG,UAAU,CAAC;AAC1B,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,IAAI,GAAG,GAAG,UAAU,EAAE,CAAC;QACrB,MAAM,IAAI,mBAAmB,CAAC,oCAAoC,GAAG,EAAE,CAAC,CAAC;IAC3E,CAAC;IAED,OAAO,GAAG,GAAG,UAAU,CAAC;AAC1B,CAAC","sourcesContent":["// SPDX-License-Identifier: GPL-3.0-only\n// Derived from libcomm14cux (https://github.com/colinbourassa/libcomm14cux)\n// Copyright (C) Colin Bourassa. Licensed under the GNU GPL v3.\n// Ported to TypeScript and modified for comm14cux-ts, 2026.\n\nimport { InvalidReadingError } from '../errors.js';\n\nconst DIRECT_MAX = 1023;\nconst LINEAR_MAX = 17290;\n\n/**\n * Decodes the \"direct\" mass airflow reading, which changes linearly with\n * sensor voltage but logarithmically with airflow.\n *\n * @param raw - The 10-bit reading, 0 to 1023.\n * @returns Airflow as a fraction from 0 to 1 of the highest measurement.\n * @throws {@link InvalidReadingError} if `raw` is above 1023.\n */\nexport function decodeMafDirect(raw: number): number {\n if (raw > DIRECT_MAX) {\n throw new InvalidReadingError(`MAF direct reading out of range: ${raw}`);\n }\n\n return raw / DIRECT_MAX;\n}\n\n/**\n * Decodes the \"linearized\" mass airflow reading, which changes linearly with\n * airflow.\n *\n * @param raw - The reading, 0 to 17290.\n * @returns Airflow as a fraction from 0 to 1 of the highest measurement.\n * @throws {@link InvalidReadingError} if `raw` is above 17290.\n */\nexport function decodeMafLinear(raw: number): number {\n if (raw > LINEAR_MAX) {\n throw new InvalidReadingError(`MAF linear reading out of range: ${raw}`);\n }\n\n return raw / LINEAR_MAX;\n}\n"]}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Converts a crank pulse width to engine speed (`7500000 / pulseWidth`,
3
+ * truncated).
4
+ *
5
+ * @param pulseWidth - Pulse width in ECU timer ticks. Must not be 0.
6
+ * @returns Engine speed in revolutions per minute.
7
+ * @throws {@link InvalidReadingError} if `pulseWidth` is 0. libcomm14cux
8
+ * divides by zero here, which is undefined behaviour in C.
9
+ */
10
+ export declare function pulseWidthToRpm(pulseWidth: number): number;
11
+ /**
12
+ * Decodes the engine speed from the filtered pulse width. 0xFFFF is the ECU's
13
+ * initial value with the ignition on and the engine stopped, and means 0 RPM.
14
+ *
15
+ * @param pulseWidth - The filtered pulse width, 0 to 0xFFFF.
16
+ * @returns Engine speed in revolutions per minute.
17
+ * @throws {@link InvalidReadingError} if `pulseWidth` is 0.
18
+ */
19
+ export declare function decodeEngineRpm(pulseWidth: number): number;
20
+ //# sourceMappingURL=engineSpeed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engineSpeed.d.ts","sourceRoot":"","sources":["../../src/decoders/engineSpeed.ts"],"names":[],"mappings":"AAOA;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAO1D;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE1D"}
@@ -0,0 +1,33 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ // Derived from libcomm14cux (https://github.com/colinbourassa/libcomm14cux)
3
+ // Copyright (C) Colin Bourassa. Licensed under the GNU GPL v3.
4
+ // Ported to TypeScript and modified for comm14cux-ts, 2026.
5
+ import { InvalidReadingError } from '../errors.js';
6
+ /**
7
+ * Converts a crank pulse width to engine speed (`7500000 / pulseWidth`,
8
+ * truncated).
9
+ *
10
+ * @param pulseWidth - Pulse width in ECU timer ticks. Must not be 0.
11
+ * @returns Engine speed in revolutions per minute.
12
+ * @throws {@link InvalidReadingError} if `pulseWidth` is 0. libcomm14cux
13
+ * divides by zero here, which is undefined behaviour in C.
14
+ */
15
+ export function pulseWidthToRpm(pulseWidth) {
16
+ if (pulseWidth === 0) {
17
+ // libcomm14cux divides by zero here (undefined behaviour in C).
18
+ throw new InvalidReadingError('Pulse width of zero');
19
+ }
20
+ return Math.trunc(7500000 / pulseWidth);
21
+ }
22
+ /**
23
+ * Decodes the engine speed from the filtered pulse width. 0xFFFF is the ECU's
24
+ * initial value with the ignition on and the engine stopped, and means 0 RPM.
25
+ *
26
+ * @param pulseWidth - The filtered pulse width, 0 to 0xFFFF.
27
+ * @returns Engine speed in revolutions per minute.
28
+ * @throws {@link InvalidReadingError} if `pulseWidth` is 0.
29
+ */
30
+ export function decodeEngineRpm(pulseWidth) {
31
+ return pulseWidth === 0xffff ? 0 : pulseWidthToRpm(pulseWidth);
32
+ }
33
+ //# sourceMappingURL=engineSpeed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engineSpeed.js","sourceRoot":"","sources":["../../src/decoders/engineSpeed.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,4EAA4E;AAC5E,+DAA+D;AAC/D,4DAA4D;AAE5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAEnD;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAAC,UAAkB;IAChD,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;QACrB,gEAAgE;QAChE,MAAM,IAAI,mBAAmB,CAAC,qBAAqB,CAAC,CAAC;IACvD,CAAC;IAED,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,UAAU,CAAC,CAAC;AAC1C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,UAAkB;IAChD,OAAO,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC;AACjE,CAAC","sourcesContent":["// SPDX-License-Identifier: GPL-3.0-only\n// Derived from libcomm14cux (https://github.com/colinbourassa/libcomm14cux)\n// Copyright (C) Colin Bourassa. Licensed under the GNU GPL v3.\n// Ported to TypeScript and modified for comm14cux-ts, 2026.\n\nimport { InvalidReadingError } from '../errors.js';\n\n/**\n * Converts a crank pulse width to engine speed (`7500000 / pulseWidth`,\n * truncated).\n *\n * @param pulseWidth - Pulse width in ECU timer ticks. Must not be 0.\n * @returns Engine speed in revolutions per minute.\n * @throws {@link InvalidReadingError} if `pulseWidth` is 0. libcomm14cux\n * divides by zero here, which is undefined behaviour in C.\n */\nexport function pulseWidthToRpm(pulseWidth: number): number {\n if (pulseWidth === 0) {\n // libcomm14cux divides by zero here (undefined behaviour in C).\n throw new InvalidReadingError('Pulse width of zero');\n }\n\n return Math.trunc(7500000 / pulseWidth);\n}\n\n/**\n * Decodes the engine speed from the filtered pulse width. 0xFFFF is the ECU's\n * initial value with the ignition on and the engine stopped, and means 0 RPM.\n *\n * @param pulseWidth - The filtered pulse width, 0 to 0xFFFF.\n * @returns Engine speed in revolutions per minute.\n * @throws {@link InvalidReadingError} if `pulseWidth` is 0.\n */\nexport function decodeEngineRpm(pulseWidth: number): number {\n return pulseWidth === 0xffff ? 0 : pulseWidthToRpm(pulseWidth);\n}\n"]}