-
Notifications
You must be signed in to change notification settings - Fork 3
/
index.js
154 lines (122 loc) · 3.86 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
require('buffer');
console.log(Buffer);
const AbstractBinding = require('@serialport/binding-abstract');
// TODO: Implement other FTDI variants.
const VENDOR_ID = '0x0403';
const PRODUCT_ID = '0x6001';
const H_CLK = 120000000;
const C_CLK = 48000000;
function FTDIToClkbits(baud, clk, clkDiv) {
const fracCode = [0, 3, 2, 4, 1, 5, 6, 7];
let bestBaud = 0;
let divisor;
let bestDivisor;
let encodedDivisor;
if (baud >= clk / clkDiv) {
encodedDivisor = 0;
bestBaud = clk / dlkDiv;
} else if (baud >= clk / (clkDiv + clkDiv / 2)) {
encodedDivisor = 1;
bestBaud = clk / (clkDiv + clkDiv / 2);
} else if (baud >= clk / (2 * clkDiv)) {
encodedDivisor = 2;
bestBaud = clk / (2 * clkDiv);
} else {
divisor = clk * 16 / clkDiv / baud;
if (divisor & 1) {
bestDivisor = divisor / 2 + 1;
} else {
bestDivisor = divisor / 2;
}
if (bestDivisor > 0x20000) {
bestDivisor = 0x1ffff;
}
bestBaud = clk * 16 / clkDiv / bestDivisor;
if (bestBaud & 1) {
bestBaud = bestBaud / 2 + 1;
} else {
bestBaud = bestBaud / 2;
}
encodedDivisor = (bestDivisor >> 3) | (fracCode[bestDivisor & 0x7] << 14);
}
return [bestBaud, encodedDivisor];
}
function FTDIConvertBaudrate(baud) {
let bestBaud;
let encodedDivisor;
let value;
let index;
if (baud <= 0) {
throw new Error('Baud rate must be > 0');
}
[bestBaud, encodedDivisor] = FTDIToClkbits(baud, C_CLK, 16);
value = encodedDivisor & 0xffff;
index = encodedDivisor >> 16;
return [bestBaud, value, index];
}
class FTDI323Binding extends AbstractBinding {
static async list() {
const devices = await navigator.usb.getDevices();
if (devices.length > 0) {
return devices;
}
await navigator.usb.requestDevice({
filters: [
{
vendorId: VENDOR_ID,
productId: PRODUCT_ID,
}
]
});
return navigator.usb.getDevices();
}
async open(device, options) {
if (!device || !device instanceof USBDevice) {
throw new TypeError('"path" is not a valid USBDevice');
}
if (typeof options !== 'object') {
throw new TypeError('"options" is not an object')
}
if (this.isOpen) {
throw new Error('Already open')
}
await device.open();
if (device.configuration === null) {
await device.selectConfiguration(1);
}
await device.claimInterface(0);
await device.selectConfiguration(1);
await device.selectAlternateInterface(0, 0);
const [baud, value, index] = FTDIConvertBaudrate(options.baudRate);
console.log(baud, value, index);
const result = await device.controlTransferOut({
requestType: 'vendor',
recipient: 'device',
request: 3,
value ,
index,
});
this.device = device;
this.isOpen = true;
}
async read(buffer, offset, length) {
await super.read(buffer, offset, 64)
const {data: {buffer: dataBuffer, byteLength: bytesRead}} = await this.device.transferIn(1, 64);
const uint8buffer = new Uint8Array(dataBuffer);
if (bytesRead === 2) {
return this.read(buffer, offset, 64);
}
for (let i = offset; i < offset + bytesRead - 2; i++) {
buffer[i] = uint8buffer[i+2-offset];
}
return { bytesRead: bytesRead-2, buffer };
}
async write(buffer) {
return this.device.transferOut(2, buffer);
}
async close() {
super.close();
return this.device.close();
}
}
module.exports = FTDI323Binding;