Skip to content

Instantly share code, notes, and snippets.

@ecrecover
Created September 8, 2025 05:33
Show Gist options
  • Select an option

  • Save ecrecover/2be47386240c773a4bba8eedacaa0592 to your computer and use it in GitHub Desktop.

Select an option

Save ecrecover/2be47386240c773a4bba8eedacaa0592 to your computer and use it in GitHub Desktop.
import { SerialPort } from 'serialport'
/** ==== CONFIG ==== */
const PORT_PATH = '/dev/tty.usbserial-BG00L04S' // ← change to your device if needed
const BAUD_RATE = 9600
/** ==== OPEN PORT ==== */
const port = new SerialPort({
path: PORT_PATH,
baudRate: BAUD_RATE,
dataBits: 8,
stopBits: 1,
parity: 'odd',
})
/** ==== LED STATE (mirrors 0x94 b0 b1 b2 b3) ==== */
let ledB0 = 0x00,
ledB1 = 0x00,
ledB2 = 0x00,
ledB3 = 0x00
function send(bytes) {
const buf = Buffer.from(bytes)
port.write(buf, (err) => {
if (err) console.error('write error:', err.message)
})
}
function pushLeds() {
send([0x94, ledB0, ledB1, ledB2, ledB3])
}
export function clearLeds() {
ledB0 = ledB1 = ledB2 = ledB3 = 0x00
pushLeds()
}
export function setLedBit(k, on = true) {
if (k < 0x00 || k > 0x1f) return
const grp = k >> 3 // 0..3
const col = k & 7 // 0..7
const bit = 7 - col // left→right
const mask = 1 << bit
if (grp === 0) ledB0 = on ? ledB0 | mask : ledB0 & ~mask
else if (grp === 1) ledB1 = on ? ledB1 | mask : ledB1 & ~mask
else if (grp === 2) ledB2 = on ? ledB2 | mask : ledB2 & ~mask
else if (grp === 3) ledB3 = on ? ledB3 | mask : ledB3 & ~mask
pushLeds()
}
export function toggleLedBit(k) {
if (k < 0x00 || k > 0x1f) return
const grp = k >> 3,
col = k & 7,
bit = 7 - col,
mask = 1 << bit
if (grp === 0) ledB0 ^= mask
else if (grp === 1) ledB1 ^= mask
else if (grp === 2) ledB2 ^= mask
else if (grp === 3) ledB3 ^= mask
pushLeds()
}
/** ==== LPFK INIT ==== */
function init() {
send([0x01]) // Reset
setTimeout(() => send([0x08]), 1000) // Enable
}
/** ==== SERIAL EVENTS ==== */
port.on('open', () => {
console.log('LPFK connected on', PORT_PATH)
init()
})
port.on('data', (buf) => {
for (const byte of buf) {
if (byte <= 0x1f) {
console.log(`Key code: 0x${byte.toString(16).padStart(2, '0')}`)
if (byte === 0x1c) {
// 特殊动画:左上 → 右下 顺序点亮
runSweepAnimation()
} else {
// 普通键:toggle 对应 LED
toggleLedBit(byte)
}
} else if (byte === 0x81) {
// ACK
} else if (byte === 0x80) {
console.warn('Retransmit requested (0x80)')
}
}
})
function runSweepAnimation() {
clearLeds()
const delay = 80 // 每步延迟 ms
for (let k = 0; k < 32; k++) {
setTimeout(() => {
setLedBit(k, true)
}, k * delay)
}
// 结束后清空
setTimeout(() => {
clearLeds()
}, 32 * delay + 500)
}
port.on('error', (err) => {
console.error('SerialPort error:', err.message)
})
/** ==== OPTIONAL: simple CLI helpers ==== */
// Press Ctrl+C to turn all LEDs off before exit.
function gracefulExit() {
try {
clearLeds()
} finally {
process.exit(0)
}
}
process.on('SIGINT', gracefulExit)
process.on('SIGTERM', gracefulExit)
// Export a few helpers for REPL usage if you `node -i -e "import('./lpfk.js')"`
export function enable() {
send([0x08])
}
export function disable() {
send([0x09])
}
export function reset() {
send([0x01])
}
export function readCfg() {
send([0x06])
}
export function setBitmap(b0, b1, b2, b3) {
ledB0 = b0 & 0xff
ledB1 = b1 & 0xff
ledB2 = b2 & 0xff
ledB3 = b3 & 0xff
pushLeds()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment