Snapshot of the working tree exactly as it stood, no edits. This is the predecessor
PRICEGOD was rewritten from ("kept intact, untouched" per pricegod/README.md), and it
is still the only place the DYMO scale is actually implemented —
rfid-daemon/index.js:1068-1265: HID discovery, parseScaleReport, one-shot read, and a
streaming /weight + /scale/start|stop session whose JSON shape PRICEGOD's daemon.js
already speaks.
Preserved verbatim on purpose (hence -og), including the known bug: DYMO_PIDS at
index.js:1082 is [0x8003, 0x8004], so it cannot see the bench M25 (0x8009). Fix that
in whatever daemon inherits the scale, not here.
node_modules stays ignored (22M of the 24M tree). No credentials in the import: the
two PEM markers in utils.js/sheets.js only strip headers off a key read from settings,
and mrpadmin / johnking are an SSH and a Postgres username, both key/trust auth.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
155 lines
5.5 KiB
JavaScript
155 lines
5.5 KiB
JavaScript
'use strict';
|
|
// Chafon H102 probe: scan baud rates, attempt GET_ALL_PARAM, attempt SET interface to CDC_COM
|
|
|
|
const { SerialPort } = require('serialport');
|
|
const PORT = process.env.RFID_PORT || '/dev/cu.usbserial-5130';
|
|
const BAUDS = [115200, 9600, 38400, 57600, 19200];
|
|
|
|
function crc16(buf) {
|
|
let crc = 0xFFFF;
|
|
for (const b of buf) {
|
|
crc ^= b;
|
|
for (let i = 0; i < 8; i++)
|
|
crc = (crc & 1) ? ((crc >> 1) ^ 0x8408) : (crc >> 1);
|
|
}
|
|
return crc;
|
|
}
|
|
|
|
function frame(cmd, data = Buffer.alloc(0)) {
|
|
const hdr = Buffer.from([0xCF, 0x00, cmd[0], cmd[1], data.length]);
|
|
const body = Buffer.concat([hdr, data]);
|
|
const chk = crc16(body);
|
|
const f = Buffer.concat([body, Buffer.from([(chk >> 8) & 0xFF, chk & 0xFF])]);
|
|
console.log(` TX: ${f.toString('hex').replace(/../g,'$& ').trim().toUpperCase()}`);
|
|
return f;
|
|
}
|
|
|
|
const CMD_INVENTORY = [0x00, 0x01];
|
|
const CMD_GET_PARAM = [0x00, 0x72];
|
|
const CMD_SET_PARAM = [0x00, 0x71];
|
|
|
|
// AllParamBean minimal structure to set interface to CDC_COM (0x04)
|
|
// Based on SDK doc: mInterface byte is first param byte.
|
|
// We send a minimal known-safe config: keep everything default, just flip interface.
|
|
// Structure (from SDK AllParamBean): interface(1) baud(1) addr(1) power(1) ...
|
|
// We'll use GET_PARAM first to read existing values then patch interface byte.
|
|
|
|
function tryPort(baud) {
|
|
return new Promise(resolve => {
|
|
console.log(`\n── Testing ${baud} baud ──`);
|
|
const port = new SerialPort({ path: PORT, baudRate: baud, autoOpen: false });
|
|
port.open(err => {
|
|
if (err) { console.log(` open error: ${err.message}`); return resolve(null); }
|
|
|
|
let buf = Buffer.alloc(0);
|
|
let resolved = false;
|
|
const done = (result) => {
|
|
if (resolved) return;
|
|
resolved = true;
|
|
port.close(() => resolve(result));
|
|
};
|
|
|
|
port.on('data', chunk => {
|
|
const hex = chunk.toString('hex').replace(/../g,'$& ').trim().toUpperCase();
|
|
const asc = chunk.toString().replace(/[^\x20-\x7E]/g, '.');
|
|
console.log(` RX: ${hex} "${asc}"`);
|
|
buf = Buffer.concat([buf, chunk]);
|
|
});
|
|
|
|
// Send inventory first (simplest command)
|
|
port.write(frame(CMD_INVENTORY));
|
|
|
|
setTimeout(() => {
|
|
if (buf.length > 0) {
|
|
console.log(` ✓ Got ${buf.length} bytes at ${baud} baud`);
|
|
done({ baud, buf });
|
|
} else {
|
|
console.log(` ✗ No response at ${baud} baud`);
|
|
done(null);
|
|
}
|
|
}, 2000);
|
|
});
|
|
});
|
|
}
|
|
|
|
async function getAndPatchConfig(baud) {
|
|
return new Promise(resolve => {
|
|
console.log(`\n── GET_ALL_PARAM at ${baud} baud ──`);
|
|
const port = new SerialPort({ path: PORT, baudRate: baud, autoOpen: false });
|
|
port.open(err => {
|
|
if (err) return resolve(false);
|
|
|
|
let buf = Buffer.alloc(0);
|
|
port.on('data', chunk => {
|
|
buf = Buffer.concat([buf, chunk]);
|
|
const hex = chunk.toString('hex').replace(/../g,'$& ').trim().toUpperCase();
|
|
console.log(` RX: ${hex}`);
|
|
});
|
|
|
|
port.write(frame(CMD_GET_PARAM));
|
|
|
|
setTimeout(() => {
|
|
if (buf.length < 7) {
|
|
console.log(' No config response received');
|
|
port.close(() => resolve(false));
|
|
return;
|
|
}
|
|
|
|
// Response: CF ADDR CMD_H CMD_L LEN STATUS DATA... CRC_H CRC_L
|
|
// DATA is the AllParamBean bytes — patch interface byte (index 0 of data = STATUS+0)
|
|
// status = buf[5], param data starts at buf[6]
|
|
const status = buf[5];
|
|
console.log(` GET_PARAM status: 0x${status.toString(16)}`);
|
|
if (status !== 0x00) {
|
|
port.close(() => resolve(false));
|
|
return;
|
|
}
|
|
|
|
const paramData = buf.slice(6, buf.length - 2); // strip CRC
|
|
console.log(` Param bytes: ${paramData.toString('hex').replace(/../g,'$& ').trim().toUpperCase()}`);
|
|
console.log(` Current interface byte: 0x${paramData[0]?.toString(16)}`);
|
|
|
|
// Patch interface byte to 0x04 (CDC_COM serial mode)
|
|
paramData[0] = 0x04;
|
|
console.log(` Setting interface to 0x04 (CDC_COM)...`);
|
|
port.write(frame(CMD_SET_PARAM, paramData));
|
|
|
|
setTimeout(() => {
|
|
const hex2 = buf.slice(paramData.length + 9).toString('hex').replace(/../g,'$& ').trim().toUpperCase();
|
|
console.log(` SET_PARAM response raw: ${hex2 || '(none yet)'}`);
|
|
port.close(() => resolve(true));
|
|
}, 2000);
|
|
}, 2000);
|
|
});
|
|
});
|
|
}
|
|
|
|
async function main() {
|
|
console.log(`Probing ${PORT}`);
|
|
console.log('Place a tag on the reader if you have one handy.\n');
|
|
|
|
let workingBaud = null;
|
|
for (const baud of BAUDS) {
|
|
const result = await tryPort(baud);
|
|
if (result) { workingBaud = result.baud; break; }
|
|
}
|
|
|
|
if (!workingBaud) {
|
|
console.log('\n━━━ No response at any baud rate ━━━');
|
|
console.log('Device is likely in USB-HID keyboard wedge mode.');
|
|
console.log('Serial port (CH340) is present but firmware is not routing data to it.');
|
|
console.log('\nFix: use Chafon CfTech Android app over BLE to change Interface setting');
|
|
console.log(' to "CDC_COM" (0x04) or "USB" (0x01), then reconnect USB.');
|
|
console.log('\nSafer option: use one of the shop Android tablets (not your Pixel).');
|
|
return;
|
|
}
|
|
|
|
console.log(`\n✓ Device communicating at ${workingBaud} baud`);
|
|
await getAndPatchConfig(workingBaud);
|
|
console.log('\nDone. If SET_PARAM succeeded, unplug and replug the H102 USB.');
|
|
console.log(`Then restart the daemon with: RFID_BAUD=${workingBaud} node index.js`);
|
|
console.log('(or update BAUD_RATE in index.js if it differs from 115200)');
|
|
}
|
|
|
|
main().catch(console.error);
|