@johntalton/ftdi 1.0.0 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +88 -16
- package/lib/eeprom.d.ts +5 -5
- package/lib/eeprom.d.ts.map +1 -1
- package/lib/eeprom.js +2 -1
- package/lib/eeprom.js.map +1 -1
- package/lib/ftdi.d.ts +1 -1
- package/lib/ftdi.d.ts.map +1 -1
- package/lib/ftdi.js +16 -16
- package/lib/ftdi.js.map +1 -1
- package/lib/i2c/i2c-template.d.ts +19 -1
- package/lib/i2c/i2c-template.d.ts.map +1 -1
- package/lib/i2c/i2c-template.js +24 -13
- package/lib/i2c/i2c-template.js.map +1 -1
- package/lib/i2c/i2c.d.ts +2 -2
- package/lib/i2c/i2c.d.ts.map +1 -1
- package/lib/i2c/i2c.js +14 -8
- package/lib/i2c/i2c.js.map +1 -1
- package/lib/mpsse/command.d.ts.map +1 -1
- package/lib/mpsse/command.js +2 -2
- package/lib/mpsse/command.js.map +1 -1
- package/lib/mpsse/mpsse-template.d.ts +4 -2
- package/lib/mpsse/mpsse-template.d.ts.map +1 -1
- package/lib/mpsse/mpsse-template.js +36 -10
- package/lib/mpsse/mpsse-template.js.map +1 -1
- package/lib/mpsse/mpsse.d.ts +2 -2
- package/lib/mpsse/mpsse.d.ts.map +1 -1
- package/lib/mpsse/mpsse.js +2 -2
- package/lib/spi/index.d.ts +14 -0
- package/lib/spi/index.d.ts.map +1 -0
- package/lib/spi/index.js +74 -0
- package/lib/spi/index.js.map +1 -0
- package/lib/util.d.ts +4 -4
- package/lib/util.d.ts.map +1 -1
- package/lib/util.js +9 -8
- package/lib/util.js.map +1 -1
- package/package.json +14 -3
- package/src/eeprom.ts +10 -9
- package/src/ftdi.ts +16 -17
- package/src/i2c/i2c-template.ts +32 -13
- package/src/i2c/i2c.ts +15 -12
- package/src/mpsse/command.ts +2 -3
- package/src/mpsse/mpsse-template.ts +27 -10
- package/src/mpsse/mpsse.ts +3 -3
- package/src/spi/index.ts +113 -0
- package/src/util.ts +10 -9
- package/lib/ft232h.d.ts +0 -37
- package/lib/ft232h.d.ts.map +0 -1
- package/lib/ft232h.js +0 -204
- package/lib/ft232h.js.map +0 -1
package/src/ftdi.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** biome-ignore-all lint/style/noNestedTernary:
|
|
1
|
+
/** biome-ignore-all lint/style/noNestedTernary: makes code better */
|
|
2
2
|
import type { BitMode, ModemControl, RequestType } from './consts.ts'
|
|
3
3
|
import { REQUESTS, RESET_USB } from './consts.ts'
|
|
4
4
|
import { MPSSE } from './mpsse/mpsse.ts'
|
|
@@ -112,16 +112,16 @@ export class FTDIDevice {
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
async getModemStatus(): Promise<DeviceStatusInfo|undefined> {
|
|
115
|
-
const
|
|
116
|
-
if(
|
|
117
|
-
if(
|
|
118
|
-
assertDataViewNotShared(
|
|
119
|
-
return DeviceStatus.parse(
|
|
115
|
+
const result = await this.#requestIn(REQUESTS.POLL_MODEM_STATUS, STATUS_PREFIX_LENGTH)
|
|
116
|
+
if(result.status !== USB_TRANSFER_OK) { throw new Error(`unexpected status: ${result.status}`) }
|
|
117
|
+
if(result.data === undefined) { throw new Error('undefined data') }
|
|
118
|
+
assertDataViewNotShared(result.data)
|
|
119
|
+
return DeviceStatus.parse(result.data)
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
async getLatencyTimer(): Promise<number> {
|
|
123
123
|
const result = await this.#requestIn(REQUESTS.GET_LATENCY_TIMER, 1)
|
|
124
|
-
if(result.status !== USB_TRANSFER_OK) { throw new Error(
|
|
124
|
+
if(result.status !== USB_TRANSFER_OK) { throw new Error(`unexpected status: ${result.status}`) }
|
|
125
125
|
if(result.data === undefined) { throw new Error('undefined data') }
|
|
126
126
|
|
|
127
127
|
const latency = result.data.getUint8(0)
|
|
@@ -133,12 +133,12 @@ export class FTDIDevice {
|
|
|
133
133
|
if(latency < 0 || latency > 255) { throw new RangeError('latency out of range') }
|
|
134
134
|
|
|
135
135
|
const result = await this.#requestOut(REQUESTS.SET_LATENCY_TIMER, latency)
|
|
136
|
-
if(result.status !== USB_TRANSFER_OK) { throw new Error(
|
|
136
|
+
if(result.status !== USB_TRANSFER_OK) { throw new Error(`unexpected status: ${result.status}`) }
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
async readPins(): Promise<number> {
|
|
140
140
|
const result = await this.#requestIn(REQUESTS.READ_PINS, 1)
|
|
141
|
-
if(result.status !== USB_TRANSFER_OK) { throw new Error(
|
|
141
|
+
if(result.status !== USB_TRANSFER_OK) { throw new Error(`unexpected status: ${result.status}`) }
|
|
142
142
|
if(result.data === undefined) { throw new Error('undefined data') }
|
|
143
143
|
return result.data.getUint8(0)
|
|
144
144
|
}
|
|
@@ -157,7 +157,7 @@ export class FTDIDevice {
|
|
|
157
157
|
const value = dtrValue | rtsValue
|
|
158
158
|
|
|
159
159
|
const result = await this.#requestOut(REQUESTS.SET_MODEM_CTRL, value)
|
|
160
|
-
if(result.status !== USB_TRANSFER_OK) { throw new Error(
|
|
160
|
+
if(result.status !== USB_TRANSFER_OK) { throw new Error(`unexpected status: ${result.status}`) }
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
async setEventChar(data: number, enable = true): Promise<void> {
|
|
@@ -166,7 +166,7 @@ export class FTDIDevice {
|
|
|
166
166
|
const value = enable ? ENABLE_BIT | data : data
|
|
167
167
|
|
|
168
168
|
const result = await this.#requestOut(REQUESTS.SET_EVENT_CHAR, value)
|
|
169
|
-
if(result.status !== USB_TRANSFER_OK) { throw new Error(
|
|
169
|
+
if(result.status !== USB_TRANSFER_OK) { throw new Error(`unexpected status: ${result.status}`) }
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
async setErrorChar(data: number, enable = true): Promise<void> {
|
|
@@ -175,20 +175,19 @@ export class FTDIDevice {
|
|
|
175
175
|
const value = enable ? ENABLE_BIT | data : data
|
|
176
176
|
|
|
177
177
|
const result = await this.#requestOut(REQUESTS.SET_ERROR_CHAR, value)
|
|
178
|
-
if(result.status !== USB_TRANSFER_OK) { throw new Error(
|
|
178
|
+
if(result.status !== USB_TRANSFER_OK) { throw new Error(`unexpected status: ${result.status}`) }
|
|
179
179
|
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
-
|
|
183
182
|
async sendData(data: BufferSource): Promise<number> {
|
|
184
183
|
const result = await this.#device.transferOut(this.#endpointBulkOut, data)
|
|
185
|
-
if(result.status !== USB_TRANSFER_OK) { throw new Error(
|
|
184
|
+
if(result.status !== USB_TRANSFER_OK) { throw new Error(`unexpected status sending data: ${result.status}`) }
|
|
186
185
|
return result.bytesWritten
|
|
187
186
|
}
|
|
188
187
|
|
|
189
188
|
async readData(length: number): Promise<DataView<ArrayBuffer>> {
|
|
190
189
|
const result = await this.#device.transferIn(this.#endpointBulkIn, length)
|
|
191
|
-
if(result.status !== USB_TRANSFER_OK) { throw new Error(
|
|
190
|
+
if(result.status !== USB_TRANSFER_OK) { throw new Error(`unexpected status reading data: ${result.status}`) }
|
|
192
191
|
if(result.data === undefined) { throw new Error('result data undefined') }
|
|
193
192
|
assertDataViewNotShared(result.data)
|
|
194
193
|
return result.data
|
|
@@ -196,7 +195,7 @@ export class FTDIDevice {
|
|
|
196
195
|
|
|
197
196
|
async readEEPROM(address: number, length: number): Promise<DataView<ArrayBuffer>> {
|
|
198
197
|
const result = await this.#requestIn(REQUESTS.READ_EEPROM, length, address)
|
|
199
|
-
if(result.status !== USB_TRANSFER_OK) { throw new Error(
|
|
198
|
+
if(result.status !== USB_TRANSFER_OK) { throw new Error(`unexpected status reading eeprom: ${result.status}`) }
|
|
200
199
|
if(result.data === undefined) { throw new Error('result data undefined') }
|
|
201
200
|
assertDataViewNotShared(result.data)
|
|
202
201
|
|
|
@@ -205,7 +204,7 @@ export class FTDIDevice {
|
|
|
205
204
|
|
|
206
205
|
async writeEEPROM(address: number, value: number): Promise<number> {
|
|
207
206
|
const result = await this.#requestOut(REQUESTS.WRITE_EEPROM, value, address)
|
|
208
|
-
if(result.status !== USB_TRANSFER_OK) { throw new Error(
|
|
207
|
+
if(result.status !== USB_TRANSFER_OK) { throw new Error(`unexpected status writing eeprom: ${result.status}`) }
|
|
209
208
|
return result.bytesWritten
|
|
210
209
|
}
|
|
211
210
|
|
package/src/i2c/i2c-template.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** biome-ignore-all lint/style/useConsistentArrayType:
|
|
1
|
+
/** biome-ignore-all lint/style/useConsistentArrayType: miss-classified */
|
|
2
2
|
import {
|
|
3
3
|
CLOCK_BASE_12,
|
|
4
4
|
CLOCK_BASE_60,
|
|
@@ -14,20 +14,37 @@ import {
|
|
|
14
14
|
} from '../mpsse/command.ts'
|
|
15
15
|
import { MPSSETemplate } from '../mpsse/mpsse-template.ts'
|
|
16
16
|
|
|
17
|
-
const
|
|
18
|
-
const
|
|
17
|
+
export const SCL_PIN_MASK = 0b0000_0001 // D0
|
|
18
|
+
export const SDA_PIN_MASK = 0b0000_0010 // D1
|
|
19
|
+
export const TX_PIN_MASK = 0b0010_0000 // D5
|
|
20
|
+
export const RX_PIN_MASK = 0b0100_0000 // D6
|
|
19
21
|
|
|
20
|
-
const SCL_HIGH_SDA_HIGH: number = SDA_PIN_MASK | SCL_PIN_MASK
|
|
21
|
-
const SCL_HIGH_SDA_LOW: number = SCL_PIN_MASK
|
|
22
|
-
const SCL_LOW_SDA_HIGH: number = SDA_PIN_MASK
|
|
23
|
-
const SCL_LOW_SDA_LOW = 0
|
|
24
22
|
|
|
25
|
-
const SDA_DIRECTION_OUT = 0b0000_0010
|
|
26
|
-
const SCL_DIRECTION_OUT = 0b0000_0001
|
|
27
|
-
const SDA_SCL_DIRECTION_OUT: number = SDA_DIRECTION_OUT | SCL_DIRECTION_OUT
|
|
28
23
|
|
|
29
|
-
const
|
|
30
|
-
const
|
|
24
|
+
export const TX_LOW_RX_LOW = 0
|
|
25
|
+
export const TX_LOW_RX_HIGH: number = RX_PIN_MASK
|
|
26
|
+
export const TX_HIGH_RX_LOW: number = TX_PIN_MASK
|
|
27
|
+
export const TX_HIGH_RX_HIGH: number = RX_PIN_MASK | TX_PIN_MASK
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
export const SCL_HIGH_SDA_HIGH: number = SDA_PIN_MASK | SCL_PIN_MASK | TX_HIGH_RX_HIGH
|
|
31
|
+
export const SCL_HIGH_SDA_LOW: number = SCL_PIN_MASK | TX_HIGH_RX_HIGH
|
|
32
|
+
export const SCL_LOW_SDA_HIGH: number = SDA_PIN_MASK | TX_HIGH_RX_HIGH
|
|
33
|
+
export const SCL_LOW_SDA_LOW: number = 0 | TX_HIGH_RX_HIGH
|
|
34
|
+
|
|
35
|
+
// export const SCL_LOW_SDA_HIGH_RX: number = SDA_PIN_MASK | TX_HIGH_RX_LOW
|
|
36
|
+
// export const SCL_LOW_SDA_HIGH_TX: number = SDA_PIN_MASK | TX_LOW_RX_HIGH
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
export const SDA_DIRECTION_OUT = 0b0000_0010
|
|
42
|
+
export const SCL_DIRECTION_OUT = 0b0000_0001
|
|
43
|
+
export const RX_TX_DIRECTION = 0b0110_0000
|
|
44
|
+
export const SDA_SCL_DIRECTION_OUT: number = SDA_DIRECTION_OUT | SCL_DIRECTION_OUT | RX_TX_DIRECTION
|
|
45
|
+
|
|
46
|
+
export const OPEN_DRAIN_LOW_PIN_MASK = 0b0110_0111
|
|
47
|
+
export const OPEN_DRAIN_HIGH_PIN_MASK = 0b0000_0000
|
|
31
48
|
|
|
32
49
|
export class I2CTemplate {
|
|
33
50
|
static initI2C(targetHertz: number, enableClockDivideBy5 = false): Uint8Array<ArrayBuffer> {
|
|
@@ -98,7 +115,9 @@ export class I2CTemplate {
|
|
|
98
115
|
|
|
99
116
|
static writeByte(data: number): Uint8Array<ArrayBuffer> {
|
|
100
117
|
return Uint8Array.from([
|
|
118
|
+
// ...MPSSETemplate.gpioSetLow(SCL_LOW_SDA_HIGH_TX, SDA_SCL_DIRECTION_OUT),
|
|
101
119
|
...MPSSETemplate.shiftOutByte(SHIFT_COMMAND.OUT_MSB_BYTES_NEGATIVE_VE, 1, data),
|
|
120
|
+
// ...MPSSETemplate.gpioSetLow(SCL_LOW_SDA_LOW, SDA_SCL_DIRECTION_OUT),
|
|
102
121
|
...I2CTemplate.#consumeAck(),
|
|
103
122
|
HOST_AND_MPSSE_MODE_COMMANDS.SEND_IMMEDIATE
|
|
104
123
|
])
|
|
@@ -116,7 +135,7 @@ export class I2CTemplate {
|
|
|
116
135
|
])
|
|
117
136
|
}
|
|
118
137
|
|
|
119
|
-
static readData(ack
|
|
138
|
+
static readData(ack: boolean): Uint8Array<ArrayBuffer> {
|
|
120
139
|
const MSB_ACK_BIT = 0x00
|
|
121
140
|
const MSB_NACK_BIT = 0x80
|
|
122
141
|
const data = ack ? MSB_ACK_BIT : MSB_NACK_BIT
|
package/src/i2c/i2c.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** biome-ignore-all lint/style/noNestedTernary: preserve const assign */
|
|
2
2
|
/** biome-ignore-all lint/performance/noAwaitInLoops: simplify impl */
|
|
3
|
-
/** biome-ignore-all lint/style/useConsistentArrayType:
|
|
3
|
+
/** biome-ignore-all lint/style/useConsistentArrayType: miss-classified */
|
|
4
4
|
import type {
|
|
5
5
|
I2CAddress,
|
|
6
6
|
I2CBufferSource,
|
|
@@ -40,9 +40,6 @@ export async function readData(device: FTDIDevice, length: number, targetBuffer?
|
|
|
40
40
|
new Uint8Array(targetBuffer.buffer, targetBuffer.byteOffset, length) :
|
|
41
41
|
new Uint8Array(targetBuffer, 0, length))
|
|
42
42
|
|
|
43
|
-
// c0 low - RX-LED-emulation
|
|
44
|
-
// await device.mpsse.setGpioHigh(0b0000_0000, 0b0000_0001)
|
|
45
|
-
|
|
46
43
|
for(let offset = 0; offset < length; offset += 1) {
|
|
47
44
|
const ack = offset + 1 < length // is last byte
|
|
48
45
|
|
|
@@ -53,9 +50,6 @@ export async function readData(device: FTDIDevice, length: number, targetBuffer?
|
|
|
53
50
|
buffer.set(new Uint8Array(byteReadResponse.buffer, byteReadResponse.byteOffset, 1), offset)
|
|
54
51
|
}
|
|
55
52
|
|
|
56
|
-
// c0 high - RX-LED-emulation
|
|
57
|
-
// await device.mpsse.setGpioHigh(0b0000_0001, 0b0000_0001)
|
|
58
|
-
|
|
59
53
|
return buffer
|
|
60
54
|
}
|
|
61
55
|
|
|
@@ -99,8 +93,8 @@ export class FT232HBus implements I2CBus {
|
|
|
99
93
|
this.#device = device
|
|
100
94
|
}
|
|
101
95
|
|
|
102
|
-
// biome-ignore lint/
|
|
103
|
-
|
|
96
|
+
// biome-ignore lint/style/useThisInClassMethods: close is a noop
|
|
97
|
+
close(): void {
|
|
104
98
|
// noop
|
|
105
99
|
}
|
|
106
100
|
|
|
@@ -121,9 +115,18 @@ export class FT232HBus implements I2CBus {
|
|
|
121
115
|
return result
|
|
122
116
|
}
|
|
123
117
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
118
|
+
async sendByte(address: I2CAddress, byteValue: number): Promise<void> {
|
|
119
|
+
|
|
120
|
+
//
|
|
121
|
+
const startAck = await sendAndReadACK(this.#device, I2CTemplate.startWithAddress(address, true))
|
|
122
|
+
if(!startAck) { throw new Error('start with address nack') }
|
|
123
|
+
|
|
124
|
+
//
|
|
125
|
+
const writeAck = await sendAndReadACK(this.#device, I2CTemplate.writeByte(byteValue))
|
|
126
|
+
if(!writeAck) { throw new Error('write data nack') }
|
|
127
|
+
|
|
128
|
+
//
|
|
129
|
+
await this.#device.sendData(I2CTemplate.stop())
|
|
127
130
|
}
|
|
128
131
|
|
|
129
132
|
async readI2cBlock(address: I2CAddress, cmd: I2CCommand, length: number, targetBuffer?: I2CBufferSource): Promise<I2CReadResult> {
|
package/src/mpsse/command.ts
CHANGED
|
@@ -14,7 +14,7 @@ export const SHIFT_COMMANDS_DEFINITION = {
|
|
|
14
14
|
|
|
15
15
|
export type ShiftCommand = number
|
|
16
16
|
|
|
17
|
-
export const SHIFT_COMMAND = {
|
|
17
|
+
export const SHIFT_COMMAND = /** @type {const} */ ({
|
|
18
18
|
OUT_MSB_BYTES_POSITIVE_VE: 0x10, // WRITE_TDI
|
|
19
19
|
OUT_MSB_BYTES_NEGATIVE_VE: 0x11, // WRITE_TDI | WRITE_NEGATIVE_EDGE
|
|
20
20
|
OUT_MSB_BITS_POSITIVE_VE: 0x12, // WRITE_TDI | BIT_MODE
|
|
@@ -45,8 +45,7 @@ export const SHIFT_COMMAND = {
|
|
|
45
45
|
IN_OUT_LSB_BYTES_OUT_POSITIVE_IN_NEGATIVE_VE: 0x3C,
|
|
46
46
|
IN_OUT_LSB_BITS_OUT_NEGATIVE_IN_POSITIVE_VE: 0x3B,
|
|
47
47
|
IN_OUT_LSB_BITS_OUT_POSITIVE_IN_NEGATIVE_VE: 0x3E,
|
|
48
|
-
|
|
49
|
-
}
|
|
48
|
+
})
|
|
50
49
|
|
|
51
50
|
// export const LSB_FIRST_TMS_COMMANDS = {
|
|
52
51
|
// CLOCK_DATA_NO_READ_POSITIVE_VE: 0x4A,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
/** biome-ignore-all lint/style/useConsistentArrayType:
|
|
1
|
+
/** biome-ignore-all lint/style/useConsistentArrayType: miss-classified */
|
|
2
|
+
/** biome-ignore-all lint/nursery/noMisleadingReturnType: false-positive */
|
|
2
3
|
import {
|
|
3
4
|
CLOCK_DIVISOR_COMMANDS,
|
|
4
5
|
FT232H_ONLY_COMMANDS,
|
|
@@ -11,23 +12,39 @@ import {
|
|
|
11
12
|
|
|
12
13
|
export class MPSSETemplate {
|
|
13
14
|
static shiftOutByte(command: ShiftCommand, length: number, data: number): Array<number> {
|
|
14
|
-
|
|
15
|
-
const
|
|
15
|
+
if(length <= 0) { throw new RangeError('can not read zero length') }
|
|
16
|
+
const lengthMinusOne = length - 1
|
|
17
|
+
const lengthL = lengthMinusOne & 0xFF
|
|
18
|
+
const lengthH = (lengthMinusOne >> 8) & 0xFF
|
|
16
19
|
return [ command, lengthL, lengthH, data ]
|
|
17
20
|
}
|
|
18
21
|
|
|
22
|
+
static shiftOutBytes(command: ShiftCommand, length: number, data: Array<number>): Array<number> {
|
|
23
|
+
if(length <= 0) { throw new RangeError('can not read zero length') }
|
|
24
|
+
const lengthMinusOne = length - 1
|
|
25
|
+
const lengthL = lengthMinusOne & 0xFF
|
|
26
|
+
const lengthH = (lengthMinusOne >> 8) & 0xFF
|
|
27
|
+
return [ command, lengthL, lengthH, ...data ]
|
|
28
|
+
}
|
|
29
|
+
|
|
19
30
|
static shiftInByte(command: ShiftCommand, length: number): Array<number> {
|
|
20
|
-
|
|
21
|
-
const
|
|
31
|
+
if(length <= 0) { throw new RangeError('can not read zero length') }
|
|
32
|
+
const lengthMinusOne = length - 1
|
|
33
|
+
const lengthL = lengthMinusOne & 0xFF
|
|
34
|
+
const lengthH = (lengthMinusOne >> 8) & 0xFF
|
|
22
35
|
return [ command, lengthL, lengthH ]
|
|
23
36
|
}
|
|
24
37
|
|
|
25
38
|
static shiftOutBits(command: ShiftCommand, length: number, data: number): Array<number> {
|
|
26
|
-
|
|
39
|
+
if(length <= 0) { throw new RangeError('can not read zero length') }
|
|
40
|
+
const lengthMinusOne = length - 1
|
|
41
|
+
return [ command, lengthMinusOne, data ]
|
|
27
42
|
}
|
|
28
43
|
|
|
29
44
|
static shiftInBits(command: ShiftCommand, length: number): Array<number> {
|
|
30
|
-
|
|
45
|
+
if(length <= 0) { throw new RangeError('can not read zero length') }
|
|
46
|
+
const lengthMinusOne = length - 1
|
|
47
|
+
return [ command, lengthMinusOne ]
|
|
31
48
|
}
|
|
32
49
|
|
|
33
50
|
static gpioSetHigh(pins: number, directions: number): Array<number> {
|
|
@@ -54,9 +71,9 @@ export class MPSSETemplate {
|
|
|
54
71
|
return [ PIN_STATE_COMMANDS.READ_DATA_BITS_LOW_BYTE ]
|
|
55
72
|
}
|
|
56
73
|
|
|
57
|
-
static setClockDivisor(
|
|
58
|
-
const divisorL =
|
|
59
|
-
const divisorH = (
|
|
74
|
+
static setClockDivisor(divisor: number): Array<number> {
|
|
75
|
+
const divisorL = divisor & 0xFF
|
|
76
|
+
const divisorH = (divisor >> 8) & 0xFF
|
|
60
77
|
|
|
61
78
|
return [
|
|
62
79
|
CLOCK_DIVISOR_COMMANDS.SET_CLK_DIVISOR,
|
package/src/mpsse/mpsse.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** biome-ignore-all lint/style/useConsistentArrayType:
|
|
1
|
+
/** biome-ignore-all lint/style/useConsistentArrayType: miss-classified */
|
|
2
2
|
import type { FTDIDevice } from '../ftdi.ts'
|
|
3
3
|
import { Util } from '../util.ts'
|
|
4
4
|
import { BAD_COMMAND, BAD_COMMAND_RESPONSE } from './command.ts'
|
|
@@ -49,8 +49,8 @@ export class MPSSE {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
|
|
52
|
-
async setClockDivisor(
|
|
53
|
-
const command = MPSSETemplate.setClockDivisor(
|
|
52
|
+
async setClockDivisor(divisor: number): Promise<void> {
|
|
53
|
+
const command = MPSSETemplate.setClockDivisor(divisor)
|
|
54
54
|
return this.executeCommands(command)
|
|
55
55
|
}
|
|
56
56
|
|
package/src/spi/index.ts
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/** biome-ignore-all lint/style/noNestedTernary: we like them */
|
|
2
|
+
import type {
|
|
3
|
+
SPIBus,
|
|
4
|
+
SPIOptions,
|
|
5
|
+
TransferRequest,
|
|
6
|
+
TransferResult,
|
|
7
|
+
} from '@johntalton/and-other-delights'
|
|
8
|
+
import { DEFAULT_SPI_MODE, MODE_0 } from '@johntalton/and-other-delights'
|
|
9
|
+
import type { FTDIDevice } from '../ftdi.ts'
|
|
10
|
+
import {
|
|
11
|
+
CLOCK_BASE_60,
|
|
12
|
+
CLOCK_DEFAULT_STANDARD_MODE_100_kHz,
|
|
13
|
+
Clock
|
|
14
|
+
} from '../mpsse/clock.ts'
|
|
15
|
+
import { H_COMMANDS, HOST_AND_MPSSE_MODE_COMMANDS, SHIFT_COMMAND } from '../mpsse/command.ts'
|
|
16
|
+
import { MPSSETemplate } from '../mpsse/mpsse-template.ts'
|
|
17
|
+
import { Util } from '../util.ts'
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
// const CLOCK_PIN_MASK = 0b0000_0001
|
|
21
|
+
// const MOSI_PIN_MASK = 0b0000_0010 // host out
|
|
22
|
+
// const MISO_PIN_MASK = 0b0000_0100 // host in
|
|
23
|
+
const CS0_PIN_MASK = 0b0000_1000
|
|
24
|
+
|
|
25
|
+
// const CS1_PIN_MASK = 0b0001_0000
|
|
26
|
+
// const LED_TX_PIN_MASK = 0b0010_0000
|
|
27
|
+
// const LED_RX_PIN_MASK = 0b0100_0000
|
|
28
|
+
// const CLOCK_MONITOR_PIN_MASK = 0b1000_0000
|
|
29
|
+
|
|
30
|
+
const SPI_PIN_DIRECTION = 0b0000_1011
|
|
31
|
+
|
|
32
|
+
export const delayMs = (ms: number): Promise<void> => new Promise(resolve => setTimeout(resolve, ms))
|
|
33
|
+
|
|
34
|
+
export interface FT232HSPIOptions extends SPIOptions {
|
|
35
|
+
chipSelect1?: [boolean]
|
|
36
|
+
ledRxTx?: [boolean]
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export class FTDISPIBus implements SPIBus {
|
|
40
|
+
readonly #device: FTDIDevice
|
|
41
|
+
readonly #options: Partial<FT232HSPIOptions>
|
|
42
|
+
|
|
43
|
+
constructor(device: FTDIDevice, options?: Partial<FT232HSPIOptions>) {
|
|
44
|
+
this.#device = device
|
|
45
|
+
this.#options = options ?? {}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async transfer(request: TransferRequest, options?: Partial<FT232HSPIOptions>): Promise<TransferResult> {
|
|
49
|
+
const {
|
|
50
|
+
mode, speedHz
|
|
51
|
+
} = {
|
|
52
|
+
mode: DEFAULT_SPI_MODE,
|
|
53
|
+
speedHz: CLOCK_DEFAULT_STANDARD_MODE_100_kHz,
|
|
54
|
+
...this.#options,
|
|
55
|
+
...(options ?? {})
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const {
|
|
59
|
+
sendBuffer,
|
|
60
|
+
receiveBufferLength
|
|
61
|
+
} = request
|
|
62
|
+
|
|
63
|
+
if(mode !== MODE_0) { throw new Error('currently mode 0 only') }
|
|
64
|
+
|
|
65
|
+
const writeLength = sendBuffer?.byteLength ?? 0
|
|
66
|
+
const sendBufferU8 = (sendBuffer === undefined) ?
|
|
67
|
+
[] :
|
|
68
|
+
ArrayBuffer.isView(sendBuffer) ?
|
|
69
|
+
new Uint8Array(sendBuffer.buffer, sendBuffer.byteOffset, sendBuffer.byteLength) :
|
|
70
|
+
new Uint8Array(sendBuffer)
|
|
71
|
+
|
|
72
|
+
// calc clock divider for non-div-5
|
|
73
|
+
const divisor = Clock.clockDivisor(speedHz, CLOCK_BASE_60)
|
|
74
|
+
|
|
75
|
+
const totalBytesWritten = await this.#device.sendData(Uint8Array.from([
|
|
76
|
+
// preamble to set state
|
|
77
|
+
H_COMMANDS.DISABLE_CLOCK_DIVIDE_BY_FIVE,
|
|
78
|
+
...MPSSETemplate.setClockDivisor(divisor),
|
|
79
|
+
H_COMMANDS.DISABLE_THREE_PHASE_CLOCKING,
|
|
80
|
+
H_COMMANDS.DISABLE_ADAPTIVE_CLOCKING,
|
|
81
|
+
|
|
82
|
+
// prep pins
|
|
83
|
+
...MPSSETemplate.gpioSetLow(CS0_PIN_MASK, SPI_PIN_DIRECTION), // CS High / Clock Low
|
|
84
|
+
...MPSSETemplate.gpioSetLow(0, SPI_PIN_DIRECTION), // CS Low / Clock Low
|
|
85
|
+
|
|
86
|
+
// transfer data
|
|
87
|
+
...MPSSETemplate.shiftOutBytes(SHIFT_COMMAND.OUT_MSB_BYTES_NEGATIVE_VE, writeLength, [ ...sendBufferU8 ]),
|
|
88
|
+
...((receiveBufferLength === 0) ? [] : MPSSETemplate.shiftInByte(SHIFT_COMMAND.IN_MSB_BYTES_POSITIVE_VE, receiveBufferLength)),
|
|
89
|
+
|
|
90
|
+
// return pins to idle state
|
|
91
|
+
...MPSSETemplate.gpioSetLow(CS0_PIN_MASK, SPI_PIN_DIRECTION), // CS high / Clock Low
|
|
92
|
+
|
|
93
|
+
HOST_AND_MPSSE_MODE_COMMANDS.SEND_IMMEDIATE // do it now
|
|
94
|
+
]))
|
|
95
|
+
|
|
96
|
+
if(totalBytesWritten === 0) { throw new Error('no bytes written') }
|
|
97
|
+
|
|
98
|
+
if(receiveBufferLength === 0) {
|
|
99
|
+
return {
|
|
100
|
+
bytesWritten: writeLength
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// consume buffer
|
|
105
|
+
const result = await Util.pollData(this.#device, receiveBufferLength)
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
bytesWritten: writeLength,
|
|
109
|
+
readBuffer: result
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
}
|
package/src/util.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
/** biome-ignore-all lint/performance/noAwaitInLoops:
|
|
2
|
-
/** biome-ignore-all lint/style/useConsistentArrayType:
|
|
3
|
-
import type { FTDIDevice } from
|
|
4
|
-
import { STATUS_PREFIX_LENGTH } from
|
|
1
|
+
/** biome-ignore-all lint/performance/noAwaitInLoops: simplifies code */
|
|
2
|
+
/** biome-ignore-all lint/style/useConsistentArrayType: miss-classified */
|
|
3
|
+
import type { FTDIDevice } from './ftdi.ts'
|
|
4
|
+
import { STATUS_PREFIX_LENGTH } from './status.ts'
|
|
5
5
|
|
|
6
6
|
export interface ChipInfo {
|
|
7
7
|
major: number
|
|
@@ -57,14 +57,15 @@ export class Util {
|
|
|
57
57
|
return info
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
static async pollData(device: FTDIDevice, attempts = DEFAULT_MAX_POLL_ATTEMPTS): Promise<Uint8Array<ArrayBuffer>> {
|
|
60
|
+
static async pollData(device: FTDIDevice, length = DEFAULT_DATA_READ_SIZE, attempts = DEFAULT_MAX_POLL_ATTEMPTS): Promise<Uint8Array<ArrayBuffer>> {
|
|
61
|
+
// console.log('pollData', length)
|
|
61
62
|
for(let i = 0; i < attempts; i += 1) {
|
|
62
|
-
const response = await device.readData(
|
|
63
|
-
if(response.byteLength === STATUS_PREFIX_LENGTH) { continue }
|
|
63
|
+
const response = await device.readData(STATUS_PREFIX_LENGTH + length)
|
|
64
64
|
if(response === undefined) { throw new Error('no response') }
|
|
65
|
+
if(response.byteLength === STATUS_PREFIX_LENGTH) { continue }
|
|
65
66
|
// const status = DeviceStatus.parse(response)
|
|
66
|
-
// console.log('attempts', i)
|
|
67
|
-
return new Uint8Array(response.buffer, STATUS_PREFIX_LENGTH)
|
|
67
|
+
// console.log('attempts', i, status)
|
|
68
|
+
return new Uint8Array(response.buffer, response.byteOffset + STATUS_PREFIX_LENGTH)
|
|
68
69
|
}
|
|
69
70
|
|
|
70
71
|
throw new Error('no valid data acquired')
|
package/lib/ft232h.d.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/** biome-ignore-all lint/style/noNestedTernary: <explanation> */
|
|
2
|
-
import type { BitMode, ModemControl } from './consts.ts';
|
|
3
|
-
import { MPSSE } from './mpsse/mpsse.ts';
|
|
4
|
-
import { type DeviceStatusInfo } from './status.ts';
|
|
5
|
-
export declare const USB_TRANSFER_OK: USBTransferStatus;
|
|
6
|
-
export declare const USB_TRANSFER_STALL: USBTransferStatus;
|
|
7
|
-
export declare const USB_TRANSFER_BABBLE: USBTransferStatus;
|
|
8
|
-
export declare const REQUEST_TYPE_VENDOR = "vendor";
|
|
9
|
-
export declare const RECIPIENT_DEVICE = "device";
|
|
10
|
-
export declare const INTERFACE_DIRECTION_IN = "in";
|
|
11
|
-
export declare const INTERFACE_DIRECTION_OUT = "out";
|
|
12
|
-
export declare const INTERFACE_TYPE_BULK = "bulk";
|
|
13
|
-
export declare const DEFAULT_CONFIGURATION_NUMBER = 1;
|
|
14
|
-
export declare const DEFAULT_INTERFACE_NUMBER = 0;
|
|
15
|
-
export declare function assertDataViewNotShared(view: DataView): asserts view is DataView & {
|
|
16
|
-
buffer: ArrayBuffer;
|
|
17
|
-
};
|
|
18
|
-
export declare class FT232H {
|
|
19
|
-
#private;
|
|
20
|
-
static from(device: USBDevice): Promise<FT232H>;
|
|
21
|
-
constructor(device: USBDevice, interfaceNumber: number, epIn: number, epOut: number);
|
|
22
|
-
get mpsse(): MPSSE;
|
|
23
|
-
reset(kind?: number): Promise<void>;
|
|
24
|
-
setBitMode(mode: BitMode): Promise<void>;
|
|
25
|
-
getModemStatus(): Promise<DeviceStatusInfo | undefined>;
|
|
26
|
-
getLatencyTimer(): Promise<number>;
|
|
27
|
-
setLatencyTimer(latency: number): Promise<void>;
|
|
28
|
-
readPins(): Promise<number>;
|
|
29
|
-
setModemControl(control: ModemControl): Promise<void>;
|
|
30
|
-
setEventChar(data: number, enable?: boolean): Promise<void>;
|
|
31
|
-
setErrorChar(data: number, enable?: boolean): Promise<void>;
|
|
32
|
-
sendData(data: BufferSource): Promise<number>;
|
|
33
|
-
readData(length: number): Promise<DataView<ArrayBuffer>>;
|
|
34
|
-
readEEPROM(address: number, length: number): Promise<DataView<ArrayBuffer>>;
|
|
35
|
-
writeEEPROM(address: number, value: number): Promise<number>;
|
|
36
|
-
}
|
|
37
|
-
//# sourceMappingURL=ft232h.d.ts.map
|
package/lib/ft232h.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ft232h.d.ts","sourceRoot":"","sources":["../src/ft232h.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAe,MAAM,aAAa,CAAA;AAErE,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AACxC,OAAO,EAEN,KAAK,gBAAgB,EAErB,MAAM,aAAa,CAAA;AAEpB,eAAO,MAAM,eAAe,EAAE,iBAAwB,CAAA;AACtD,eAAO,MAAM,kBAAkB,EAAE,iBAA2B,CAAA;AAC5D,eAAO,MAAM,mBAAmB,EAAE,iBAA4B,CAAA;AAG9D,eAAO,MAAM,mBAAmB,WAAW,CAAA;AAC3C,eAAO,MAAM,gBAAgB,WAAW,CAAA;AAExC,eAAO,MAAM,sBAAsB,OAAO,CAAA;AAC1C,eAAO,MAAM,uBAAuB,QAAQ,CAAA;AAC5C,eAAO,MAAM,mBAAmB,SAAS,CAAA;AAEzC,eAAO,MAAM,4BAA4B,IAAI,CAAA;AAC7C,eAAO,MAAM,wBAAwB,IAAI,CAAA;AAGzC,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,IAAI,QAAQ,GAAG;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,CAI1G;AAED,qBAAa,MAAM;;IAOlB,OAAa,IAAI,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAGpD;IAED,YAAY,MAAM,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAMlF;IAED,IAAI,KAAK,IAAI,KAAK,CAAuB;IAmDnC,KAAK,CAAC,IAAI,SAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAEjD;IAEK,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAI7C;IAEK,cAAc,IAAI,OAAO,CAAC,gBAAgB,GAAC,SAAS,CAAC,CAM1D;IAEK,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC,CAOvC;IAEK,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMpD;IAEK,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,CAKhC;IAEK,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAe1D;IAEK,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,UAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAO7D;IAEK,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,UAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ7D;IAGM,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAIlD;IAEI,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAM7D;IAEK,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAOhF;IAEK,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAIjE;CAKD"}
|