Skip to content

Commit 667dfe8

Browse files
authored
Use control transfer to write/read from HID (#17)
* Add support for NRF51-DK board. Add support for sending data using control transfer. Allow to override hid interface class. * Use control transfer to write/read data from the device. * Read data from the device after 1 ms delay. * Update webusb version * Use control transfer to interface. * Remove delay between sending write and read commands. * Tidy variables. Move isBufferBinary to utils.
1 parent 449244f commit 667dfe8

File tree

8 files changed

+17218
-37
lines changed

8 files changed

+17218
-37
lines changed

binaries/nrf51dk-led-green.hex

Lines changed: 8577 additions & 0 deletions
Large diffs are not rendered by default.

binaries/nrf51dk-led-red.hex

Lines changed: 8577 additions & 0 deletions
Large diffs are not rendered by default.

examples/web.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,9 @@
256256
case "9900":
257257
binary = binariesPath + "microbit-say-" + color + ".hex";
258258
break;
259+
case "1100":
260+
binary = binariesPath + "nrf51dk-led-" + color + ".hex";
261+
break;
259262
default:
260263
log("No binary found for this target");
261264
return;

src/dap/utils.ts

Lines changed: 0 additions & 17 deletions
This file was deleted.

src/targets/FlashProgram.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as MemoryMap from "nrf-intel-hex";
2-
import {Utils} from "../dap/utils";
2+
import {isBufferBinary} from "../util";
33

44
export class FlashSection {
55
constructor(public address: number, public data: Uint32Array) {
@@ -40,7 +40,7 @@ export class FlashProgram {
4040
constructor(public sections: FlashSection[]) {}
4141

4242
public static fromArrayBuffer(buffer: ArrayBuffer): FlashProgram {
43-
if (Utils.isBufferBinary(buffer)) {
43+
if (isBufferBinary(buffer)) {
4444
return FlashProgram.fromBinary(0, new Uint32Array(buffer));
4545
}
4646
const bufferString = Buffer.from(buffer).toString("utf8");

src/targets/FlashTarget.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,3 +223,4 @@ export class FlashTarget extends CortexM {
223223
export let FlashTargets = new Map<string, IPlatform>();
224224
FlashTargets.set("0240", new K64F());
225225
FlashTargets.set("9900", new NRF51());
226+
FlashTargets.set("1100", new NRF51());

src/transport/hid.ts

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,23 @@ export class HID {
2424
private endpoints: USBEndpoint[];
2525
private epIn: USBEndpoint;
2626
private epOut: USBEndpoint;
27+
private useControlTransfer: boolean;
28+
private packetSize = 64;
29+
private controlTransferGetReport = 0x01;
30+
private controlTransferSetReport = 0x09;
31+
private controlTransferOutReport = 0x200;
32+
private controlTransferInReport = 0x100;
2733

2834
constructor(device: USBDevice) {
2935
this.device = device;
3036
}
3137

32-
public async open() {
38+
public async open(hidInterfaceClass = 0xFF, useControlTransfer = true) {
39+
this.useControlTransfer = useControlTransfer;
3340
await this.device.open();
3441
await this.device.selectConfiguration(1);
35-
3642
const hids = this.device.configuration.interfaces.filter(
37-
intf => intf.alternates[0].interfaceClass === 0xFF);
43+
intf => intf.alternates[0].interfaceClass === hidInterfaceClass);
3844

3945
if (hids.length === 0) {
4046
throw new Error("No HID interfaces found.");
@@ -45,9 +51,7 @@ export class HID {
4551
if (this.interfaces.length === 1) {
4652
this.interface = this.interfaces[0];
4753
}
48-
4954
await this.device.claimInterface(this.interface.interfaceNumber);
50-
5155
this.endpoints = this.interface.alternates[0].endpoints;
5256

5357
this.epIn = null;
@@ -60,28 +64,49 @@ export class HID {
6064
this.epOut = endpoint;
6165
}
6266
}
63-
64-
if (this.epIn === null || this.epOut === null) {
65-
// tslint:disable-next-line:no-console
66-
console.log("Unable to find an in and an out endpoint.");
67-
}
6867
}
6968

7069
public async close() {
7170
return this.device.close();
7271
}
7372

7473
public async write(data: ArrayBuffer): Promise<USBOutTransferResult> {
75-
const reportSize = this.epOut.packetSize;
76-
const buffer = bufferExtend(data, reportSize);
77-
78-
return this.device.transferOut(this.epOut.endpointNumber, buffer);
74+
if (this.epOut && !this.useControlTransfer) {
75+
const reportSize = this.epOut.packetSize;
76+
const buffer = bufferExtend(data, reportSize);
77+
return this.device.transferOut(this.epOut.endpointNumber, buffer);
78+
} else {
79+
// Device does not have out endpoint. Send data using control transfer
80+
const buffer = bufferExtend(data, this.packetSize);
81+
return this.device.controlTransferOut(
82+
{
83+
requestType: "class",
84+
recipient: "interface",
85+
request: this.controlTransferSetReport,
86+
value: this.controlTransferOutReport,
87+
index: this.interface.interfaceNumber
88+
},
89+
buffer
90+
);
91+
}
7992
}
8093

8194
public async read(): Promise<DataView> {
82-
const reportSize = this.epIn.packetSize;
83-
84-
return this.device.transferIn(this.epIn.endpointNumber, reportSize)
85-
.then(res => res.data);
95+
if (this.epIn && !this.useControlTransfer) {
96+
const reportSize = this.epIn.packetSize;
97+
return this.device.transferIn(this.epIn.endpointNumber, reportSize)
98+
.then(res => res.data);
99+
} else {
100+
return this.device.controlTransferIn(
101+
{
102+
requestType: "class",
103+
recipient: "interface",
104+
request: this.controlTransferGetReport,
105+
value: this.controlTransferInReport,
106+
index: this.interface.interfaceNumber
107+
},
108+
this.packetSize
109+
).then(res => res.data);
110+
}
86111
}
87112
}

src/util.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,18 @@ export const hexBytes = (bytes: number[]) => {
113113

114114
return r.toUpperCase();
115115
};
116+
117+
export const isBufferBinary = (buffer: ArrayBuffer): boolean => {
118+
// detect if buffer contains text or binary data
119+
const lengthToCheck = buffer.byteLength > 50 ? 50 : buffer.byteLength;
120+
const bufferString = Buffer.from(buffer).toString("utf8");
121+
for (let i = 0; i < lengthToCheck; i++) {
122+
const charCode = bufferString.charCodeAt(i);
123+
// 65533 is a code for unknown character
124+
// 0-8 are codes for control characters
125+
if (charCode === 65533 || charCode <= 8) {
126+
return true;
127+
}
128+
}
129+
return false;
130+
};

0 commit comments

Comments
 (0)