pxt-jacdac/led-pixel/encoder.ts

127 строки
4.3 KiB
TypeScript

namespace jacdac {
function cmdCode(cmd: string) {
switch (cmd) {
case "setall": return 0xD0
case "fade": return 0xD1
case "fadehsv": return 0xD2
case "rotfwd": return 0xD3
case "rotback": return 0xD4
case "show":
case "wait": return 0xD5
case "range": return 0xD6
case "mode": return 0xD7
case "tmpmode": return 0xD8
case "set1":
case "setone": return 0xCF
case "mult": return 0x100
default: return undefined
}
}
function isWhiteSpace(code: number) {
return code == 32 || code == 13 || code == 10 || code == 9
}
export function lightEncode(format: string, args: (number | number[])[]) {
const outarr: number[] = []
let colors: number[] = []
let pos = 0
let currcmd = 0
function pushNumber(n: number) {
if (n == null || (n | 0) != n || n < 0 || n >= 16383)
throw "light: number out of range: " + n
if (n < 128)
outarr.push(n)
else {
outarr.push(0x80 | (n >> 8))
outarr.push(n & 0xff)
}
}
function flush() {
if (currcmd == 0xCF) {
if (colors.length != 1)
throw "setone requires 1 color"
} else {
if (colors.length == 0)
return
if (colors.length <= 3)
outarr.push(0xC0 | colors.length)
else {
outarr.push(0xC0)
outarr.push(colors.length)
}
}
for (let c of colors) {
outarr.push((c >> 16) & 0xff)
outarr.push((c >> 8) & 0xff)
outarr.push((c >> 0) & 0xff)
}
colors = []
}
function nextToken() {
while (isWhiteSpace(format.charCodeAt(pos)))
pos++;
const beg = pos
while (pos < format.length && !isWhiteSpace(format.charCodeAt(pos)))
pos++
return format.slice(beg, pos)
}
while (pos < format.length) {
const token = nextToken()
const t0 = token.charCodeAt(0)
if (97 <= t0 && t0 <= 122) { // a-z
flush()
currcmd = cmdCode(token)
if (currcmd == undefined)
throw "Unknown light command: " + token
if (currcmd == 0x100) {
const f = parseFloat(nextToken())
if (isNaN(f) || f < 0 || f > 2)
throw "expecting scale"
outarr.push(0xD8) // tmpmode
outarr.push(3) // mult
outarr.push(0xD0) // setall
const mm = Math.clamp(0, 255, Math.round(128 * f))
outarr.push(0xC1)
outarr.push(mm)
outarr.push(mm)
outarr.push(mm)
} else {
outarr.push(currcmd)
}
} else if (48 <= t0 && t0 <= 57) { // 0-9
pushNumber(parseInt(token))
} else if (t0 == 37) { // %
if (args.length == 0) throw "Out of args, %"
const v = args.shift()
if (typeof v != "number")
throw "Expecting number"
pushNumber(v)
} else if (t0 == 35) { // #
if (token.length == 1) {
if (args.length == 0) throw "Out of args, #"
const v = args.shift()
if (typeof v == "number")
colors.push(v)
else
for (let vv of v) colors.push(vv)
} else {
if (token.length == 7) {
const b = Buffer.fromHex("00" + token.slice(1))
colors.push(b.getNumber(NumberFormat.UInt32BE, 0))
} else {
throw "Invalid color: " + token
}
}
}
}
flush()
return Buffer.fromArray(outarr)
}
}