blob: 6aa4ed7c7f83925b7127331d990b634298f2e053 [file] [log] [blame]
/**
* 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);
}
}