Removing beta tag (#781)
This commit is contained in:
parent
9825a90df2
commit
4096875a88
@ -1,285 +0,0 @@
|
|||||||
namespace pxt.editor {
|
|
||||||
import HF2 = pxt.HF2
|
|
||||||
import U = pxt.U
|
|
||||||
|
|
||||||
function log(msg: string) {
|
|
||||||
pxt.log("EWRAP: " + msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DirEntry {
|
|
||||||
name: string;
|
|
||||||
md5?: string;
|
|
||||||
size?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
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) == usbMagic) {
|
|
||||||
let code = HF2.read16(buf, 6)
|
|
||||||
let payload = buf.slice(8)
|
|
||||||
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
|
|
||||||
}
|
|
||||||
if (this.dataDump)
|
|
||||||
log("RECV: " + U.toHex(buf))
|
|
||||||
this.msgs.push(buf)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private allocCore(addSize: number, replyType: number) {
|
|
||||||
let len = 5 + addSize
|
|
||||||
let buf = new Uint8Array(len)
|
|
||||||
HF2.write16(buf, 0, len - 2) // pktLen
|
|
||||||
HF2.write16(buf, 2, this.cmdSeq++) // msgCount
|
|
||||||
buf[4] = replyType
|
|
||||||
return buf
|
|
||||||
}
|
|
||||||
|
|
||||||
private allocSystem(addSize: number, cmd: number, replyType = 1) {
|
|
||||||
let buf = this.allocCore(addSize + 1, replyType)
|
|
||||||
buf[5] = cmd
|
|
||||||
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)
|
|
||||||
let pkt = this.allocCore(2 + code.length, 0)
|
|
||||||
HF2.write16(pkt, 5, 0x0800)
|
|
||||||
U.memcpy(pkt, 7, code)
|
|
||||||
log(`run ${path}`)
|
|
||||||
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 (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])
|
|
||||||
}
|
|
||||||
return resp
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
flashAsync(path: string, file: Uint8Array) {
|
|
||||||
log(`write ${file.length} bytes to ${path}`)
|
|
||||||
|
|
||||||
let handle = -1
|
|
||||||
|
|
||||||
let loopAsync = (pos: number): Promise<void> => {
|
|
||||||
if (pos >= file.length) return Promise.resolve()
|
|
||||||
let size = file.length - pos
|
|
||||||
if (size > 1000) size = 1000
|
|
||||||
let upl = this.allocSystem(1 + size, 0x93, 0x1)
|
|
||||||
upl[6] = handle
|
|
||||||
U.memcpy(upl, 6 + 1, file, pos, size)
|
|
||||||
return this.talkAsync(upl, 8) // 8=EOF
|
|
||||||
.then(() => loopAsync(pos + size))
|
|
||||||
}
|
|
||||||
|
|
||||||
let begin = this.allocSystem(4 + path.length + 1, 0x92)
|
|
||||||
HF2.write32(begin, 6, file.length) // fileSize
|
|
||||||
U.memcpy(begin, 10, U.stringToUint8Array(path))
|
|
||||||
return this.lock.enqueue("file", () =>
|
|
||||||
this.talkAsync(begin)
|
|
||||||
.then(resp => {
|
|
||||||
handle = resp[7]
|
|
||||||
return loopAsync(0)
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
lsAsync(path: string): Promise<DirEntry[]> {
|
|
||||||
let lsReq = this.allocSystem(2 + path.length + 1, 0x99)
|
|
||||||
HF2.write16(lsReq, 6, 1024) // maxRead
|
|
||||||
U.memcpy(lsReq, 8, U.stringToUint8Array(path))
|
|
||||||
|
|
||||||
return this.talkAsync(lsReq, 8)
|
|
||||||
.then(resp =>
|
|
||||||
U.uint8ArrayToString(resp.slice(12)).split(/\n/).map(s => {
|
|
||||||
if (!s) return null as DirEntry
|
|
||||||
let m = /^([A-F0-9]+) ([A-F0-9]+) ([^\/]*)$/.exec(s)
|
|
||||||
if (m)
|
|
||||||
return {
|
|
||||||
md5: m[1],
|
|
||||||
size: parseInt(m[2], 16),
|
|
||||||
name: m[3]
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return {
|
|
||||||
name: s.replace(/\/$/, "")
|
|
||||||
}
|
|
||||||
}).filter(v => !!v))
|
|
||||||
}
|
|
||||||
|
|
||||||
rmAsync(path: string): Promise<void> {
|
|
||||||
log(`rm ${path}`)
|
|
||||||
let rmReq = this.allocSystem(path.length + 1, 0x9c)
|
|
||||||
U.memcpy(rmReq, 6, U.stringToUint8Array(path))
|
|
||||||
|
|
||||||
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
|
|
||||||
let handle = -1
|
|
||||||
let resp = (buf: Uint8Array): Promise<void> => {
|
|
||||||
if (buf[6] == 2) {
|
|
||||||
// handle not ready - file is missing
|
|
||||||
this.isStreaming = false
|
|
||||||
return Promise.resolve()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buf[6] != 0 && buf[6] != 8)
|
|
||||||
U.userError("bad response when streaming file: " + buf[6] + " " + U.toHex(buf))
|
|
||||||
|
|
||||||
this.isStreaming = true
|
|
||||||
fileSize = HF2.read32(buf, 7)
|
|
||||||
if (handle == -1) {
|
|
||||||
handle = buf[11]
|
|
||||||
log(`stream on, handle=${handle}`)
|
|
||||||
}
|
|
||||||
let data = buf.slice(12)
|
|
||||||
filePtr += data.length
|
|
||||||
if (data.length > 0)
|
|
||||||
cb(data)
|
|
||||||
|
|
||||||
if (buf[6] == 8) {
|
|
||||||
// end of file
|
|
||||||
this.isStreaming = false
|
|
||||||
return this.rmAsync(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
let contFileReq = this.allocSystem(1 + 2, 0x97)
|
|
||||||
HF2.write16(contFileReq, 7, 1000) // maxRead
|
|
||||||
contFileReq[6] = handle
|
|
||||||
return Promise.delay(data.length > 0 ? 0 : 500)
|
|
||||||
.then(() => this.talkAsync(contFileReq, -1))
|
|
||||||
.then(resp)
|
|
||||||
}
|
|
||||||
|
|
||||||
let getFileReq = this.allocSystem(2 + path.length + 1, 0x96)
|
|
||||||
HF2.write16(getFileReq, 6, 1000) // maxRead
|
|
||||||
U.memcpy(getFileReq, 8, U.stringToUint8Array(path))
|
|
||||||
return this.talkAsync(getFileReq, -1).then(resp)
|
|
||||||
}
|
|
||||||
|
|
||||||
streamFileAsync(path: string, cb: (d: Uint8Array) => void) {
|
|
||||||
let loop = (): Promise<void> =>
|
|
||||||
this.lock.enqueue("file", () =>
|
|
||||||
this.streamFileOnceAsync(path, cb))
|
|
||||||
.then(() => Promise.delay(500))
|
|
||||||
.then(loop)
|
|
||||||
return loop()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
downloadFileAsync(path: string, cb: (d: Uint8Array) => void) {
|
|
||||||
return this.lock.enqueue("file", () =>
|
|
||||||
this.streamFileOnceAsync(path, cb))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private initAsync() {
|
|
||||||
return Promise.resolve()
|
|
||||||
}
|
|
||||||
|
|
||||||
private resetState() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
reconnectAsync(first = false): Promise<void> {
|
|
||||||
this.resetState()
|
|
||||||
if (first) return this.initAsync()
|
|
||||||
log(`reconnect`);
|
|
||||||
return this.io.reconnectAsync()
|
|
||||||
.then(() => this.initAsync())
|
|
||||||
}
|
|
||||||
|
|
||||||
disconnectAsync() {
|
|
||||||
log(`disconnect`);
|
|
||||||
return this.io.disconnectAsync()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -95,7 +95,6 @@
|
|||||||
"privacyUrl": "https://go.microsoft.com/fwlink/?LinkId=521839",
|
"privacyUrl": "https://go.microsoft.com/fwlink/?LinkId=521839",
|
||||||
"termsOfUseUrl": "https://go.microsoft.com/fwlink/?LinkID=206977",
|
"termsOfUseUrl": "https://go.microsoft.com/fwlink/?LinkID=206977",
|
||||||
"githubUrl": "https://github.com/Microsoft/pxt-ev3",
|
"githubUrl": "https://github.com/Microsoft/pxt-ev3",
|
||||||
"betaUrl": "https://makecode.mindstorms.com/about",
|
|
||||||
"driveDisplayName": "EV3",
|
"driveDisplayName": "EV3",
|
||||||
"boardName": "LEGO® MINDSTORMS® Education EV3",
|
"boardName": "LEGO® MINDSTORMS® Education EV3",
|
||||||
"copyrightText": "LEGO, the LEGO logo, MINDSTORMS and the MINDSTORMS EV3 logo are trademarks and/ or copyrights of the LEGO Group. ©2018 The LEGO Group. All rights reserved.",
|
"copyrightText": "LEGO, the LEGO logo, MINDSTORMS and the MINDSTORMS EV3 logo are trademarks and/ or copyrights of the LEGO Group. ©2018 The LEGO Group. All rights reserved.",
|
||||||
|
Loading…
Reference in New Issue
Block a user