Last active
April 28, 2018 02:06
-
-
Save ryanmjacobs/326cd56e8c21c929ec831484cfe5aadb to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// make sure to unbind your device first | |
// https://stackoverflow.com/questions/47695160/failed-to-claim-interface-0-device-or-resource-busy | |
// echo -n "1-1.3:1.0" | sudo tee /sys/bus/usb/drivers/ch341/unbind | |
let device; | |
async function connectDevice(dev) { | |
await dev.open(); | |
if (dev.configuration === null) | |
await dev.selectConfiguration(1).catch(error => { log(error); }); | |
let ifaces = dev.configuration.interfaces.map(e => e.interfaceNumber); | |
await dev.claimInterface(ifaces[0]).catch(error => { log(error); }); | |
device = dev; | |
} | |
async function send(buf) { | |
console.log (device.opened); | |
var sendData = prompt("Enter something to send","Cascadia"); | |
var buffer = new ArrayBuffer(sendData.length+2); | |
var bufferView = new Uint8Array(buffer); | |
for (var i=0, strLen=sendData.length; i < strLen; i++) { | |
bufferView[i+1] = sendData.charCodeAt(i); | |
} | |
bufferView[0] = strLen+2; | |
bufferView[strLen+1] = 13; | |
if (device.opened) { | |
await device.controlTransferOut({ | |
requestType: "vendor", | |
recipient: "device", | |
request: 250, | |
value: 24, // AMW more data follows | |
index: 0, | |
}, buffer); | |
} | |
} | |
document.getElementById("webusb-connect").onclick = function() { | |
navigator.usb.requestDevice({ filters: [{ vendorId: 0x1209 }] }) | |
.then(dev => { | |
connectDevice(dev); | |
}).catch(error => { log(error); }); | |
}; | |
navigator.usb.getDevices().then(devs => { | |
console.log(devs); | |
}); | |
// not sure what this function does... | |
document.getElementById("webusb-send").onclick = function() { | |
let buf = new ArrayBuffer(5); | |
send(buf); | |
} | |
// or this one... | |
document.getElementById("webusb-rec").onclick = function() { | |
let budf = new ArrayBuffer(5) | |
console.log(device.opened); | |
if (!device.opened) | |
return; | |
device.controlTransferIn({ | |
requestType: "vendor", | |
recipient: "device", | |
request: 249, | |
value: 0x70, | |
index: 0x81 | |
}, 64).then(result => { | |
let decoder = new TextDecoder(); | |
console.log('Received: ' + decoder.decode(result.data)+ '\n'); | |
log('Received: ' + decoder.decode(result.data)+ '\n'); | |
}).catch(error => console.log(error)); | |
}; | |
// We define our function as an 'async function' so that we can | |
// write blocking code within our function body using the 'await' | |
// keyword. | |
document.getElementById("webusb-sendCmd").onclick = async function() { | |
const cmd = 1; | |
try { | |
// The await keyword will 'block' until the promise resolves. | |
// sendCmd() is a function that returns a Promise, because | |
// it optimally returns device.controlTransferOut, (which is a | |
// Promise). | |
await sendCmd(); | |
const results = await requestCmdResult(); | |
console.log("The results are: ...."); | |
console.log(results); | |
} catch (error) { | |
// One of our promises failed to resolve. | |
console.log(error); | |
if (error == "some error string") { | |
// handle it | |
} else if (error == "other error string") { | |
// handle it | |
} | |
} | |
} | |
function sendCmd(cmd) { | |
// Good code returns early for failures. | |
// This is better than wrapping your entire function body with | |
// a single if statement. | |
if (!device.opened) | |
return Promise.reject("error: device not opened"); | |
console.log(device.opened); | |
console.log(cmd); | |
// If you look at the WebUSB spec: | |
// https://wicg.github.io/webusb/#dom-usbdevice-controltransferout | |
// it says that controlTransferOut returns a Promise, | |
// so we simply return this Promise so that it bubbles up through | |
// our higher level code that can handles the errors. | |
// | |
// Promises can either resolve (which means success!) | |
// or reject (which means failure). | |
// | |
// Typically, you can take a Promise and describe what you want to do | |
// when it resolves with a .then(), like so: | |
// | |
// const p = new Promise(); | |
// p.then(someData => console.log(someData)); | |
// | |
// You could also add a catch block to catch rejected errors. | |
// | |
// p.then(someData => console.log(someData)) | |
// .catch(someError => console.log(error)); | |
// | |
// OR in more modern JavaScript, you can use async/await to block the | |
// Promise (which is incredibly useful for dealing with multiple | |
// Promises). | |
// | |
// function oldMethod() { | |
// const a = new Promise(); | |
// a.then(resultA => { | |
// const b = new Promise(); | |
// b.then(resultB => { | |
// const c = new Promise(); | |
// b.then(resultC => { | |
// console.log(resultA, resultB, resultC); | |
// }); | |
// }); | |
// }); | |
// } | |
// | |
// async function newMethod() { | |
// const resultA = await ( new Promise() ); | |
// const resultB = await ( new Promise() ); | |
// const resultC = await ( new Promise() ); | |
// | |
// console.log(resultA, resultB, resultC); | |
// } | |
return device.controlTransferOut({ | |
requestType: "vendor", | |
recipient: "device", | |
request: 250, | |
value: cmd, | |
index: 0 | |
}); | |
} | |
function requestResults() { | |
if (!device.opened) | |
return Promise.reject("error: device not opened"); | |
return device.controlTransferIn({ | |
requestType: "vendor", | |
recipient: "device", | |
request: 249, | |
value: 0x70, | |
index: 0x81 | |
}, 64).then(result => { | |
let decoder = new TextDecoder(); | |
console.log('Received: ' + decoder.decode(result.data)+ '\n'); | |
log('Received: ' + decoder.decode(result.data)+ '\n'); | |
return result.data; | |
}); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment