Add Lian Li SL-INF wireless tools and SignalRGB plugin
Proof-of-concept tools for the UNI FAN SL-INF Wireless kit (SLV3 TX/RX dongles 0416:8040/8041): a Python scan/colour script, tinyuz helpers, a JavaScript tinyuz encoder, the SignalRGB plugin and tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
35240e5dfc
13 files changed
+971
No files matched your search
@@ -0,0 +1,115 @@
|
||||
// Minimal tinyuz encoder (greedy LZ77), stream format of github.com/sisong/tinyuz.
|
||||
// Output decodes with the reference tuz_decompress_mem.
|
||||
const kMinDictMatchLen = 2;
|
||||
const kBigPosForLen = (1 << 11) + (1 << 9) + (1 << 7) - 1;
|
||||
const kMaxDist = 4096;
|
||||
const kCtrlStreamEnd = 3;
|
||||
|
||||
function tuzCompress(data) {
|
||||
const code = [0, 0, 0, 0]; // dict size, patched at the end
|
||||
let typesIndex = 0;
|
||||
let typeCount = 0;
|
||||
let haveDataBack = false;
|
||||
let posBack = 1;
|
||||
let dictSizeMax = 1;
|
||||
|
||||
const outType = (bit) => {
|
||||
if (typeCount === 0) {
|
||||
typesIndex = code.length;
|
||||
code.push(0);
|
||||
}
|
||||
code[typesIndex] |= bit << typeCount;
|
||||
typeCount = (typeCount + 1) & 7;
|
||||
};
|
||||
|
||||
const outLen = (v, packBit) => {
|
||||
let count = 1;
|
||||
while (v >= 2 ** (count * packBit)) {
|
||||
v -= 2 ** (count * packBit);
|
||||
count++;
|
||||
}
|
||||
while (count--) {
|
||||
for (let i = 0; i < packBit; i++) {
|
||||
outType(Math.floor(v / 2 ** (count * packBit + i)) & 1);
|
||||
}
|
||||
outType(count > 0 ? 1 : 0);
|
||||
}
|
||||
};
|
||||
|
||||
const outDictPos = (pos) => {
|
||||
const big = pos >= 128 ? 1 : 0;
|
||||
if (big) {
|
||||
pos -= 128;
|
||||
}
|
||||
code.push((pos & 0x7f) | (big << 7));
|
||||
if (big) {
|
||||
outLen(pos >> 7, 2);
|
||||
}
|
||||
};
|
||||
|
||||
const outLiteral = (b) => {
|
||||
outType(1);
|
||||
code.push(b);
|
||||
haveDataBack = true;
|
||||
};
|
||||
|
||||
const outDict = (len, dist) => {
|
||||
outType(0);
|
||||
const same = haveDataBack && dist === posBack;
|
||||
let saved = len - kMinDictMatchLen;
|
||||
if (!same && dist > kBigPosForLen) {
|
||||
saved--;
|
||||
}
|
||||
outLen(saved, 1);
|
||||
if (haveDataBack) {
|
||||
outType(same ? 1 : 0);
|
||||
}
|
||||
if (!same) {
|
||||
outDictPos(dist);
|
||||
}
|
||||
dictSizeMax = Math.max(dictSizeMax, dist);
|
||||
haveDataBack = false;
|
||||
posBack = dist;
|
||||
};
|
||||
|
||||
let i = 0;
|
||||
while (i < data.length) {
|
||||
let bestLen = 0;
|
||||
let bestDist = 0;
|
||||
for (let dist = 1; dist <= Math.min(i, kMaxDist); dist++) {
|
||||
let len = 0;
|
||||
while (i + len < data.length && data[i + len] === data[i + len - dist]) {
|
||||
len++;
|
||||
}
|
||||
if (len > bestLen) {
|
||||
bestLen = len;
|
||||
bestDist = dist;
|
||||
}
|
||||
}
|
||||
const minLen = bestDist > kBigPosForLen ? 3 : kMinDictMatchLen;
|
||||
if (bestLen >= minLen && (bestLen > 2 || bestDist < 128)) {
|
||||
outDict(bestLen, bestDist);
|
||||
i += bestLen;
|
||||
} else {
|
||||
outLiteral(data[i]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// stream end control code
|
||||
outType(0);
|
||||
outLen(kCtrlStreamEnd, 1);
|
||||
if (haveDataBack) {
|
||||
outType(0);
|
||||
}
|
||||
outDictPos(0);
|
||||
|
||||
for (let k = 0; k < 4; k++) {
|
||||
code[k] = (dictSizeMax >> (8 * k)) & 0xff;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
if (typeof module !== "undefined") {
|
||||
module.exports = { tuzCompress };
|
||||
}
|
||||
Reference in new issue
Block a user