@johntalton/ftdi 1.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.
- package/LICENSE +21 -0
- package/README.md +89 -0
- package/lib/consts.d.ts +33 -0
- package/lib/consts.d.ts.map +1 -0
- package/lib/consts.js +42 -0
- package/lib/consts.js.map +1 -0
- package/lib/eeprom.d.ts +129 -0
- package/lib/eeprom.d.ts.map +1 -0
- package/lib/eeprom.js +495 -0
- package/lib/eeprom.js.map +1 -0
- package/lib/ft232h.d.ts +37 -0
- package/lib/ft232h.d.ts.map +1 -0
- package/lib/ft232h.js +204 -0
- package/lib/ft232h.js.map +1 -0
- package/lib/ftdi.d.ts +37 -0
- package/lib/ftdi.d.ts.map +1 -0
- package/lib/ftdi.js +204 -0
- package/lib/ftdi.js.map +1 -0
- package/lib/i2c/i2c-template.d.ts +10 -0
- package/lib/i2c/i2c-template.d.ts.map +1 -0
- package/lib/i2c/i2c-template.js +122 -0
- package/lib/i2c/i2c-template.js.map +1 -0
- package/lib/i2c/i2c.d.ts +29 -0
- package/lib/i2c/i2c.d.ts.map +1 -0
- package/lib/i2c/i2c.js +169 -0
- package/lib/i2c/i2c.js.map +1 -0
- package/lib/i2c/index.d.ts +5 -0
- package/lib/i2c/index.d.ts.map +1 -0
- package/lib/i2c/index.js +5 -0
- package/lib/i2c/index.js.map +1 -0
- package/lib/i2c/range.d.ts +2 -0
- package/lib/i2c/range.d.ts.map +1 -0
- package/lib/i2c/range.js +6 -0
- package/lib/i2c/range.js.map +1 -0
- package/lib/index.d.ts +9 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +9 -0
- package/lib/index.js.map +1 -0
- package/lib/mpsse/clock.d.ts +16 -0
- package/lib/mpsse/clock.d.ts.map +1 -0
- package/lib/mpsse/clock.js +34 -0
- package/lib/mpsse/clock.js.map +1 -0
- package/lib/mpsse/command.d.ts +66 -0
- package/lib/mpsse/command.d.ts.map +1 -0
- package/lib/mpsse/command.js +89 -0
- package/lib/mpsse/command.js.map +1 -0
- package/lib/mpsse/index.d.ts +7 -0
- package/lib/mpsse/index.d.ts.map +1 -0
- package/lib/mpsse/index.js +7 -0
- package/lib/mpsse/index.js.map +1 -0
- package/lib/mpsse/mpsse-template.d.ts +19 -0
- package/lib/mpsse/mpsse-template.d.ts.map +1 -0
- package/lib/mpsse/mpsse-template.js +81 -0
- package/lib/mpsse/mpsse-template.js.map +1 -0
- package/lib/mpsse/mpsse.d.ts +18 -0
- package/lib/mpsse/mpsse.d.ts.map +1 -0
- package/lib/mpsse/mpsse.js +77 -0
- package/lib/mpsse/mpsse.js.map +1 -0
- package/lib/status.d.ts +39 -0
- package/lib/status.d.ts.map +1 -0
- package/lib/status.js +62 -0
- package/lib/status.js.map +1 -0
- package/lib/util.d.ts +26 -0
- package/lib/util.d.ts.map +1 -0
- package/lib/util.js +57 -0
- package/lib/util.js.map +1 -0
- package/package.json +38 -0
- package/src/consts.ts +57 -0
- package/src/eeprom.ts +663 -0
- package/src/ftdi.ts +215 -0
- package/src/i2c/i2c-template.ts +156 -0
- package/src/i2c/i2c.ts +210 -0
- package/src/i2c/index.ts +4 -0
- package/src/i2c/range.ts +6 -0
- package/src/index.ts +8 -0
- package/src/mpsse/clock.ts +36 -0
- package/src/mpsse/command.ts +113 -0
- package/src/mpsse/index.ts +6 -0
- package/src/mpsse/mpsse-template.ts +96 -0
- package/src/mpsse/mpsse.ts +95 -0
- package/src/status.ts +94 -0
- package/src/util.ts +72 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
export const BAD_COMMAND = 0xAF // suggested bad command
|
|
2
|
+
export const BAD_COMMAND_RESPONSE = 0xFA // first response byte when any bad command sent
|
|
3
|
+
|
|
4
|
+
// Shifting commands IN MPSSE Mode
|
|
5
|
+
export const SHIFT_COMMANDS_DEFINITION = {
|
|
6
|
+
WRITE_NEGATIVE_EDGE: 0b0000_0001, // -ve CLK on write
|
|
7
|
+
BIT_MODE: 0b0000_0010, // bit mode = 1 else byte mode
|
|
8
|
+
READ_NEGATIVE_EDGE: 0b0000_0100, // -ve CLK on read
|
|
9
|
+
LSB_FIRST: 0b0000_1000, // LSB first = 1 else MSB first
|
|
10
|
+
WRITE_TDI: 0b0001_0000, // Do write TDI
|
|
11
|
+
READ_TDO: 0b0010_0000, // Do read TDO
|
|
12
|
+
WRITE_TMS: 0b0100_0000 // Do writeTMS
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type ShiftCommand = number
|
|
16
|
+
|
|
17
|
+
export const SHIFT_COMMAND = {
|
|
18
|
+
OUT_MSB_BYTES_POSITIVE_VE: 0x10, // WRITE_TDI
|
|
19
|
+
OUT_MSB_BYTES_NEGATIVE_VE: 0x11, // WRITE_TDI | WRITE_NEGATIVE_EDGE
|
|
20
|
+
OUT_MSB_BITS_POSITIVE_VE: 0x12, // WRITE_TDI | BIT_MODE
|
|
21
|
+
OUT_MSB_BITS_NEGATIVE_VE: 0x13, // WRITE_TDI | BIT_MODE | WRITE_NEGATIVE_EDGE
|
|
22
|
+
|
|
23
|
+
IN_MSB_BYTES_POSITIVE_VE: 0x20, // READ_TDO
|
|
24
|
+
IN_MSB_BYTES_NEGATIVE_VE: 0x24, // READ_TDO | READ_NEGATIVE_EDGE
|
|
25
|
+
IN_MSB_BITS_POSITIVE_VE: 0x22, // READ_TDO | BIT_MODE
|
|
26
|
+
IN_MSB_BITS_NEGATIVE_VE: 0x26, // READ_TDO | BIT_MODE | READ_NEGATIVE_EDGE
|
|
27
|
+
|
|
28
|
+
IN_OUT_MSB_BYTES_OUT_NEGATIVE_IN_POSITIVE_VE: 0x31,
|
|
29
|
+
IN_OUT_MSB_BYTES_OUT_POSITIVE_IN_NEGATIVE_VE: 0x34,
|
|
30
|
+
IN_OUT_MSB_BITS_OUT_NEGATIVE_IN_POSITIVE_VE: 0x33,
|
|
31
|
+
IN_OUT_MSB_BITS_OUT_POSITIVE_IN_NEGATIVE_VE: 0x36,
|
|
32
|
+
|
|
33
|
+
//
|
|
34
|
+
OUT_LSB_BYTES_POSITIVE_VE: 0x18, // LSB_FIRST | WRITE_TDI
|
|
35
|
+
OUT_LSB_BYTES_NEGATIVE_VE: 0x19, // LSB_FIRST | WRITE_TDI | WRITE_NEGATIVE_EDGE
|
|
36
|
+
OUT_LSB_BITS_POSITIVE_VE: 0x1A, // LSB_FIRST | WRITE_TDI | BIT_MODE
|
|
37
|
+
OUT_LSB_BITS_NEGATIVE_VE: 0x1B, // LSB_FIRST | WRITE_TDI | BIT_MODE | WRITE_NEGATIVE_EDGE
|
|
38
|
+
|
|
39
|
+
IN_LSB_BYTES_POSITIVE_VE: 0x28, // LSB_FIRST | READ_TDI
|
|
40
|
+
IN_LSB_BYTES_NEGATIVE_VE: 0x2C, // LSB_FIRST | READ_TDI | READ_NEGATIVE_EDGE
|
|
41
|
+
IN_LSB_BITS_POSITIVE_VE: 0x2A, // LSB_FIRST | READ_TDI | BIT_MODE
|
|
42
|
+
IN_LSB_BITS_NEGATIVE_VE: 0x2E, // LSB_FIRST | READ_TDI | BIT_MODE | READ_NEGATIVE_EDGE
|
|
43
|
+
|
|
44
|
+
IN_OUT_LSB_BYTES_OUT_NEGATIVE_IN_POSITIVE_VE: 0x39,
|
|
45
|
+
IN_OUT_LSB_BYTES_OUT_POSITIVE_IN_NEGATIVE_VE: 0x3C,
|
|
46
|
+
IN_OUT_LSB_BITS_OUT_NEGATIVE_IN_POSITIVE_VE: 0x3B,
|
|
47
|
+
IN_OUT_LSB_BITS_OUT_POSITIVE_IN_NEGATIVE_VE: 0x3E,
|
|
48
|
+
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// export const LSB_FIRST_TMS_COMMANDS = {
|
|
52
|
+
// CLOCK_DATA_NO_READ_POSITIVE_VE: 0x4A,
|
|
53
|
+
// CLOCK_DATA_NO_READ_NEGATIVE_VE: 0x4B,
|
|
54
|
+
|
|
55
|
+
// CLOCK_DATA_WITH_READ_ON_POSITIVE_VE_READ_POSITIVE_VE: 0x6A,
|
|
56
|
+
// CLOCK_DATA_WITH_READ_ON_NEGATIVE_VE_READ_POSITIVE_VE: 0x6B,
|
|
57
|
+
// CLOCK_DATA_WITH_READ_ON_POSITIVE_VE_READ_NEGATIVE_VE: 0x6E,
|
|
58
|
+
// CLOCK_DATA_WITH_READ_ON_NEGATIVE_VE_READ_NEGATIVE_VE: 0x6F
|
|
59
|
+
// }
|
|
60
|
+
|
|
61
|
+
export const PIN_STATE_COMMANDS = {
|
|
62
|
+
SET_DATA_BITS_LOW_BYTE: 0x80,
|
|
63
|
+
SET_DATA_BITS_HIGH_BYTE: 0x82,
|
|
64
|
+
|
|
65
|
+
READ_DATA_BITS_LOW_BYTE: 0x81,
|
|
66
|
+
READ_DATA_BITS_HIGH_BYTE: 0x83
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export const LOOPBACK_COMMANDS = {
|
|
70
|
+
ENABLED: 0x84,
|
|
71
|
+
DISABLE: 0x85
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export const CLOCK_DIVISOR_COMMANDS = {
|
|
75
|
+
SET_CLK_DIVISOR: 0x86
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export const HOST_AND_MPSSE_MODE_COMMANDS = {
|
|
79
|
+
SEND_IMMEDIATE: 0x87,
|
|
80
|
+
// WAIT_IO_HIGH: 0x88,
|
|
81
|
+
// WAIT_IO_LOW: 0x89
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// export const HOST_EMULATION_MODE_COMMANDS = {
|
|
85
|
+
// READ_SHORT_ADDRESS: 0x90,
|
|
86
|
+
// READ_EXTENDED_ADDRESS: 0x91,
|
|
87
|
+
// WRITE_SHORT_ADDRESS: 0x92,
|
|
88
|
+
// WRITE_EXTENDED_ADDRESS: 0x93
|
|
89
|
+
// }
|
|
90
|
+
|
|
91
|
+
export const H_COMMANDS = {
|
|
92
|
+
DISABLE_CLOCK_DIVIDE_BY_FIVE: 0x8A,
|
|
93
|
+
ENABLE_CLOCK_DIVIDE_BY_FIVE: 0x8B,
|
|
94
|
+
|
|
95
|
+
ENABLE_THREE_PHASE_CLOCKING: 0x8C,
|
|
96
|
+
DISABLE_THREE_PHASE_CLOCKING: 0x8D,
|
|
97
|
+
|
|
98
|
+
// CLOCK_N_BITS_NO_TRANSFER: 0x8E,
|
|
99
|
+
// CLOCK_N_EIGHT_BITS_NO_TRANSFER: 0x8F,
|
|
100
|
+
|
|
101
|
+
// CLOCK_WAIT_IO_HIGH: 0x94,
|
|
102
|
+
// CLOCK_WAIT_IO_LOW: 0x95,
|
|
103
|
+
|
|
104
|
+
ENABLE_ADAPTIVE_CLOCKING: 0x96,
|
|
105
|
+
DISABLE_ADAPTIVE_CLOCKING: 0x97,
|
|
106
|
+
|
|
107
|
+
// CLOCK_N_BITS_NO_TRANSFER_OR_UNTIL_HIGH: 0x9C,
|
|
108
|
+
// CLOCK_N_EIGHT_BITS_NO_TRANSFER_OR_UNTIL_LOW: 0x9D
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export const FT232H_ONLY_COMMANDS = {
|
|
112
|
+
SET_IO_ONLY_DRIVE_LOW: 0x9E
|
|
113
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/** biome-ignore-all lint/style/useConsistentArrayType: <explanation> */
|
|
2
|
+
import {
|
|
3
|
+
CLOCK_DIVISOR_COMMANDS,
|
|
4
|
+
FT232H_ONLY_COMMANDS,
|
|
5
|
+
H_COMMANDS,
|
|
6
|
+
LOOPBACK_COMMANDS,
|
|
7
|
+
PIN_STATE_COMMANDS,
|
|
8
|
+
type ShiftCommand
|
|
9
|
+
} from './command.ts'
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
export class MPSSETemplate {
|
|
13
|
+
static shiftOutByte(command: ShiftCommand, length: number, data: number): Array<number> {
|
|
14
|
+
const lengthL = (length - 1) & 0x0F
|
|
15
|
+
const lengthH = ((length - 1) & 0xF0) >> 8
|
|
16
|
+
return [ command, lengthL, lengthH, data ]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
static shiftInByte(command: ShiftCommand, length: number): Array<number> {
|
|
20
|
+
const lengthL = (length - 1) & 0x0F
|
|
21
|
+
const lengthH = ((length - 1) & 0xF0) >> 8
|
|
22
|
+
return [ command, lengthL, lengthH ]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static shiftOutBits(command: ShiftCommand, length: number, data: number): Array<number> {
|
|
26
|
+
return [ command, length - 1, data ]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
static shiftInBits(command: ShiftCommand, length: number): Array<number> {
|
|
30
|
+
return [ command, length - 1 ]
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static gpioSetHigh(pins: number, directions: number): Array<number> {
|
|
34
|
+
return [
|
|
35
|
+
PIN_STATE_COMMANDS.SET_DATA_BITS_HIGH_BYTE,
|
|
36
|
+
pins,
|
|
37
|
+
directions
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static gpioSetLow(pins: number, directions: number): Array<number> {
|
|
42
|
+
return [
|
|
43
|
+
PIN_STATE_COMMANDS.SET_DATA_BITS_LOW_BYTE,
|
|
44
|
+
pins,
|
|
45
|
+
directions
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
static gpioGetHigh(): Array<number> {
|
|
50
|
+
return [ PIN_STATE_COMMANDS.READ_DATA_BITS_HIGH_BYTE ]
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
static gpioGetLow(): Array<number> {
|
|
54
|
+
return [ PIN_STATE_COMMANDS.READ_DATA_BITS_LOW_BYTE ]
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
static setClockDivisor(divider: number): Array<number> {
|
|
58
|
+
const divisorL = divider & 0xFF
|
|
59
|
+
const divisorH = (divider >> 8) & 0xFF
|
|
60
|
+
|
|
61
|
+
return [
|
|
62
|
+
CLOCK_DIVISOR_COMMANDS.SET_CLK_DIVISOR,
|
|
63
|
+
divisorL,
|
|
64
|
+
divisorH
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
static enableLoopback(enable = true): Array<number> {
|
|
69
|
+
if(enable) { return [ LOOPBACK_COMMANDS.ENABLED ] }
|
|
70
|
+
return [ LOOPBACK_COMMANDS.DISABLE ]
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
static enableClockDivideBy5(enable = true): Array<number> {
|
|
74
|
+
if(enable) { return [ H_COMMANDS.ENABLE_CLOCK_DIVIDE_BY_FIVE ] }
|
|
75
|
+
return [ H_COMMANDS.DISABLE_CLOCK_DIVIDE_BY_FIVE]
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
static enableThreePhaseClocking(enable = true): Array<number> {
|
|
79
|
+
if(enable) { return [ H_COMMANDS.ENABLE_THREE_PHASE_CLOCKING ] }
|
|
80
|
+
return [ H_COMMANDS.DISABLE_THREE_PHASE_CLOCKING ]
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
static enableAdaptiveClocking(enable = true): Array<number> {
|
|
84
|
+
if(enable) { return [ H_COMMANDS.ENABLE_ADAPTIVE_CLOCKING ] }
|
|
85
|
+
return [ H_COMMANDS.DISABLE_ADAPTIVE_CLOCKING ]
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
static setDriveOnlyZero(pinsLow: number, pinsHigh: number): Array<number> {
|
|
89
|
+
return [
|
|
90
|
+
FT232H_ONLY_COMMANDS.SET_IO_ONLY_DRIVE_LOW,
|
|
91
|
+
pinsLow,
|
|
92
|
+
pinsHigh
|
|
93
|
+
]
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/** biome-ignore-all lint/style/useConsistentArrayType: <explanation> */
|
|
2
|
+
import type { FTDIDevice } from '../ftdi.ts'
|
|
3
|
+
import { Util } from '../util.ts'
|
|
4
|
+
import { BAD_COMMAND, BAD_COMMAND_RESPONSE } from './command.ts'
|
|
5
|
+
import { MPSSETemplate } from './mpsse-template.ts'
|
|
6
|
+
|
|
7
|
+
export class MPSSE {
|
|
8
|
+
readonly #device: FTDIDevice
|
|
9
|
+
|
|
10
|
+
constructor(device: FTDIDevice) {
|
|
11
|
+
this.#device = device
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async executeCommands(commands: Array<number>|number): Promise<void> {
|
|
15
|
+
const cmdList = Array.isArray(commands) ? commands : [ commands ]
|
|
16
|
+
const flatCmdList = cmdList.flat()
|
|
17
|
+
await this.#device.sendData(Uint8Array.from(flatCmdList))
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async validateMPSSE(command = BAD_COMMAND): Promise<boolean> {
|
|
21
|
+
await this.executeCommands(command)
|
|
22
|
+
const response = await Util.pollData(this.#device).catch(() => undefined)
|
|
23
|
+
|
|
24
|
+
if(response === undefined) { return false }
|
|
25
|
+
const [ first, second ] = response
|
|
26
|
+
if(first !== BAD_COMMAND_RESPONSE) { return false }
|
|
27
|
+
if(second !== command) { return false }
|
|
28
|
+
return true
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async setGpioHigh(pins: number, directions: number): Promise<void> {
|
|
32
|
+
const command = MPSSETemplate.gpioSetHigh(pins, directions)
|
|
33
|
+
return this.executeCommands(command)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async setGpioLow(pins: number, directions: number): Promise<void> {
|
|
37
|
+
const command = MPSSETemplate.gpioSetLow(pins, directions)
|
|
38
|
+
return this.executeCommands(command)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async getGpioHigh(): Promise<void> {
|
|
42
|
+
const command = MPSSETemplate.gpioGetHigh()
|
|
43
|
+
return this.executeCommands(command)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async getGpioLow(): Promise<void> {
|
|
47
|
+
const command = MPSSETemplate.gpioGetLow()
|
|
48
|
+
return this.executeCommands(command)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
async setClockDivisor(divider: number): Promise<void> {
|
|
53
|
+
const command = MPSSETemplate.setClockDivisor(divider)
|
|
54
|
+
return this.executeCommands(command)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// async waitIOHigh(): Promise<void> {s
|
|
58
|
+
|
|
59
|
+
// async waitIOLow(): Promise<void> {
|
|
60
|
+
// }
|
|
61
|
+
|
|
62
|
+
async enableClockDivideBy5(enable = true): Promise<void> {
|
|
63
|
+
const command = MPSSETemplate.enableClockDivideBy5(enable)
|
|
64
|
+
return this.executeCommands(command)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async enableThreePhaseClocking(enable = true): Promise<void> {
|
|
68
|
+
const command = MPSSETemplate.enableThreePhaseClocking(enable)
|
|
69
|
+
return this.executeCommands(command)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// async clcokWaitIOHigh(): Promise<void> {
|
|
73
|
+
// }
|
|
74
|
+
|
|
75
|
+
// async clockWaitIOLow(): Promise<void> {
|
|
76
|
+
// }
|
|
77
|
+
|
|
78
|
+
async enableAdaptiveClocking(enable = true): Promise<void> {
|
|
79
|
+
const command = MPSSETemplate.enableAdaptiveClocking(enable)
|
|
80
|
+
return this.executeCommands(command)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// async clockBitsNoTransferOrUntilHigh(): Promise<void> {
|
|
84
|
+
// }
|
|
85
|
+
|
|
86
|
+
// async clockByteNoTransferOrUntilLow(): Promise<void> {
|
|
87
|
+
// }
|
|
88
|
+
|
|
89
|
+
async setDriveOnlyZero(pinsLow: number, pinsHigh: number): Promise<void> {
|
|
90
|
+
const command = MPSSETemplate.setDriveOnlyZero(pinsLow, pinsHigh)
|
|
91
|
+
return this.executeCommands(command)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
package/src/status.ts
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
|
|
2
|
+
export const STATUS_PREFIX_LENGTH = 2
|
|
3
|
+
|
|
4
|
+
export const MODEM_STATUS_CLEAR_TO_SEND = 0x10
|
|
5
|
+
export const MODEM_STATUS_DATA_SET_READY = 0x20
|
|
6
|
+
export const MODEM_STATUS_RING_INDICATOR = 0x40
|
|
7
|
+
export const MODEM_STATUS_DATA_CARRIER_DETECT = 0x80
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
export const LINE_STATUS_DATA_READY = 0x01
|
|
11
|
+
export const LINE_STATUS_OVERRUN_ERROR = 0x02
|
|
12
|
+
export const LINE_STATUS_PARITY_ERROR = 0x04
|
|
13
|
+
export const LINE_STATUS_FRAMING_ERROR = 0x08
|
|
14
|
+
export const LINE_STATUS_BREAK_INTERRUPT = 0x10
|
|
15
|
+
export const LINE_STATUS_TX_HOLDING_EMPTY = 0x20
|
|
16
|
+
export const LINE_STATUS_TX_EMPTY = 0x40
|
|
17
|
+
export const LINE_STATUS_RECEIVER_ERROR = 0x80
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
export interface DeviceModemStatus {
|
|
21
|
+
data: number
|
|
22
|
+
isClearToSend: boolean
|
|
23
|
+
isDataSetReady: boolean
|
|
24
|
+
isRing: boolean
|
|
25
|
+
isCarrierDetect: boolean
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface DeviceLineStatus {
|
|
29
|
+
data: number
|
|
30
|
+
isDataReady: boolean
|
|
31
|
+
isOverrunError: boolean
|
|
32
|
+
isParityError: boolean
|
|
33
|
+
isFramingError: boolean
|
|
34
|
+
isInterrupt: boolean
|
|
35
|
+
isTXHoldingEmpty: boolean
|
|
36
|
+
isTXEmpty: boolean
|
|
37
|
+
isReceiverError: boolean
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface DeviceStatusInfo {
|
|
41
|
+
modem: DeviceModemStatus,
|
|
42
|
+
line: DeviceLineStatus
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
export class DeviceStatus {
|
|
47
|
+
static parse(data: BufferSource): DeviceStatusInfo|undefined {
|
|
48
|
+
const u8 = ArrayBuffer.isView(data) ?
|
|
49
|
+
new Uint8Array(data.buffer, data.byteOffset, STATUS_PREFIX_LENGTH) :
|
|
50
|
+
new Uint16Array(data, 0, STATUS_PREFIX_LENGTH)
|
|
51
|
+
|
|
52
|
+
const [ modemStatus, lineStatus ] = u8
|
|
53
|
+
|
|
54
|
+
if(modemStatus === undefined) { return undefined }
|
|
55
|
+
if(lineStatus === undefined) { return undefined }
|
|
56
|
+
|
|
57
|
+
//
|
|
58
|
+
const isClearToSend = (modemStatus & MODEM_STATUS_CLEAR_TO_SEND) !== 0
|
|
59
|
+
const isDataSetReady = (modemStatus & MODEM_STATUS_DATA_SET_READY) !== 0
|
|
60
|
+
const isRing = (modemStatus & MODEM_STATUS_RING_INDICATOR) !== 0
|
|
61
|
+
const isCarrierDetect = (modemStatus & MODEM_STATUS_DATA_CARRIER_DETECT) !== 0
|
|
62
|
+
|
|
63
|
+
//
|
|
64
|
+
const isDataReady = (lineStatus & LINE_STATUS_DATA_READY) !== 0
|
|
65
|
+
const isOverrunError = (lineStatus & LINE_STATUS_OVERRUN_ERROR) !== 0
|
|
66
|
+
const isParityError = (lineStatus & LINE_STATUS_PARITY_ERROR) !== 0
|
|
67
|
+
const isFramingError = (lineStatus & LINE_STATUS_FRAMING_ERROR) !== 0
|
|
68
|
+
const isInterrupt = (lineStatus & LINE_STATUS_BREAK_INTERRUPT) !== 0
|
|
69
|
+
const isTXHoldingEmpty = (lineStatus & LINE_STATUS_TX_HOLDING_EMPTY) !== 0
|
|
70
|
+
const isTXEmpty = (lineStatus & LINE_STATUS_TX_EMPTY) !== 0
|
|
71
|
+
const isReceiverError = (lineStatus & LINE_STATUS_RECEIVER_ERROR) !== 0
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
modem: {
|
|
75
|
+
data: modemStatus,
|
|
76
|
+
isClearToSend,
|
|
77
|
+
isDataSetReady,
|
|
78
|
+
isRing,
|
|
79
|
+
isCarrierDetect,
|
|
80
|
+
},
|
|
81
|
+
line: {
|
|
82
|
+
data: lineStatus,
|
|
83
|
+
isDataReady,
|
|
84
|
+
isOverrunError,
|
|
85
|
+
isParityError,
|
|
86
|
+
isFramingError,
|
|
87
|
+
isInterrupt,
|
|
88
|
+
isTXHoldingEmpty,
|
|
89
|
+
isTXEmpty,
|
|
90
|
+
isReceiverError
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
package/src/util.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/** biome-ignore-all lint/performance/noAwaitInLoops: <explanation> */
|
|
2
|
+
/** biome-ignore-all lint/style/useConsistentArrayType: <explanation> */
|
|
3
|
+
import type { FTDIDevice } from "./ftdi.ts"
|
|
4
|
+
import { STATUS_PREFIX_LENGTH } from "./status.ts"
|
|
5
|
+
|
|
6
|
+
export interface ChipInfo {
|
|
7
|
+
major: number
|
|
8
|
+
minor: number
|
|
9
|
+
name: string
|
|
10
|
+
|
|
11
|
+
mpsse?: boolean
|
|
12
|
+
cbus?: boolean
|
|
13
|
+
driveZero?: boolean
|
|
14
|
+
|
|
15
|
+
eepromSize?: number
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const USB_MAJOR_TYPE_BM = 4
|
|
19
|
+
export const USB_MAJOR_TYPE_2232C = 5
|
|
20
|
+
export const USB_MAJOR_TYPE_R = 6
|
|
21
|
+
export const USB_MAJOR_TYPE_2232H = 7
|
|
22
|
+
export const USB_MAJOR_TYPE_4232H = 8
|
|
23
|
+
export const USB_MAJOR_TYPE_232H = 9
|
|
24
|
+
|
|
25
|
+
export const CHIP_INFO: Array<ChipInfo> = [
|
|
26
|
+
// FT8U232AM FT8U245AM // AM Series 1st gen
|
|
27
|
+
// FT245BM FT232BL FT232BQ FT245BL // BM Series 2nd gen
|
|
28
|
+
// FT2232C FT2232D
|
|
29
|
+
// FT4222H // Hi-Speed Quad SPI/I2C Bridge
|
|
30
|
+
// FT600Q / FT601Q / FT602Q
|
|
31
|
+
{ major: 0x02, minor: 0, name: 'FT232AM' }, // 1st gen
|
|
32
|
+
{ major: 0x04, minor: 0, name: 'FT232BM', eepromSize: 64 }, // 2nd gen
|
|
33
|
+
{ major: 0x05, minor: 0, name: 'FT2232C', mpsse: true },
|
|
34
|
+
{ major: 0x06, minor: 0, name: 'FT232R', eepromSize: 64, cbus: true },
|
|
35
|
+
{ major: 0x07, minor: 0, name: 'FT2232H', mpsse: true }, // Dual Channel UART/FIFO/MPSSE
|
|
36
|
+
{ major: 0x08, minor: 0, name: 'FT4232H', mpsse: true }, // Quad Channel UART/FIFO/MPSSE
|
|
37
|
+
{ major: 0x09, minor: 0, name: 'FT232H', eepromSize: 128, mpsse: true, driveZero: true, cbus: true }, // Single Channel UART/FIFO/MPSSE
|
|
38
|
+
{ major: 0x10, minor: 0, name: 'FT-X', cbus: true },
|
|
39
|
+
{ major: 0x20, minor: 0, name: 'FT2233HP' }, // Dual Channel Type-C + Power Delivery
|
|
40
|
+
{ major: 0x28, minor: 0, name: 'FT2233HP' },
|
|
41
|
+
{ major: 0x29, minor: 0, name: 'FT4233HP' }, // Quad Channel Type-C + Power Delivery
|
|
42
|
+
{ major: 0x30, minor: 0, name: 'FT2232HP' }, // Dual Channel Type-C + Power Delivery
|
|
43
|
+
{ major: 0x31, minor: 0, name: 'FT4232HP', mpsse: true }, // Quad Channel Type-C + Power Delivery
|
|
44
|
+
{ major: 0x32, minor: 0, name: 'FT233HP' }, // Single Channel Type-C + Power Delivery
|
|
45
|
+
{ major: 0x33, minor: 0, name: 'FT232HP' }, // Single Channel Type-C + Power Delivery
|
|
46
|
+
{ major: 0x36, minor: 0, name: 'FT4232HA', mpsse: true }, // Automotive Grade Quad UART
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
export const DEFAULT_DATA_READ_SIZE = 64
|
|
51
|
+
export const DEFAULT_MAX_POLL_ATTEMPTS = 5
|
|
52
|
+
|
|
53
|
+
export class Util {
|
|
54
|
+
static chip(major: number, minor: number): ChipInfo | undefined {
|
|
55
|
+
const info = CHIP_INFO.find(ci => ci.major === major && ci.minor === minor)
|
|
56
|
+
if(info === undefined) { return undefined }
|
|
57
|
+
return info
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
static async pollData(device: FTDIDevice, attempts = DEFAULT_MAX_POLL_ATTEMPTS): Promise<Uint8Array<ArrayBuffer>> {
|
|
61
|
+
for(let i = 0; i < attempts; i += 1) {
|
|
62
|
+
const response = await device.readData(DEFAULT_DATA_READ_SIZE)
|
|
63
|
+
if(response.byteLength === STATUS_PREFIX_LENGTH) { continue }
|
|
64
|
+
if(response === undefined) { throw new Error('no response') }
|
|
65
|
+
// const status = DeviceStatus.parse(response)
|
|
66
|
+
// console.log('attempts', i)
|
|
67
|
+
return new Uint8Array(response.buffer, STATUS_PREFIX_LENGTH)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
throw new Error('no valid data acquired')
|
|
71
|
+
}
|
|
72
|
+
}
|