| /** |
| * Low-level interface to programmer's I2C USB class. |
| * |
| * See //dc/hbj11/flasher/bluepill/src/i2c.rs for more information. |
| */ |
| |
| const ControlInRequest = Object.freeze({ |
| 'GetStatus': 1, |
| }); |
| |
| const ControlOutRequest = Object.freeze({ |
| 'SetLED': 1, |
| 'ReadI2C': 2, |
| 'ReadBuffer': 3, |
| 'WriteI2C': 4, |
| 'SetWritePointer': 5, |
| }); |
| |
| export const Status = Object.freeze({ |
| 'Idle': 0, |
| 'InvalidArgument': 1, |
| 'Ack': 2, |
| 'Nack': 3, |
| 'BusError': 4, |
| }); |
| |
| export const StatusFromU8 = function(u8) { |
| for (const label of Object.keys(Status)) { |
| let val = Status[label]; |
| if (val === u8) { |
| return label; |
| } |
| } |
| }; |
| |
| /** |
| * Low-level interface to programmer's I2C USB class. Thinly wraps available |
| * USB transfers. |
| */ |
| export class USBI2CClassInterface { |
| /** |
| * @param {USBDevice} usb - The WebUSB device that backs this USB class. |
| */ |
| constructor(device) { |
| this.usb = device; |
| this.BUFFER_SIZE = 1024; |
| this.PACKET_SIZE = 64; |
| } |
| |
| /** |
| * Open this programmer via WebUSB and finds all required endpoints. |
| */ |
| async open() { |
| await this.usb.open(); |
| await this.usb.selectConfiguration(1); |
| await this.usb.claimInterface(0); |
| |
| let eps = this.usb.configuration.interfaces[0].alternate.endpoints; |
| this.bulk_out = null; |
| this.bulk_in = null; |
| for (const ep of eps) { |
| if (ep.direction == "out" && ep.type == "bulk") { |
| this.bulk_out = ep; |
| } |
| if (ep.direction == "in" && ep.type == "bulk") { |
| this.bulk_in = ep; |
| } |
| } |
| if (this.bulk_out === null) { |
| throw new Error("Could not find bulk out endpoint"); |
| } |
| if (this.bulk_in === null) { |
| throw new Error("Could not find bulk in endpoint"); |
| } |
| } |
| |
| /** |
| * Performs a USB Control OUT request to the I2C class. |
| * @param {number} request - Request number for transfer (0-255). |
| * @param {number} value - Value for transfer (0-65535). |
| * @returns {Promise<USBOutTransferResult>} The underlying WebUSB transfer result. |
| */ |
| async controlOut(request, value) { |
| return await this.usb.controlTransferOut({ |
| requestType: "vendor", |
| recipient: "interface", |
| request: request, |
| value: value, |
| index: 0, |
| }); |
| } |
| |
| /** |
| * Read status from programmer. |
| * @returns {Status} The status of the programmer. |
| */ |
| async getStatus() { |
| let res = await this.usb.controlTransferIn({ |
| requestType: "vendor", |
| recipient: "interface", |
| request: ControlInRequest.GetStatus, |
| value: 0, |
| index: 0 |
| }, 1); |
| if (res.data.byteLength < 1) { |
| throw new Error('returned data too short') |
| } |
| return res.data.getInt8(0); |
| } |
| |
| /** |
| * Sends SetLED control OUT request. |
| */ |
| async setLED(on) { |
| return await this.controlOut(ControlOutRequest.SetLED, on ? 1 : 0); |
| } |
| |
| /** |
| * Sends ReadI2C control OUT request. |
| */ |
| async readI2C(addr, length) { |
| return await this.controlOut(ControlOutRequest.ReadI2C, (length << 8) | addr); |
| } |
| |
| /** |
| * Sends ReadBuffer control OUT request. |
| */ |
| async readBuffer(addr, length) { |
| return await this.controlOut(ControlOutRequest.ReadBuffer, (length << 8) | addr); |
| } |
| |
| /** |
| * Sends WriteI2C control OUT request. |
| */ |
| async writeI2C(addr, length) { |
| return await this.controlOut(ControlOutRequest.WriteI2C, (length << 8) | addr); |
| } |
| |
| /** |
| * Sends SetWritePointer control OUT request. |
| */ |
| async setWritePointer(addr) { |
| return await this.controlOut(ControlOutRequest.SetWritePointer, addr); |
| } |
| |
| /** |
| * Requets bulk IN data. |
| */ |
| async bulkIn(length) { |
| return await this.usb.transferIn(this.bulk_in.endpointNumber, length); |
| } |
| |
| /** |
| * Sends bulk OUT data. |
| */ |
| async bulkOut(data) { |
| return await this.usb.transferOut(this.bulk_out.endpointNumber, data); |
| } |
| } |