USB handling in PXT app

This commit is contained in:
Michal Moskal 2017-07-09 10:19:14 +01:00
parent 672f888663
commit 0de116c9cc
4 changed files with 116 additions and 22 deletions

View File

@ -4,9 +4,9 @@
require("./editor") require("./editor")
declare namespace pxt.editor { declare namespace pxt.editor {
function deployCoreAsync(resp: pxtc.CompileResult, isCli?: boolean): Promise<void>; function deployCoreAsync(resp: pxtc.CompileResult, disconnect?: boolean): Promise<void>;
} }
export function deployCoreAsync(resp: pxtc.CompileResult) { export function deployCoreAsync(resp: pxtc.CompileResult) {
return pxt.editor.deployCoreAsync(resp, true) return pxt.editor.deployCoreAsync(resp, process.env["PXT_SERIAL"] ? false : true)
} }

View File

@ -42,6 +42,8 @@ namespace pxt.editor {
w = w_ w = w_
if (w.isStreaming) if (w.isStreaming)
U.userError("please stop the program first") U.userError("please stop the program first")
return w.stopAsync()
}).then(() => {
return w.rmAsync(elfPath) return w.rmAsync(elfPath)
}).then(() => { }).then(() => {
let f = U.stringToUint8Array(atob(resp.outfiles[pxt.outputName()])) let f = U.stringToUint8Array(atob(resp.outfiles[pxt.outputName()]))
@ -60,6 +62,7 @@ namespace pxt.editor {
return w.disconnectAsync() return w.disconnectAsync()
else else
return Promise.resolve() return Promise.resolve()
//return Promise.delay(1000).then(() => w.dmesgAsync())
}) })
} }
@ -72,11 +75,7 @@ namespace pxt.editor {
/* /*
.then(w => w.streamFileAsync("/tmp/serial.txt", buf => { .then(w => w.streamFileAsync("/tmp/serial.txt", buf => {
let str = Util.fromUTF8(Util.uint8ArrayToString(buf)) let str = Util.fromUTF8(Util.uint8ArrayToString(buf))
window.postMessage({
type: 'serial',
id: 'n/a', // TODO
data: str
}, "*")
})) }))
*/ */
return Promise.resolve<pxt.editor.ExtensionResult>(res); return Promise.resolve<pxt.editor.ExtensionResult>(res);

View File

@ -13,26 +13,37 @@ namespace pxt.editor {
} }
const runTemplate = "C00882010084XX0060640301606400" const runTemplate = "C00882010084XX0060640301606400"
const usbMagic = 0x3d3f
export class Ev3Wrapper { export class Ev3Wrapper {
msgs = new U.PromiseBuffer<Uint8Array>() msgs = new U.PromiseBuffer<Uint8Array>()
private cmdSeq = U.randomUint32() & 0xffff; private cmdSeq = U.randomUint32() & 0xffff;
private lock = new U.PromiseQueue(); private lock = new U.PromiseQueue();
isStreaming = false; isStreaming = false;
dataDump = false;
constructor(public io: pxt.HF2.PacketIO) { constructor(public io: pxt.HF2.PacketIO) {
io.onData = buf => { io.onData = buf => {
buf = buf.slice(0, HF2.read16(buf, 0) + 2) buf = buf.slice(0, HF2.read16(buf, 0) + 2)
if (HF2.read16(buf, 4) == 0x3d3f) { if (HF2.read16(buf, 4) == usbMagic) {
let code = HF2.read16(buf, 6) let code = HF2.read16(buf, 6)
let payload = buf.slice(8) let payload = buf.slice(8)
if (code == 1) if (code == 1) {
console.log("Serial: " + U.uint8ArrayToString(payload)) let str = U.uint8ArrayToString(payload)
if (Util.isNodeJS)
console.log("SERIAL: " + str.replace(/\n+$/, ""))
else else
window.postMessage({
type: 'serial',
id: 'n/a', // TODO?
data: str
}, "*")
} else
console.log("Magic: " + code + ": " + U.toHex(payload)) console.log("Magic: " + code + ": " + U.toHex(payload))
return return
} }
//log("DATA: " + U.toHex(buf)) if (this.dataDump)
log("RECV: " + U.toHex(buf))
this.msgs.push(buf) this.msgs.push(buf)
} }
} }
@ -52,6 +63,30 @@ namespace pxt.editor {
return buf return buf
} }
private allocCustom(code: number, addSize = 0) {
let buf = this.allocCore(1 + 2 + addSize, 0)
HF2.write16(buf, 4, usbMagic)
HF2.write16(buf, 6, code)
return buf
}
stopAsync() {
return this.isVmAsync()
.then(vm => {
if (vm) return Promise.resolve();
log(`stopping PXT app`)
let buf = this.allocCustom(2)
return this.justSendAsync(buf)
.then(() => Promise.delay(500))
})
}
dmesgAsync() {
log(`asking for DMESG buffer over serial`)
let buf = this.allocCustom(3)
return this.justSendAsync(buf)
}
runAsync(path: string) { runAsync(path: string) {
let codeHex = runTemplate.replace("XX", U.toHex(U.stringToUint8Array(path))) let codeHex = runTemplate.replace("XX", U.toHex(U.stringToUint8Array(path)))
let code = U.fromHex(codeHex) let code = U.fromHex(codeHex)
@ -59,21 +94,30 @@ namespace pxt.editor {
HF2.write16(pkt, 5, 0x0800) HF2.write16(pkt, 5, 0x0800)
U.memcpy(pkt, 7, code) U.memcpy(pkt, 7, code)
log(`run ${path}`) log(`run ${path}`)
return this.talkAsync(pkt) return this.justSendAsync(pkt)
.then(buf => { }
justSendAsync(buf: Uint8Array) {
return this.lock.enqueue("talk", () => {
this.msgs.drain()
if (this.dataDump)
log("SEND: " + U.toHex(buf))
return this.io.sendPacketAsync(buf)
}) })
} }
talkAsync(buf: Uint8Array, altResponse = 0) { talkAsync(buf: Uint8Array, altResponse = 0) {
return this.lock.enqueue("talk", () => { return this.lock.enqueue("talk", () => {
this.msgs.drain() this.msgs.drain()
if (this.dataDump)
log("TALK: " + U.toHex(buf))
return this.io.sendPacketAsync(buf) return this.io.sendPacketAsync(buf)
.then(() => this.msgs.shiftAsync(1000)) .then(() => this.msgs.shiftAsync(1000))
.then(resp => { .then(resp => {
if (resp[2] != buf[2] || resp[3] != buf[3]) if (resp[2] != buf[2] || resp[3] != buf[3])
U.userError("msg count de-sync") U.userError("msg count de-sync")
if (buf[4] == 1) { if (buf[4] == 1) {
if (resp[5] != buf[5]) if (altResponse != -1 && resp[5] != buf[5])
U.userError("cmd de-sync") U.userError("cmd de-sync")
if (altResponse != -1 && resp[6] != 0 && resp[6] != altResponse) if (altResponse != -1 && resp[6] != 0 && resp[6] != altResponse)
U.userError("cmd error: " + resp[6]) U.userError("cmd error: " + resp[6])
@ -84,7 +128,7 @@ namespace pxt.editor {
} }
flashAsync(path: string, file: Uint8Array) { flashAsync(path: string, file: Uint8Array) {
log(`write ${file.length} to ${path}`) log(`write ${file.length} bytes to ${path}`)
let handle = -1 let handle = -1
@ -138,10 +182,22 @@ namespace pxt.editor {
let rmReq = this.allocSystem(path.length + 1, 0x9c) let rmReq = this.allocSystem(path.length + 1, 0x9c)
U.memcpy(rmReq, 6, U.stringToUint8Array(path)) U.memcpy(rmReq, 6, U.stringToUint8Array(path))
return this.talkAsync(rmReq) return this.talkAsync(rmReq, 5)
.then(resp => { }) .then(resp => { })
} }
isVmAsync(): Promise<boolean> {
let path = "/no/such/dir"
let mkdirReq = this.allocSystem(path.length + 1, 0x9b)
U.memcpy(mkdirReq, 6, U.stringToUint8Array(path))
return this.talkAsync(mkdirReq, -1)
.then(resp => {
let isVM = resp[6] == 0x05
log(`${isVM ? "PXT app" : "VM"} running`)
return isVM
})
}
private streamFileOnceAsync(path: string, cb: (d: Uint8Array) => void) { private streamFileOnceAsync(path: string, cb: (d: Uint8Array) => void) {
let fileSize = 0 let fileSize = 0
let filePtr = 0 let filePtr = 0

View File

@ -12,6 +12,7 @@
#include <signal.h> #include <signal.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <errno.h>
#include <fcntl.h> #include <fcntl.h>
void *operator new(size_t size) { void *operator new(size_t size) {
@ -71,19 +72,56 @@ Event *mkEvent(int source, int value) {
#define USB_MAGIC 0x3d3f #define USB_MAGIC 0x3d3f
#define USB_SERIAL 1 #define USB_SERIAL 1
#define USB_RESTART 2
#define USB_DMESG 3
struct UsbPacket { struct UsbPacket {
uint16_t size; uint16_t size;
uint16_t msgcount; uint16_t msgcount;
uint16_t magic; uint16_t magic;
uint16_t code; uint16_t code;
char buf[1000]; char buf[1024 - 8];
}; };
void sendUsb(uint16_t code, const char *data, int len) { void *usbThread(void *) {
if (usbFD == 0) UsbPacket pkt;
usbFD = open("/dev/lms_usbdev", O_RDWR, 0666); UsbPacket resp;
while (true) {
int len = read(usbFD, &pkt, sizeof(pkt));
if (len <= 4) {
sleep_core_us(20000);
continue;
}
resp.msgcount = pkt.msgcount;
if (pkt.magic == USB_MAGIC) {
if (pkt.code == USB_RESTART) {
target_reset();
} else if (pkt.code == USB_DMESG) {
dumpDmesg();
}
/*
resp.magic = pkt.magic;
resp.code = pkt.code;
resp.size = 8;
write(usbFD, &resp, sizeof(resp));
*/
} else {
resp.magic = 0xffff;
resp.size = 4;
write(usbFD, &resp, sizeof(resp));
}
sleep_core_us(1000);
}
}
static void startUsb() {
usbFD = open("/dev/lms_usbdev", O_RDWR, 0666);
pthread_t pid;
pthread_create(&pid, NULL, usbThread, NULL);
pthread_detach(pid);
}
void sendUsb(uint16_t code, const char *data, int len) {
while (len > 0) { while (len > 0) {
int sz = len; int sz = len;
if (sz > 1000) if (sz > 1000)
@ -398,6 +436,7 @@ void initRuntime() {
startTime = currTime(); startTime = currTime();
DMESG("runtime starting..."); DMESG("runtime starting...");
stopLMS(); stopLMS();
startUsb();
pthread_t disp; pthread_t disp;
pthread_create(&disp, NULL, evtDispatcher, NULL); pthread_create(&disp, NULL, evtDispatcher, NULL);
pthread_detach(disp); pthread_detach(disp);