115 строки
3.4 KiB
TypeScript
115 строки
3.4 KiB
TypeScript
namespace jacdac {
|
|
let recvQ: Buffer[]
|
|
|
|
/**
|
|
* Gets the physical layer component id
|
|
**/
|
|
//% shim=jacdac::__physId
|
|
export function __physId(): int32 {
|
|
return 30
|
|
}
|
|
|
|
function jdCrc16(p: Buffer) {
|
|
let crc = 0xffff;
|
|
for (let i = 0; i < p.length; ++i) {
|
|
const data = p[i];
|
|
let x = (crc >> 8) ^ data;
|
|
x ^= x >> 4;
|
|
crc = (crc << 8) ^ (x << 12) ^ (x << 5) ^ x;
|
|
crc &= 0xffff;
|
|
}
|
|
return crc;
|
|
}
|
|
|
|
/**
|
|
* Write a buffer to the jacdac physical layer.
|
|
**/
|
|
//% shim=jacdac::__physSendPacket
|
|
export function __physSendPacket(header: Buffer, data: Buffer): void {
|
|
// the sim transport layer computes the CRC
|
|
let payload = header.concat(data);
|
|
const tailend = payload.length & 3
|
|
if (tailend)
|
|
payload = payload.concat(Buffer.create(4 - tailend))
|
|
header[2] = payload[2] = payload.length - 12
|
|
const crc = jdCrc16(payload.slice(2));
|
|
header[0] = payload[0] = (crc >> 0) & 0xff;
|
|
header[1] = payload[1] = (crc >> 8) & 0xff
|
|
control.simmessages.send("jacdac", payload)
|
|
}
|
|
|
|
/**
|
|
* Reads a packet from the queue. NULL if queue is empty
|
|
**/
|
|
//% shim=jacdac::__physGetPacket
|
|
export function __physGetPacket(): Buffer {
|
|
if (!recvQ) return undefined
|
|
return recvQ.shift()
|
|
}
|
|
|
|
|
|
/**
|
|
* Gets reception time in ms of last __physGetPacket()
|
|
**/
|
|
//% shim=jacdac::__physGetTimestamp
|
|
export function __physGetTimestamp(): number {
|
|
if (!recvQ) return 0
|
|
return control.millis() // TODO
|
|
}
|
|
|
|
/**
|
|
* Indicates if the bus is running
|
|
**/
|
|
//% shim=jacdac::__physIsRunning
|
|
export function __physIsRunning(): boolean {
|
|
return recvQ != null
|
|
}
|
|
|
|
/**
|
|
* Starts the Jacdac physical layer.
|
|
**/
|
|
//% shim=jacdac::__physStart
|
|
export function __physStart(): void {
|
|
if (__physIsRunning()) return
|
|
recvQ = []
|
|
control.simmessages.onReceived("jacdac", buf => {
|
|
if (buf[2] + 12 != buf.length) {
|
|
control.dmesg("bad size in sim jdpkt: " + buf.toHex())
|
|
buf = buf.slice(0, buf[2] + 12)
|
|
}
|
|
const crc = jdCrc16(buf.slice(2));
|
|
if (buf.getNumber(NumberFormat.UInt16LE, 0) != crc) {
|
|
control.dmesg("bad crc in sim")
|
|
} else {
|
|
let num = 0
|
|
const b0 = buf.slice(0)
|
|
while (buf[2] >= 4) {
|
|
const tmp = buf.slice(0, buf[12] + 16)
|
|
recvQ.push(tmp)
|
|
const nextoff = (buf[12] + 16 + 3) & ~3
|
|
buf.write(12, buf.slice(nextoff))
|
|
const skip = nextoff - 12
|
|
if (buf[2] <= skip)
|
|
break
|
|
buf[2] -= skip
|
|
}
|
|
control.raiseEvent(__physId(), 1)
|
|
}
|
|
})
|
|
// announce packet, don't rely on forever
|
|
control.runInParallel(function () {
|
|
while (true) {
|
|
control.raiseEvent(__physId(), 100);
|
|
pause(500)
|
|
}
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Reads the diagnostics struct provided by the physical layer. Returns a buffer or NULL.
|
|
**/
|
|
//% shim=jacdac::__physGetDiagnostics
|
|
export function __physGetDiagnostics(): Buffer {
|
|
return null // TODO?
|
|
}
|
|
} |