blob: 6aa4ed7c7f83925b7127331d990b634298f2e053 [file] [log] [blame]
Serge Bazanski81981362021-03-06 13:08:00 +01001/**
2 * Low-level interface to programmer's I2C USB class.
3 *
4 * See //dc/hbj11/flasher/bluepill/src/i2c.rs for more information.
5 */
6
7const ControlInRequest = Object.freeze({
8 'GetStatus': 1,
9});
10
11const ControlOutRequest = Object.freeze({
12 'SetLED': 1,
13 'ReadI2C': 2,
14 'ReadBuffer': 3,
15 'WriteI2C': 4,
16 'SetWritePointer': 5,
17});
18
19export const Status = Object.freeze({
20 'Idle': 0,
21 'InvalidArgument': 1,
22 'Ack': 2,
23 'Nack': 3,
24 'BusError': 4,
25});
26
27export const StatusFromU8 = function(u8) {
28 for (const label of Object.keys(Status)) {
29 let val = Status[label];
30 if (val === u8) {
31 return label;
32 }
33 }
34};
35
36/**
37 * Low-level interface to programmer's I2C USB class. Thinly wraps available
38 * USB transfers.
39 */
40export class USBI2CClassInterface {
41 /**
42 * @param {USBDevice} usb - The WebUSB device that backs this USB class.
43 */
44 constructor(device) {
45 this.usb = device;
46 this.BUFFER_SIZE = 1024;
47 this.PACKET_SIZE = 64;
48 }
49
50 /**
51 * Open this programmer via WebUSB and finds all required endpoints.
52 */
53 async open() {
54 await this.usb.open();
55 await this.usb.selectConfiguration(1);
56 await this.usb.claimInterface(0);
57
58 let eps = this.usb.configuration.interfaces[0].alternate.endpoints;
59 this.bulk_out = null;
60 this.bulk_in = null;
61 for (const ep of eps) {
62 if (ep.direction == "out" && ep.type == "bulk") {
63 this.bulk_out = ep;
64 }
65 if (ep.direction == "in" && ep.type == "bulk") {
66 this.bulk_in = ep;
67 }
68 }
69 if (this.bulk_out === null) {
70 throw new Error("Could not find bulk out endpoint");
71 }
72 if (this.bulk_in === null) {
73 throw new Error("Could not find bulk in endpoint");
74 }
75 }
76
77 /**
78 * Performs a USB Control OUT request to the I2C class.
79 * @param {number} request - Request number for transfer (0-255).
80 * @param {number} value - Value for transfer (0-65535).
81 * @returns {Promise<USBOutTransferResult>} The underlying WebUSB transfer result.
82 */
83 async controlOut(request, value) {
84 return await this.usb.controlTransferOut({
85 requestType: "vendor",
86 recipient: "interface",
87 request: request,
88 value: value,
89 index: 0,
90 });
91 }
92
93 /**
94 * Read status from programmer.
95 * @returns {Status} The status of the programmer.
96 */
97 async getStatus() {
98 let res = await this.usb.controlTransferIn({
99 requestType: "vendor",
100 recipient: "interface",
101 request: ControlInRequest.GetStatus,
102 value: 0,
103 index: 0
104 }, 1);
105 if (res.data.byteLength < 1) {
106 throw new Error('returned data too short')
107 }
108 return res.data.getInt8(0);
109 }
110
111 /**
112 * Sends SetLED control OUT request.
113 */
114 async setLED(on) {
115 return await this.controlOut(ControlOutRequest.SetLED, on ? 1 : 0);
116 }
117
118 /**
119 * Sends ReadI2C control OUT request.
120 */
121 async readI2C(addr, length) {
122 return await this.controlOut(ControlOutRequest.ReadI2C, (length << 8) | addr);
123 }
124
125 /**
126 * Sends ReadBuffer control OUT request.
127 */
128 async readBuffer(addr, length) {
129 return await this.controlOut(ControlOutRequest.ReadBuffer, (length << 8) | addr);
130 }
131
132 /**
133 * Sends WriteI2C control OUT request.
134 */
135 async writeI2C(addr, length) {
136 return await this.controlOut(ControlOutRequest.WriteI2C, (length << 8) | addr);
137 }
138
139 /**
140 * Sends SetWritePointer control OUT request.
141 */
142 async setWritePointer(addr) {
143 return await this.controlOut(ControlOutRequest.SetWritePointer, addr);
144 }
145
146 /**
147 * Requets bulk IN data.
148 */
149 async bulkIn(length) {
150 return await this.usb.transferIn(this.bulk_in.endpointNumber, length);
151 }
152
153 /**
154 * Sends bulk OUT data.
155 */
156 async bulkOut(data) {
157 return await this.usb.transferOut(this.bulk_out.endpointNumber, data);
158 }
159}