Serge Bazanski | 8198136 | 2021-03-06 13:08:00 +0100 | [diff] [blame] | 1 | /** |
| 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 | |
| 7 | const ControlInRequest = Object.freeze({ |
| 8 | 'GetStatus': 1, |
| 9 | }); |
| 10 | |
| 11 | const ControlOutRequest = Object.freeze({ |
| 12 | 'SetLED': 1, |
| 13 | 'ReadI2C': 2, |
| 14 | 'ReadBuffer': 3, |
| 15 | 'WriteI2C': 4, |
| 16 | 'SetWritePointer': 5, |
| 17 | }); |
| 18 | |
| 19 | export const Status = Object.freeze({ |
| 20 | 'Idle': 0, |
| 21 | 'InvalidArgument': 1, |
| 22 | 'Ack': 2, |
| 23 | 'Nack': 3, |
| 24 | 'BusError': 4, |
| 25 | }); |
| 26 | |
| 27 | export 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 | */ |
| 40 | export 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 | } |