身份识别调试完成
This commit is contained in:
@@ -3,56 +3,33 @@ const koffi = require("koffi");
|
||||
const path = require("path");
|
||||
const iconv = require("iconv-lite");
|
||||
|
||||
// 定义结构体
|
||||
// 定义结构体 (使用原始字节数组,避免对齐问题,手动解析)
|
||||
const IDCardData = koffi.struct("IDCardData", {
|
||||
Name: koffi.array("uint8", 32),
|
||||
Sex: koffi.array("uint8", 6),
|
||||
Nation: koffi.array("uint8", 20),
|
||||
Born: koffi.array("uint8", 18),
|
||||
Address: koffi.array("uint8", 72),
|
||||
IDCardNo: koffi.array("uint8", 38),
|
||||
GrantDept: koffi.array("uint8", 32),
|
||||
UserLifeBegin: koffi.array("uint8", 18),
|
||||
UserLifeEnd: koffi.array("uint8", 18),
|
||||
reserved: koffi.array("uint8", 38),
|
||||
PhotoFileName: koffi.array("uint8", 255),
|
||||
raw: koffi.array("uint8", 1024), // 分配足够大的空间
|
||||
});
|
||||
|
||||
let lib = null;
|
||||
let apiCache = null;
|
||||
let running = false;
|
||||
|
||||
// 解码字符串 (尝试 UCS-2/UTF-16LE)
|
||||
// 解码字符串 (GBK)
|
||||
function decodeString(buffer) {
|
||||
// 这里的 buffer 是 uint8 数组,先转为 Buffer
|
||||
const buf = Buffer.from(buffer);
|
||||
// 这里的 buffer 是 uint8 数组 或 Buffer
|
||||
const buf = Buffer.isBuffer(buffer) ? buffer : Buffer.from(buffer);
|
||||
|
||||
// 很多读卡器 DLL 返回的是 UCS-2 (UTF-16LE)
|
||||
// 也有可能是 GBK。我们可以通过检查字节特征来判断,或者优先尝试 UCS-2
|
||||
// UCS-2 的特征是每两个字节一个字符,对于 ASCII 字符,高字节通常是 0x00
|
||||
|
||||
// 尝试作为 UTF-16LE 解码
|
||||
// 找到双 null 结尾 (0x00 0x00)
|
||||
// 找到第一个 null 字节 (0x00) 的位置
|
||||
let nullIndex = -1;
|
||||
for (let i = 0; i < buf.length - 1; i += 2) {
|
||||
if (buf[i] === 0 && buf[i + 1] === 0) {
|
||||
for (let i = 0; i < buf.length; i++) {
|
||||
if (buf[i] === 0) {
|
||||
nullIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const validBuf16 = nullIndex !== -1 ? buf.slice(0, nullIndex) : buf;
|
||||
const str16 = iconv.decode(validBuf16, "utf16le").trim();
|
||||
|
||||
// 如果解码出来的字符串看起来是乱码(包含很多 )或者为空但 buffer 不为空,可能需要尝试 GBK
|
||||
// 但通常 Syn_IDCardRead.dll 返回的是 UCS-2
|
||||
// 让我们先打印一下原始 hex 以便调试
|
||||
// parentPort.postMessage({ type: 'log', payload: `Hex: ${buf.slice(0, 10).toString('hex')}` });
|
||||
|
||||
return str16;
|
||||
}
|
||||
|
||||
// 加载 DLL
|
||||
const validBuf = nullIndex !== -1 ? buf.slice(0, nullIndex) : buf;
|
||||
return iconv.decode(validBuf, "gbk").trim();
|
||||
} // 加载 DLL
|
||||
function loadDll() {
|
||||
if (lib) return true;
|
||||
if (apiCache) return apiCache;
|
||||
try {
|
||||
const fs = require("fs");
|
||||
const dllNames = ["Syn_IDCardRead.dll", "SynIDCardRead.dll"];
|
||||
@@ -105,7 +82,7 @@ function loadDll() {
|
||||
};
|
||||
|
||||
try {
|
||||
return {
|
||||
apiCache = {
|
||||
Syn_OpenPort: loadFunc("Syn_OpenPort", "_Syn_OpenPort@4", "int", [
|
||||
"int",
|
||||
]),
|
||||
@@ -130,10 +107,8 @@ function loadDll() {
|
||||
koffi.out(koffi.pointer(IDCardData)),
|
||||
]),
|
||||
};
|
||||
return apiCache;
|
||||
} catch (e) {
|
||||
// 如果 lib.stdcall 也不行,尝试回退到 func 但不带 __stdcall (可能不是 stdcall 或者 koffi 版本差异)
|
||||
// 但根据之前的错误,不带 __stdcall 找不到函数,带了又报类型错误,说明很可能是 stdcall 但字符串解析有问题
|
||||
// 这里我们坚持用 lib.stdcall 这种显式 API 调用,它比字符串解析更稳定
|
||||
throw e;
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -200,24 +175,49 @@ async function startListen() {
|
||||
const data = {}; // koffi 输出对象
|
||||
const ret = api.Syn_ReadMsg(port, 0, data);
|
||||
|
||||
if (ret === 0 && data) {
|
||||
if (ret === 0 && data && data.raw) {
|
||||
const rawBuf = Buffer.from(data.raw);
|
||||
|
||||
// 调试:打印前 64 字节 Hex
|
||||
// parentPort.postMessage({
|
||||
// type: "log",
|
||||
// payload: `Raw Hex (First 64): ${rawBuf.slice(0, 64).toString("hex")}`,
|
||||
// });
|
||||
|
||||
// 手动切片解析 (修正后的偏移)
|
||||
// Name: 0-32 (32)
|
||||
// Sex: 32-36 (4)
|
||||
// Nation: 36-42 (6)
|
||||
// Born: 42-60 (18)
|
||||
// Address: 60-132 (72)
|
||||
// IDCardNo: 132-170 (38)
|
||||
// GrantDept: 170-202 (32)
|
||||
// UserLifeBegin: 202-220 (18)
|
||||
// UserLifeEnd: 220-238 (18)
|
||||
// PhotoFileName: 276-531 (255)
|
||||
|
||||
const payload = {
|
||||
name: decodeString(data.Name),
|
||||
sex: decodeString(data.Sex),
|
||||
nation: decodeString(data.Nation),
|
||||
born: decodeString(data.Born),
|
||||
address: decodeString(data.Address),
|
||||
id_card_no: decodeString(data.IDCardNo),
|
||||
grant_dept: decodeString(data.GrantDept),
|
||||
life_begin: decodeString(data.UserLifeBegin),
|
||||
life_end: decodeString(data.UserLifeEnd),
|
||||
photo_path: decodeString(data.PhotoFileName),
|
||||
name: decodeString(rawBuf.slice(0, 32)),
|
||||
sex: decodeString(rawBuf.slice(32, 36)),
|
||||
nation: decodeString(rawBuf.slice(36, 42)),
|
||||
born: decodeString(rawBuf.slice(42, 60)),
|
||||
address: decodeString(rawBuf.slice(60, 132)),
|
||||
id_card_no: decodeString(rawBuf.slice(132, 170)),
|
||||
grant_dept: decodeString(rawBuf.slice(170, 202)),
|
||||
life_begin: decodeString(rawBuf.slice(202, 220)),
|
||||
life_end: decodeString(rawBuf.slice(220, 238)),
|
||||
photo_path: decodeString(rawBuf.slice(276, 531)),
|
||||
};
|
||||
|
||||
parentPort.postMessage({
|
||||
type: "log",
|
||||
payload: `Read IDCard success: ${payload.name} ${payload.id_card_no}`,
|
||||
});
|
||||
// 打印完整 payload 以便调试
|
||||
parentPort.postMessage({
|
||||
type: "log",
|
||||
payload: `Full Payload: ${JSON.stringify(payload)}`,
|
||||
});
|
||||
parentPort.postMessage({ type: "data", payload });
|
||||
|
||||
// 读到卡后暂停一下,避免重复读取太快
|
||||
|
||||
Reference in New Issue
Block a user