USB handling in PXT app
This commit is contained in:
parent
672f888663
commit
0de116c9cc
@ -4,9 +4,9 @@
|
||||
require("./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) {
|
||||
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_
|
||||
if (w.isStreaming)
|
||||
U.userError("please stop the program first")
|
||||
return w.stopAsync()
|
||||
}).then(() => {
|
||||
return w.rmAsync(elfPath)
|
||||
}).then(() => {
|
||||
let f = U.stringToUint8Array(atob(resp.outfiles[pxt.outputName()]))
|
||||
@ -60,6 +62,7 @@ namespace pxt.editor {
|
||||
return w.disconnectAsync()
|
||||
else
|
||||
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 => {
|
||||
let str = Util.fromUTF8(Util.uint8ArrayToString(buf))
|
||||
window.postMessage({
|
||||
type: 'serial',
|
||||
id: 'n/a', // TODO
|
||||
data: str
|
||||
}, "*")
|
||||
|
||||
}))
|
||||
*/
|
||||
return Promise.resolve<pxt.editor.ExtensionResult>(res);
|
||||
|
@ -13,26 +13,37 @@ namespace pxt.editor {
|
||||
}
|
||||
|
||||
const runTemplate = "C00882010084XX0060640301606400"
|
||||
const usbMagic = 0x3d3f
|
||||
|
||||
export class Ev3Wrapper {
|
||||
msgs = new U.PromiseBuffer<Uint8Array>()
|
||||
private cmdSeq = U.randomUint32() & 0xffff;
|
||||
private lock = new U.PromiseQueue();
|
||||
isStreaming = false;
|
||||
dataDump = false;
|
||||
|
||||
constructor(public io: pxt.HF2.PacketIO) {
|
||||
io.onData = buf => {
|
||||
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 payload = buf.slice(8)
|
||||
if (code == 1)
|
||||
console.log("Serial: " + U.uint8ArrayToString(payload))
|
||||
else
|
||||
if (code == 1) {
|
||||
let str = U.uint8ArrayToString(payload)
|
||||
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))
|
||||
return
|
||||
}
|
||||
//log("DATA: " + U.toHex(buf))
|
||||
if (this.dataDump)
|
||||
log("RECV: " + U.toHex(buf))
|
||||
this.msgs.push(buf)
|
||||
}
|
||||
}
|
||||
@ -52,6 +63,30 @@ namespace pxt.editor {
|
||||
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) {
|
||||
let codeHex = runTemplate.replace("XX", U.toHex(U.stringToUint8Array(path)))
|
||||
let code = U.fromHex(codeHex)
|
||||
@ -59,21 +94,30 @@ namespace pxt.editor {
|
||||
HF2.write16(pkt, 5, 0x0800)
|
||||
U.memcpy(pkt, 7, code)
|
||||
log(`run ${path}`)
|
||||
return this.talkAsync(pkt)
|
||||
.then(buf => {
|
||||
})
|
||||
return this.justSendAsync(pkt)
|
||||
}
|
||||
|
||||
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) {
|
||||
return this.lock.enqueue("talk", () => {
|
||||
this.msgs.drain()
|
||||
if (this.dataDump)
|
||||
log("TALK: " + U.toHex(buf))
|
||||
return this.io.sendPacketAsync(buf)
|
||||
.then(() => this.msgs.shiftAsync(1000))
|
||||
.then(resp => {
|
||||
if (resp[2] != buf[2] || resp[3] != buf[3])
|
||||
U.userError("msg count de-sync")
|
||||
if (buf[4] == 1) {
|
||||
if (resp[5] != buf[5])
|
||||
if (altResponse != -1 && resp[5] != buf[5])
|
||||
U.userError("cmd de-sync")
|
||||
if (altResponse != -1 && resp[6] != 0 && resp[6] != altResponse)
|
||||
U.userError("cmd error: " + resp[6])
|
||||
@ -84,7 +128,7 @@ namespace pxt.editor {
|
||||
}
|
||||
|
||||
flashAsync(path: string, file: Uint8Array) {
|
||||
log(`write ${file.length} to ${path}`)
|
||||
log(`write ${file.length} bytes to ${path}`)
|
||||
|
||||
let handle = -1
|
||||
|
||||
@ -138,10 +182,22 @@ namespace pxt.editor {
|
||||
let rmReq = this.allocSystem(path.length + 1, 0x9c)
|
||||
U.memcpy(rmReq, 6, U.stringToUint8Array(path))
|
||||
|
||||
return this.talkAsync(rmReq)
|
||||
return this.talkAsync(rmReq, 5)
|
||||
.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) {
|
||||
let fileSize = 0
|
||||
let filePtr = 0
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
void *operator new(size_t size) {
|
||||
@ -71,19 +72,56 @@ Event *mkEvent(int source, int value) {
|
||||
|
||||
#define USB_MAGIC 0x3d3f
|
||||
#define USB_SERIAL 1
|
||||
#define USB_RESTART 2
|
||||
#define USB_DMESG 3
|
||||
|
||||
struct UsbPacket {
|
||||
uint16_t size;
|
||||
uint16_t msgcount;
|
||||
uint16_t magic;
|
||||
uint16_t code;
|
||||
char buf[1000];
|
||||
char buf[1024 - 8];
|
||||
};
|
||||
|
||||
void sendUsb(uint16_t code, const char *data, int len) {
|
||||
if (usbFD == 0)
|
||||
usbFD = open("/dev/lms_usbdev", O_RDWR, 0666);
|
||||
void *usbThread(void *) {
|
||||
UsbPacket pkt;
|
||||
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) {
|
||||
int sz = len;
|
||||
if (sz > 1000)
|
||||
@ -398,6 +436,7 @@ void initRuntime() {
|
||||
startTime = currTime();
|
||||
DMESG("runtime starting...");
|
||||
stopLMS();
|
||||
startUsb();
|
||||
pthread_t disp;
|
||||
pthread_create(&disp, NULL, evtDispatcher, NULL);
|
||||
pthread_detach(disp);
|
||||
|
Loading…
Reference in New Issue
Block a user