node-ch347 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +24 -0
- package/README.md +234 -0
- package/dist/config.d.ts +20 -0
- package/dist/config.js +110 -0
- package/dist/constants.d.ts +83 -0
- package/dist/constants.js +107 -0
- package/dist/flash.d.ts +134 -0
- package/dist/flash.js +597 -0
- package/dist/gpio.d.ts +67 -0
- package/dist/gpio.js +196 -0
- package/dist/index.d.ts +149 -0
- package/dist/index.js +222 -0
- package/dist/spi.d.ts +66 -0
- package/dist/spi.js +227 -0
- package/dist/types.d.ts +74 -0
- package/dist/types.js +45 -0
- package/dist/uart.d.ts +81 -0
- package/dist/uart.js +343 -0
- package/dist/usb.d.ts +80 -0
- package/dist/usb.js +422 -0
- package/package.json +49 -0
package/dist/gpio.js
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* CH347 GPIO Control
|
|
4
|
+
*
|
|
5
|
+
* Protocol from ch347-gpio.c:
|
|
6
|
+
* - GPIO buffer is 11 bytes: [0xCC, length(8), 0x00, pin0, pin1, pin2, pin3, pin4, pin5, pin6, pin7]
|
|
7
|
+
* - Each pin byte has control bits:
|
|
8
|
+
* - Bit 7 (0x80): In response, indicates output direction
|
|
9
|
+
* - Bit 6 (0x40): Enable pin change (out) / Current value (in)
|
|
10
|
+
* - Bit 5-4 (0x30): Set direction to output
|
|
11
|
+
* - Bit 3 (0x08): Set pin value high
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.CH347GPIO = void 0;
|
|
15
|
+
const constants_1 = require("./constants");
|
|
16
|
+
class CH347GPIO {
|
|
17
|
+
usb;
|
|
18
|
+
pinStates = [];
|
|
19
|
+
constructor(usb) {
|
|
20
|
+
this.usb = usb;
|
|
21
|
+
// Initialize pin states
|
|
22
|
+
for (let i = 0; i < constants_1.CH347_GPIO_COUNT; i++) {
|
|
23
|
+
this.pinStates[i] = {
|
|
24
|
+
pin: i,
|
|
25
|
+
direction: 'input',
|
|
26
|
+
value: false,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Build GPIO command buffer
|
|
32
|
+
*/
|
|
33
|
+
buildCommandBuffer(pinConfigs) {
|
|
34
|
+
const buf = Buffer.alloc(11);
|
|
35
|
+
buf[0] = constants_1.CH347_CMD_GPIO;
|
|
36
|
+
buf[1] = 8; // Length of pin data
|
|
37
|
+
buf[2] = 0;
|
|
38
|
+
// Set pin bytes
|
|
39
|
+
for (const [pin, config] of pinConfigs) {
|
|
40
|
+
if (pin >= 0 && pin < constants_1.CH347_GPIO_COUNT) {
|
|
41
|
+
let pinByte = 0;
|
|
42
|
+
if (config.setDir || config.setValue) {
|
|
43
|
+
pinByte |= constants_1.GPIO_PIN_ENABLE; // Enable change (0xC0)
|
|
44
|
+
}
|
|
45
|
+
if (config.setDir && config.dirOut) {
|
|
46
|
+
pinByte |= constants_1.GPIO_PIN_DIR_OUT; // Set output direction (0x30)
|
|
47
|
+
}
|
|
48
|
+
if (config.setValue && config.value) {
|
|
49
|
+
pinByte |= constants_1.GPIO_PIN_VALUE_HIGH; // Set value high (0x08)
|
|
50
|
+
}
|
|
51
|
+
buf[3 + pin] = pinByte;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return buf;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Parse GPIO response buffer
|
|
58
|
+
*/
|
|
59
|
+
parseResponse(buf) {
|
|
60
|
+
const states = [];
|
|
61
|
+
for (let i = 0; i < constants_1.CH347_GPIO_COUNT; i++) {
|
|
62
|
+
const pinByte = buf[3 + i];
|
|
63
|
+
states.push({
|
|
64
|
+
pin: i,
|
|
65
|
+
direction: (pinByte & constants_1.GPIO_PIN_IS_OUTPUT) ? 'output' : 'input',
|
|
66
|
+
value: (pinByte & constants_1.GPIO_PIN_VALUE) !== 0,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return states;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Read all GPIO states
|
|
73
|
+
*/
|
|
74
|
+
async readAll() {
|
|
75
|
+
// Send read command (empty pin config)
|
|
76
|
+
const cmdBuf = this.buildCommandBuffer(new Map());
|
|
77
|
+
const response = await this.usb.transfer(cmdBuf, 11);
|
|
78
|
+
this.pinStates = this.parseResponse(response);
|
|
79
|
+
return this.pinStates;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Read single GPIO pin state
|
|
83
|
+
*/
|
|
84
|
+
async read(pin) {
|
|
85
|
+
if (pin < 0 || pin >= constants_1.CH347_GPIO_COUNT) {
|
|
86
|
+
throw new Error(`Invalid pin number: ${pin}`);
|
|
87
|
+
}
|
|
88
|
+
const states = await this.readAll();
|
|
89
|
+
return states[pin];
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Configure GPIO pin direction
|
|
93
|
+
*/
|
|
94
|
+
async setDirection(pin, direction) {
|
|
95
|
+
if (pin < 0 || pin >= constants_1.CH347_GPIO_COUNT) {
|
|
96
|
+
throw new Error(`Invalid pin number: ${pin}`);
|
|
97
|
+
}
|
|
98
|
+
const pinConfig = new Map();
|
|
99
|
+
pinConfig.set(pin, {
|
|
100
|
+
setDir: true,
|
|
101
|
+
dirOut: direction === 'output',
|
|
102
|
+
setValue: true,
|
|
103
|
+
value: this.pinStates[pin]?.value ?? false,
|
|
104
|
+
});
|
|
105
|
+
const cmdBuf = this.buildCommandBuffer(pinConfig);
|
|
106
|
+
const response = await this.usb.transfer(cmdBuf, 11);
|
|
107
|
+
this.pinStates = this.parseResponse(response);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Set GPIO output value
|
|
111
|
+
*/
|
|
112
|
+
async write(pin, value) {
|
|
113
|
+
if (pin < 0 || pin >= constants_1.CH347_GPIO_COUNT) {
|
|
114
|
+
throw new Error(`Invalid pin number: ${pin}`);
|
|
115
|
+
}
|
|
116
|
+
// First ensure pin is set as output
|
|
117
|
+
const pinConfig = new Map();
|
|
118
|
+
pinConfig.set(pin, {
|
|
119
|
+
setDir: true,
|
|
120
|
+
dirOut: true,
|
|
121
|
+
setValue: true,
|
|
122
|
+
value: value,
|
|
123
|
+
});
|
|
124
|
+
const cmdBuf = this.buildCommandBuffer(pinConfig);
|
|
125
|
+
const response = await this.usb.transfer(cmdBuf, 11);
|
|
126
|
+
this.pinStates = this.parseResponse(response);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Set multiple GPIO pins at once
|
|
130
|
+
*/
|
|
131
|
+
async writeMultiple(pins) {
|
|
132
|
+
const pinConfig = new Map();
|
|
133
|
+
for (const { pin, value } of pins) {
|
|
134
|
+
if (pin < 0 || pin >= constants_1.CH347_GPIO_COUNT) {
|
|
135
|
+
throw new Error(`Invalid pin number: ${pin}`);
|
|
136
|
+
}
|
|
137
|
+
pinConfig.set(pin, {
|
|
138
|
+
setDir: true,
|
|
139
|
+
dirOut: true,
|
|
140
|
+
setValue: true,
|
|
141
|
+
value: value,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
const cmdBuf = this.buildCommandBuffer(pinConfig);
|
|
145
|
+
const response = await this.usb.transfer(cmdBuf, 11);
|
|
146
|
+
this.pinStates = this.parseResponse(response);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Configure multiple GPIO pins
|
|
150
|
+
*/
|
|
151
|
+
async configure(configs) {
|
|
152
|
+
const pinConfig = new Map();
|
|
153
|
+
for (const config of configs) {
|
|
154
|
+
if (config.pin < 0 || config.pin >= constants_1.CH347_GPIO_COUNT) {
|
|
155
|
+
throw new Error(`Invalid pin number: ${config.pin}`);
|
|
156
|
+
}
|
|
157
|
+
pinConfig.set(config.pin, {
|
|
158
|
+
setDir: true,
|
|
159
|
+
dirOut: config.direction === 'output',
|
|
160
|
+
setValue: config.value !== undefined,
|
|
161
|
+
value: config.value ?? false,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
const cmdBuf = this.buildCommandBuffer(pinConfig);
|
|
165
|
+
const response = await this.usb.transfer(cmdBuf, 11);
|
|
166
|
+
this.pinStates = this.parseResponse(response);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Pulse a GPIO pin (useful for buttons)
|
|
170
|
+
*/
|
|
171
|
+
async pulse(pin, durationMs = 100, activeHigh = true) {
|
|
172
|
+
await this.write(pin, activeHigh);
|
|
173
|
+
await this.delay(durationMs);
|
|
174
|
+
await this.write(pin, !activeHigh);
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Toggle GPIO pin
|
|
178
|
+
*/
|
|
179
|
+
async toggle(pin) {
|
|
180
|
+
const state = await this.read(pin);
|
|
181
|
+
const newValue = !state.value;
|
|
182
|
+
await this.write(pin, newValue);
|
|
183
|
+
return newValue;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Get cached pin states (call readAll() to refresh)
|
|
187
|
+
*/
|
|
188
|
+
getPinStates() {
|
|
189
|
+
return [...this.pinStates];
|
|
190
|
+
}
|
|
191
|
+
delay(ms) {
|
|
192
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
exports.CH347GPIO = CH347GPIO;
|
|
196
|
+
//# sourceMappingURL=gpio.js.map
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CH347 Library
|
|
3
|
+
*
|
|
4
|
+
* A Node.js library for interfacing with CH347 USB devices.
|
|
5
|
+
* Supports GPIO and SPI flash programming.
|
|
6
|
+
* UART path discovery is provided; use external serial libraries for UART communication.
|
|
7
|
+
*
|
|
8
|
+
* Cross-platform: Linux and macOS
|
|
9
|
+
*/
|
|
10
|
+
export { CH347USB } from './usb';
|
|
11
|
+
export { CH347GPIO } from './gpio';
|
|
12
|
+
export { CH347SPI } from './spi';
|
|
13
|
+
export { CH347Flash } from './flash';
|
|
14
|
+
export { listDevicesWithSerial, CH347DeviceWithSerial, } from './config';
|
|
15
|
+
export * from './types';
|
|
16
|
+
export * from './constants';
|
|
17
|
+
import { CH347GPIO } from './gpio';
|
|
18
|
+
import { CH347SPI } from './spi';
|
|
19
|
+
import { CH347Flash } from './flash';
|
|
20
|
+
import { CH347DeviceWithSerial } from './config';
|
|
21
|
+
import { CH347DeviceInfo, SPIConfig, FlashInfo, GPIOState } from './types';
|
|
22
|
+
export interface CH347DeviceOptions {
|
|
23
|
+
spi?: Partial<SPIConfig>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Main CH347 device class
|
|
27
|
+
* Provides unified access to GPIO, SPI, and Flash functionality
|
|
28
|
+
*/
|
|
29
|
+
export declare class CH347Device {
|
|
30
|
+
private usb;
|
|
31
|
+
private _gpio;
|
|
32
|
+
private _spi;
|
|
33
|
+
private _flash;
|
|
34
|
+
private options;
|
|
35
|
+
constructor(options?: CH347DeviceOptions);
|
|
36
|
+
/**
|
|
37
|
+
* List all connected CH347 devices
|
|
38
|
+
*/
|
|
39
|
+
static listDevices(): CH347DeviceInfo[];
|
|
40
|
+
/**
|
|
41
|
+
* List all connected CH347 devices with their serial numbers
|
|
42
|
+
*/
|
|
43
|
+
static listDevicesWithSerial(): Promise<CH347DeviceWithSerial[]>;
|
|
44
|
+
/**
|
|
45
|
+
* Open connection to CH347 device
|
|
46
|
+
* @param deviceIndex Index of device to open (default 0)
|
|
47
|
+
*/
|
|
48
|
+
open(deviceIndex?: number): Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* Close connection
|
|
51
|
+
*/
|
|
52
|
+
close(): void;
|
|
53
|
+
/**
|
|
54
|
+
* Check if device is connected
|
|
55
|
+
*/
|
|
56
|
+
isConnected(): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Get the UART tty path for this CH347 device
|
|
59
|
+
* Returns the serial port path (e.g., '/dev/ttyACM0' on Linux, '/dev/tty.usbmodem*' on macOS)
|
|
60
|
+
*/
|
|
61
|
+
getUARTPath(): string | null;
|
|
62
|
+
/**
|
|
63
|
+
* Get GPIO controller
|
|
64
|
+
*/
|
|
65
|
+
get gpio(): CH347GPIO;
|
|
66
|
+
/**
|
|
67
|
+
* Get SPI controller
|
|
68
|
+
*/
|
|
69
|
+
get spi(): CH347SPI;
|
|
70
|
+
/**
|
|
71
|
+
* Get Flash programmer
|
|
72
|
+
*/
|
|
73
|
+
get flash(): CH347Flash;
|
|
74
|
+
/**
|
|
75
|
+
* Read all GPIO pin states
|
|
76
|
+
*/
|
|
77
|
+
gpioReadAll(): Promise<GPIOState[]>;
|
|
78
|
+
/**
|
|
79
|
+
* Set GPIO pin output value
|
|
80
|
+
*/
|
|
81
|
+
gpioWrite(pin: number, value: boolean): Promise<void>;
|
|
82
|
+
/**
|
|
83
|
+
* Read GPIO pin state
|
|
84
|
+
*/
|
|
85
|
+
gpioRead(pin: number): Promise<GPIOState>;
|
|
86
|
+
/**
|
|
87
|
+
* Pulse GPIO pin (for button press simulation)
|
|
88
|
+
*/
|
|
89
|
+
gpioPulse(pin: number, durationMs?: number, activeHigh?: boolean): Promise<void>;
|
|
90
|
+
/**
|
|
91
|
+
* Initialize SPI interface
|
|
92
|
+
*/
|
|
93
|
+
spiInit(config?: Partial<SPIConfig>): Promise<void>;
|
|
94
|
+
/**
|
|
95
|
+
* Read flash JEDEC ID
|
|
96
|
+
*/
|
|
97
|
+
flashReadId(): Promise<FlashInfo>;
|
|
98
|
+
/**
|
|
99
|
+
* Read data from flash
|
|
100
|
+
*/
|
|
101
|
+
flashRead(address: number, length: number, onProgress?: (progress: {
|
|
102
|
+
percentage: number;
|
|
103
|
+
}) => void): Promise<Buffer>;
|
|
104
|
+
/**
|
|
105
|
+
* Write data to flash
|
|
106
|
+
*/
|
|
107
|
+
flashWrite(address: number, data: Buffer, onProgress?: (progress: {
|
|
108
|
+
percentage: number;
|
|
109
|
+
}) => void): Promise<void>;
|
|
110
|
+
/**
|
|
111
|
+
* Erase flash sector (4KB)
|
|
112
|
+
*/
|
|
113
|
+
flashEraseSector(address: number): Promise<void>;
|
|
114
|
+
/**
|
|
115
|
+
* Erase entire flash chip
|
|
116
|
+
*/
|
|
117
|
+
flashEraseChip(onProgress?: (progress: {
|
|
118
|
+
percentage: number;
|
|
119
|
+
}) => void): Promise<void>;
|
|
120
|
+
/**
|
|
121
|
+
* Program flash (erase + write + verify)
|
|
122
|
+
*/
|
|
123
|
+
flashProgram(address: number, data: Buffer, options?: {
|
|
124
|
+
erase?: boolean;
|
|
125
|
+
verify?: boolean;
|
|
126
|
+
onProgress?: (progress: {
|
|
127
|
+
percentage: number;
|
|
128
|
+
}) => void;
|
|
129
|
+
}): Promise<boolean>;
|
|
130
|
+
/**
|
|
131
|
+
* Program flash from a binary file
|
|
132
|
+
* If address is not specified, requires file size to match flash size (call flashReadId first)
|
|
133
|
+
*/
|
|
134
|
+
flashProgramFile(filePath: string, address?: number, options?: {
|
|
135
|
+
erase?: boolean;
|
|
136
|
+
verify?: boolean;
|
|
137
|
+
onProgress?: (progress: {
|
|
138
|
+
percentage: number;
|
|
139
|
+
}) => void;
|
|
140
|
+
}): Promise<boolean>;
|
|
141
|
+
/**
|
|
142
|
+
* Read flash contents to a binary file
|
|
143
|
+
*/
|
|
144
|
+
flashReadToFile(filePath: string, address?: number, length?: number, onProgress?: (progress: {
|
|
145
|
+
percentage: number;
|
|
146
|
+
}) => void): Promise<void>;
|
|
147
|
+
}
|
|
148
|
+
export default CH347Device;
|
|
149
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* CH347 Library
|
|
4
|
+
*
|
|
5
|
+
* A Node.js library for interfacing with CH347 USB devices.
|
|
6
|
+
* Supports GPIO and SPI flash programming.
|
|
7
|
+
* UART path discovery is provided; use external serial libraries for UART communication.
|
|
8
|
+
*
|
|
9
|
+
* Cross-platform: Linux and macOS
|
|
10
|
+
*/
|
|
11
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) k2 = k;
|
|
13
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
14
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
15
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
16
|
+
}
|
|
17
|
+
Object.defineProperty(o, k2, desc);
|
|
18
|
+
}) : (function(o, m, k, k2) {
|
|
19
|
+
if (k2 === undefined) k2 = k;
|
|
20
|
+
o[k2] = m[k];
|
|
21
|
+
}));
|
|
22
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
23
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.CH347Device = exports.listDevicesWithSerial = exports.CH347Flash = exports.CH347SPI = exports.CH347GPIO = exports.CH347USB = void 0;
|
|
27
|
+
// Core modules
|
|
28
|
+
var usb_1 = require("./usb");
|
|
29
|
+
Object.defineProperty(exports, "CH347USB", { enumerable: true, get: function () { return usb_1.CH347USB; } });
|
|
30
|
+
var gpio_1 = require("./gpio");
|
|
31
|
+
Object.defineProperty(exports, "CH347GPIO", { enumerable: true, get: function () { return gpio_1.CH347GPIO; } });
|
|
32
|
+
var spi_1 = require("./spi");
|
|
33
|
+
Object.defineProperty(exports, "CH347SPI", { enumerable: true, get: function () { return spi_1.CH347SPI; } });
|
|
34
|
+
var flash_1 = require("./flash");
|
|
35
|
+
Object.defineProperty(exports, "CH347Flash", { enumerable: true, get: function () { return flash_1.CH347Flash; } });
|
|
36
|
+
// Device configuration (serial number, etc.)
|
|
37
|
+
var config_1 = require("./config");
|
|
38
|
+
Object.defineProperty(exports, "listDevicesWithSerial", { enumerable: true, get: function () { return config_1.listDevicesWithSerial; } });
|
|
39
|
+
// Types
|
|
40
|
+
__exportStar(require("./types"), exports);
|
|
41
|
+
// Constants
|
|
42
|
+
__exportStar(require("./constants"), exports);
|
|
43
|
+
// Convenience class that combines all functionality
|
|
44
|
+
const usb_2 = require("./usb");
|
|
45
|
+
const gpio_2 = require("./gpio");
|
|
46
|
+
const spi_2 = require("./spi");
|
|
47
|
+
const flash_2 = require("./flash");
|
|
48
|
+
const config_2 = require("./config");
|
|
49
|
+
/**
|
|
50
|
+
* Main CH347 device class
|
|
51
|
+
* Provides unified access to GPIO, SPI, and Flash functionality
|
|
52
|
+
*/
|
|
53
|
+
class CH347Device {
|
|
54
|
+
usb;
|
|
55
|
+
_gpio = null;
|
|
56
|
+
_spi = null;
|
|
57
|
+
_flash = null;
|
|
58
|
+
options;
|
|
59
|
+
constructor(options = {}) {
|
|
60
|
+
this.usb = new usb_2.CH347USB();
|
|
61
|
+
this.options = options;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* List all connected CH347 devices
|
|
65
|
+
*/
|
|
66
|
+
static listDevices() {
|
|
67
|
+
return usb_2.CH347USB.listDevices();
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* List all connected CH347 devices with their serial numbers
|
|
71
|
+
*/
|
|
72
|
+
static async listDevicesWithSerial() {
|
|
73
|
+
return (0, config_2.listDevicesWithSerial)();
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Open connection to CH347 device
|
|
77
|
+
* @param deviceIndex Index of device to open (default 0)
|
|
78
|
+
*/
|
|
79
|
+
async open(deviceIndex = 0) {
|
|
80
|
+
await this.usb.open(deviceIndex);
|
|
81
|
+
// Initialize GPIO
|
|
82
|
+
this._gpio = new gpio_2.CH347GPIO(this.usb);
|
|
83
|
+
// Initialize SPI with optional config
|
|
84
|
+
this._spi = new spi_2.CH347SPI(this.usb, this.options.spi);
|
|
85
|
+
// Initialize Flash (wraps SPI)
|
|
86
|
+
this._flash = new flash_2.CH347Flash(this._spi);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Close connection
|
|
90
|
+
*/
|
|
91
|
+
close() {
|
|
92
|
+
this.usb.close();
|
|
93
|
+
this._gpio = null;
|
|
94
|
+
this._spi = null;
|
|
95
|
+
this._flash = null;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Check if device is connected
|
|
99
|
+
*/
|
|
100
|
+
isConnected() {
|
|
101
|
+
return this.usb.isConnected();
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Get the UART tty path for this CH347 device
|
|
105
|
+
* Returns the serial port path (e.g., '/dev/ttyACM0' on Linux, '/dev/tty.usbmodem*' on macOS)
|
|
106
|
+
*/
|
|
107
|
+
getUARTPath() {
|
|
108
|
+
return this.usb.getUARTPath();
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Get GPIO controller
|
|
112
|
+
*/
|
|
113
|
+
get gpio() {
|
|
114
|
+
if (!this._gpio) {
|
|
115
|
+
throw new Error('Device not open');
|
|
116
|
+
}
|
|
117
|
+
return this._gpio;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Get SPI controller
|
|
121
|
+
*/
|
|
122
|
+
get spi() {
|
|
123
|
+
if (!this._spi) {
|
|
124
|
+
throw new Error('Device not open');
|
|
125
|
+
}
|
|
126
|
+
return this._spi;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Get Flash programmer
|
|
130
|
+
*/
|
|
131
|
+
get flash() {
|
|
132
|
+
if (!this._flash) {
|
|
133
|
+
throw new Error('Device not open');
|
|
134
|
+
}
|
|
135
|
+
return this._flash;
|
|
136
|
+
}
|
|
137
|
+
// ==================== GPIO Convenience Methods ====================
|
|
138
|
+
/**
|
|
139
|
+
* Read all GPIO pin states
|
|
140
|
+
*/
|
|
141
|
+
async gpioReadAll() {
|
|
142
|
+
return this.gpio.readAll();
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Set GPIO pin output value
|
|
146
|
+
*/
|
|
147
|
+
async gpioWrite(pin, value) {
|
|
148
|
+
return this.gpio.write(pin, value);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Read GPIO pin state
|
|
152
|
+
*/
|
|
153
|
+
async gpioRead(pin) {
|
|
154
|
+
return this.gpio.read(pin);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Pulse GPIO pin (for button press simulation)
|
|
158
|
+
*/
|
|
159
|
+
async gpioPulse(pin, durationMs = 100, activeHigh = true) {
|
|
160
|
+
return this.gpio.pulse(pin, durationMs, activeHigh);
|
|
161
|
+
}
|
|
162
|
+
// ==================== SPI Flash Convenience Methods ====================
|
|
163
|
+
/**
|
|
164
|
+
* Initialize SPI interface
|
|
165
|
+
*/
|
|
166
|
+
async spiInit(config) {
|
|
167
|
+
return this.spi.init(config);
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Read flash JEDEC ID
|
|
171
|
+
*/
|
|
172
|
+
async flashReadId() {
|
|
173
|
+
return this.flash.readJedecId();
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Read data from flash
|
|
177
|
+
*/
|
|
178
|
+
async flashRead(address, length, onProgress) {
|
|
179
|
+
return this.flash.read(address, length, onProgress);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Write data to flash
|
|
183
|
+
*/
|
|
184
|
+
async flashWrite(address, data, onProgress) {
|
|
185
|
+
return this.flash.write(address, data, onProgress);
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Erase flash sector (4KB)
|
|
189
|
+
*/
|
|
190
|
+
async flashEraseSector(address) {
|
|
191
|
+
return this.flash.eraseSector(address);
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Erase entire flash chip
|
|
195
|
+
*/
|
|
196
|
+
async flashEraseChip(onProgress) {
|
|
197
|
+
return this.flash.eraseChip(onProgress);
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Program flash (erase + write + verify)
|
|
201
|
+
*/
|
|
202
|
+
async flashProgram(address, data, options) {
|
|
203
|
+
return this.flash.program(address, data, options);
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Program flash from a binary file
|
|
207
|
+
* If address is not specified, requires file size to match flash size (call flashReadId first)
|
|
208
|
+
*/
|
|
209
|
+
async flashProgramFile(filePath, address, options) {
|
|
210
|
+
return this.flash.programFile(filePath, address, options);
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Read flash contents to a binary file
|
|
214
|
+
*/
|
|
215
|
+
async flashReadToFile(filePath, address = 0, length, onProgress) {
|
|
216
|
+
return this.flash.readToFile(filePath, address, length, onProgress);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
exports.CH347Device = CH347Device;
|
|
220
|
+
// Default export
|
|
221
|
+
exports.default = CH347Device;
|
|
222
|
+
//# sourceMappingURL=index.js.map
|
package/dist/spi.d.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CH347 SPI Interface
|
|
3
|
+
*
|
|
4
|
+
* Protocol based on official WCH SDK and flashrom implementation.
|
|
5
|
+
* Commands:
|
|
6
|
+
* 0xC0 - SPI_SET_CFG: Configure SPI
|
|
7
|
+
* 0xC1 - SPI_CS_CTRL: Chip select control
|
|
8
|
+
* 0xC2 - SPI_OUT_IN: Bidirectional transfer
|
|
9
|
+
* 0xC3 - SPI_IN: Read only
|
|
10
|
+
* 0xC4 - SPI_OUT: Write only
|
|
11
|
+
* 0xCA - SPI_GET_CFG: Get configuration
|
|
12
|
+
*/
|
|
13
|
+
import { CH347USB } from './usb';
|
|
14
|
+
import { SPIConfig } from './types';
|
|
15
|
+
export declare class CH347SPI {
|
|
16
|
+
private usb;
|
|
17
|
+
private config;
|
|
18
|
+
private isInitialized;
|
|
19
|
+
constructor(usb: CH347USB, config?: Partial<SPIConfig>);
|
|
20
|
+
/**
|
|
21
|
+
* Initialize SPI interface with configuration
|
|
22
|
+
*/
|
|
23
|
+
init(config?: Partial<SPIConfig>): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Control chip select
|
|
26
|
+
*/
|
|
27
|
+
setChipSelect(active: boolean): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* SPI write and read (full duplex transfer)
|
|
30
|
+
* @param data Data to write
|
|
31
|
+
* @param csControl If true, automatically control CS (default true)
|
|
32
|
+
* @returns Data read during transfer
|
|
33
|
+
*/
|
|
34
|
+
writeRead(data: Buffer, csControl?: boolean): Promise<Buffer>;
|
|
35
|
+
/**
|
|
36
|
+
* SPI write only
|
|
37
|
+
* @param data Data to write
|
|
38
|
+
* @param csControl If true, automatically control CS (default true)
|
|
39
|
+
*/
|
|
40
|
+
write(data: Buffer, csControl?: boolean): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* SPI read only
|
|
43
|
+
* @param length Number of bytes to read
|
|
44
|
+
* @param csControl If true, automatically control CS (default true)
|
|
45
|
+
* @returns Data read
|
|
46
|
+
*/
|
|
47
|
+
read(length: number, csControl?: boolean): Promise<Buffer>;
|
|
48
|
+
/**
|
|
49
|
+
* Execute SPI command with CS control
|
|
50
|
+
* Useful for sending flash commands
|
|
51
|
+
*/
|
|
52
|
+
command(writeData: Buffer, readLength?: number): Promise<Buffer>;
|
|
53
|
+
/**
|
|
54
|
+
* Execute SPI command with full duplex transfer
|
|
55
|
+
*/
|
|
56
|
+
transfer(data: Buffer): Promise<Buffer>;
|
|
57
|
+
/**
|
|
58
|
+
* Get current configuration
|
|
59
|
+
*/
|
|
60
|
+
getConfig(): SPIConfig;
|
|
61
|
+
/**
|
|
62
|
+
* Check if SPI is initialized
|
|
63
|
+
*/
|
|
64
|
+
isReady(): boolean;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=spi.d.ts.map
|