USB handling in PXT app
This commit is contained in:
parent
672f888663
commit
0de116c9cc
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
else
|
if (Util.isNodeJS)
|
||||||
|
console.log("SERIAL: " + str.replace(/\n+$/, ""))
|
||||||
|
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
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user