| <!DOCTYPE html> |
| <html> |
| <head> |
| <meta charset="utf-8"> |
| <title></title> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <script src="resources/manual.js"></script> |
| </head> |
| <body> |
| <p> |
| This test requires a USB device implementing the USB CDC-ACM protocol |
| configured to loop back TX to RX. For example, this Arduino sketch could |
| be used: |
| |
| <pre> |
| void setup() { |
| Serial.begin(115200); |
| Serial.setTimeout(0); |
| while (!Serial) { |
| ; |
| } |
| } |
| |
| void loop() { |
| if (Serial.available()) { |
| char buf[1024]; // Greater than the endpoint packet size. |
| int count = Serial.readBytes(buf, sizeof buf); |
| Serial.write(buf, count); |
| } |
| } |
| </pre> |
| </p> |
| <script> |
| manual_usb_serial_test(async (t, device, inEndpoint, outEndpoint) => { |
| // Set up two IN transfers which should complete in order. |
| const transfer1 = |
| device.transferIn(inEndpoint.endpointNumber, inEndpoint.packetSize); |
| const transfer2 = |
| device.transferIn(inEndpoint.endpointNumber, inEndpoint.packetSize); |
| |
| // Write a single byte to the port which should be echoed to complete |
| // transfer1. |
| let result = await device.transferOut( |
| outEndpoint.endpointNumber, new Uint8Array(['a'.charCodeAt(0)])); |
| assert_equals(result.status, 'ok'); |
| assert_equals(result.bytesWritten, 1); |
| |
| result = await transfer1; |
| assert_equals(result.status, 'ok'); |
| assert_not_equals(result.data, null); |
| assert_equals(result.data.byteLength, 1, 'byteLength'); |
| assert_equals(result.data.getUint8(0), 'a'.charCodeAt(0)); |
| |
| // Set up a third IN transfer which will be canceled when the device is |
| // closed at the end of the test. |
| const transfer3 = promise_rejects_dom( |
| t, 'AbortError', |
| device.transferIn(inEndpoint.endpointNumber, |
| inEndpoint.packetSize)); |
| |
| // Write a single byte to the port which should be echoed to complete |
| // transfer2. |
| result = await device.transferOut( |
| outEndpoint.endpointNumber, new Uint8Array(['b'.charCodeAt(0)])); |
| assert_equals(result.status, 'ok'); |
| assert_equals(result.bytesWritten, 1); |
| |
| result = await transfer2; |
| assert_equals(result.status, 'ok'); |
| assert_not_equals(result.data, null); |
| assert_equals(result.data.byteLength, 1, 'byteLength'); |
| assert_equals(result.data.getUint8(0), 'b'.charCodeAt(0)); |
| |
| await device.close(); |
| await transfer3; |
| }, 'Multiple small IN transfers on an endpoint complete in order'); |
| |
| manual_usb_serial_test(async (t, device, inEndpoint, outEndpoint) => { |
| const bufferLength = outEndpoint.packetSize * 20; |
| const parallelRequests = 6; |
| |
| // Keep track of the order in which transfers are submitted. |
| let enqueueSequence = 0; |
| let dequeueSequence = 0; |
| const received = new Uint8Array(bufferLength); |
| let receivedOffset = 0; |
| let done = false; |
| const transfers = []; |
| |
| async function readNext(sequence) { |
| let result; |
| try { |
| result = await device.transferIn(inEndpoint.endpointNumber, |
| inEndpoint.packetSize); |
| } catch (e) { |
| // The last few transfers will fail when the device is closed. |
| assert_true(done); |
| assert_equals(dequeueSequence++, sequence, 'dequeueSequence done'); |
| assert_equals(receivedOffset, bufferLength, 'receivedOffset'); |
| assert_equals(e.name, 'AbortError'); |
| return; |
| } |
| |
| assert_equals(dequeueSequence++, sequence, 'dequeueSequence'); |
| assert_equals(result.status, 'ok'); |
| assert_not_equals(result.data, null); |
| |
| const data = new Uint8Array( |
| result.data.buffer, result.data.byteOffset, |
| result.data.byteLength); |
| received.set(data, receivedOffset); |
| receivedOffset += result.data.byteLength; |
| |
| // Check |done| because there might be zero-length packet completions |
| // after the data has been completely received. |
| if (!done) { |
| if (receivedOffset == bufferLength) { |
| done = true; |
| assert_array_equals(received, buffer); |
| await device.close(); |
| } else { |
| await readNext(enqueueSequence++); |
| } |
| } |
| } |
| |
| for (let i = 0; i < parallelRequests; ++i) { |
| transfers.push(readNext(enqueueSequence++)); |
| } |
| |
| // Write a large buffer to the device which will be split up into |
| // smaller packets when echoed back. |
| const buffer = new Uint8Array(bufferLength); |
| for (let i = 0; i < buffer.byteLength; ++i) { |
| buffer[i] = i; |
| } |
| let result = await device.transferOut( |
| outEndpoint.endpointNumber, buffer); |
| assert_equals(result.status, 'ok'); |
| assert_equals(result.bytesWritten, buffer.byteLength); |
| |
| await Promise.all(transfers); |
| assert_equals(dequeueSequence, enqueueSequence); |
| }, 'Multiple large IN transfers on an endpoint complete in order'); |
| </script> |
| </body> |
| </html> |