import logger from "../dxmodules/dxLogger.js"
|
import std from '../dxmodules/dxStd.js'
|
import bus from "../dxmodules/dxEventBus.js"
|
import dxos from '../dxmodules/dxOs.js'
|
import config from '../dxmodules/dxConfig.js'
|
import dxMap from '../dxmodules/dxMap.js'
|
import dxFacial from '../dxmodules/dxFacial.js'
|
import dxCapcal from '../dxmodules/dxCapcal.js'
|
import dxCamera from '../dxmodules/dxCamera.js'
|
import audio from '../dxmodules/dxAudio.js'
|
import fingerMz from '../dxmodules/dxFingerMz.js'
|
import fingerZaz from '../dxmodules/dxFingerZaz.js'
|
import pwm from '../dxmodules/dxPwm.js'
|
import ntp from '../dxmodules/dxNtp.js'
|
import gpio from "../dxmodules/dxGpio.js"
|
import dxNfcCard from "../dxmodules/dxNfcCard.js"
|
import watchdog from "../dxmodules/dxWatchdog.js"
|
import dxGpioKey from "../dxmodules/dxGpioKey.js"
|
import net from "../dxmodules/dxNetwork.js"
|
import dxDriver from "../dxmodules/dxDriver.js"
|
import dxDisplay from "../dxmodules/dxDisplay.js"
|
import sqliteService from "./service/sqliteService.js"
|
import mqttService from "./service/mqttService.js"
|
import mqtt from '../dxmodules/dxMqttClient.js'
|
import dxVgCode from './common/utils/codeUtils.js'
|
import dxUartBle from '../dxmodules/dxVgBle.js'
|
import utils from "./common/utils/utils.js"
|
import common from "../dxmodules/dxCommon.js"
|
|
const driver = {}
|
|
driver.config = {
|
init: function () {
|
config.init()
|
let mac = dxos.getUuid2mac(19)
|
let uuid = dxos.getSn(19)
|
if (!config.get('sys.mac') && mac) {
|
config.set('sys.mac', mac)
|
}
|
if (!config.get('sys.uuid') && uuid) {
|
config.set('sys.uuid', uuid)
|
}
|
//如果 sn 为空先用设备 uuid
|
if (!config.get('sys.sn') && uuid) {
|
config.set('sys.sn', uuid)
|
}
|
if (!config.get('mqtt.clientId') && uuid) {
|
config.set('mqtt.clientId', uuid)
|
}
|
if (driver.device.finger) {
|
if (dxDriver.DRIVER.MODEL == "vf105") {
|
config.set('sys.model', "vf107")
|
} else if (dxDriver.DRIVER.MODEL == "vf114") {
|
config.set('sys.model', "vf124")
|
}
|
} else {
|
config.set('sys.model', dxDriver.DRIVER.MODEL)
|
}
|
//初始化语言判断国内版本还是国外版本
|
try {
|
const language = std.loadFile('/etc/app/region.conf')?.trim();
|
const defaultLanguage = "CN";
|
|
if (language === "INTL") {
|
if (config.get('base.language') == "CN") {
|
config.set('base.language', "EN")
|
}
|
} else {
|
// 包括 CN、空文件、读取失败等情况都使用默认语言
|
config.set('base.language', defaultLanguage);
|
}
|
} catch (error) {
|
config.set('base.language', "CN");
|
}
|
config.save()
|
}
|
}
|
|
driver.screen = {
|
accessFail: function () {
|
bus.fire('accessRes', false)
|
},
|
accessSuccess: function () {
|
bus.fire('accessRes', true)
|
},
|
upgrade: function (data) {
|
bus.fire('upgrade', data)
|
},
|
getCard: function (card) {
|
let language = config.get("base.language") || "CN";
|
driver.audio.play(`/app/code/resource/wav/${language}/read.wav`)
|
bus.fire('getCard', card)
|
},
|
hideSn: function (data) {
|
bus.fire('hideSn', data)
|
},
|
appMode: function (data) {
|
bus.fire('appMode', data)
|
},
|
hideIp: function (data) {
|
bus.fire('hideIp', data)
|
},
|
changeLanguage: function () {
|
bus.fire('changeLanguage')
|
},
|
reload: function () {
|
bus.fire('reload')
|
},
|
error: function (msg) {
|
bus.fire('showMessage', { status: false, msg: msg })
|
},
|
success: function (msg) {
|
bus.fire('showMessage', { status: true, msg: msg })
|
},
|
}
|
|
driver.sqlite = {
|
DB_PATH: '/data/db/app.db',
|
init: function () {
|
std.ensurePathExists(driver.sqlite.DB_PATH)
|
sqliteService.init(driver.sqlite.DB_PATH)
|
}
|
}
|
|
driver.pwm = {
|
init: function () {
|
let nirLuminance = config.get("base.nirBrightness")
|
let whiteLuminance = config.get("base.brightness")
|
if (dxDriver.DRIVER.MODEL == "vf203") {
|
pwm.init(dxDriver.PWM.NIR_SUPPLEMENT_CHANNEL);
|
pwm.setPower(nirLuminance, dxDriver.PWM.NIR_SUPPLEMENT_CHANNEL);
|
} else if (dxDriver.DRIVER.MODEL == "vf202" || dxDriver.DRIVER.MODEL == "vf114" || dxDriver.DRIVER.MODEL == "vf105") {
|
pwm.init(dxDriver.PWM.WHITE_SUPPLEMENT_CHANNEL);
|
pwm.init(dxDriver.PWM.NIR_SUPPLEMENT_CHANNEL);
|
pwm.setPower(whiteLuminance, dxDriver.PWM.WHITE_SUPPLEMENT_CHANNEL);
|
pwm.setPower(nirLuminance, dxDriver.PWM.NIR_SUPPLEMENT_CHANNEL);
|
}
|
},
|
setWhitePower: function (whiteLuminance) {
|
pwm.setPower(whiteLuminance, dxDriver.PWM.WHITE_SUPPLEMENT_CHANNEL);
|
},
|
setNirPower: function (nirLuminance) {
|
pwm.setPower(nirLuminance, dxDriver.PWM.NIR_SUPPLEMENT_CHANNEL);
|
}
|
}
|
|
driver.audio = {
|
init: function () {
|
audio.init();
|
audio.setVolume(config.get("base.volume"))
|
},
|
play: function (src) {
|
audio.play(src)
|
},
|
ttsPlay: function (text) {
|
let type = config.get("base.language") == "CN" ? 0 : 1
|
audio.playTxt(text, type)
|
},
|
volume: function (volume) {
|
if (volume === undefined || volume === null) {
|
return audio.getVolume()
|
} else if (volume < 0 || volume > 10) {
|
throw new Error('输入值必须在0到10之间');
|
} else {
|
audio.setVolume(volume)
|
}
|
},
|
interrupt: function () {
|
audio.interrupt()
|
},
|
clearCache: function () {
|
audio.clearCache()
|
}
|
}
|
|
driver.nfc = {
|
NFC_CARD_RECEIVE: "nfcCardReceive",
|
EID_RECEIVE: "eidReceive",
|
init: function () {
|
dxNfcCard.init();
|
},
|
eidInit: function () {
|
try {
|
dxNfcCard.eidInit({ config: {
|
device_model: dxDriver.DRIVER.MODEL
|
} })
|
} catch (error) {
|
logger.error(error)
|
}
|
},
|
eidActive: function (code) {
|
const options = {
|
codeMsg: code,
|
version: config.get("sys.appVersion"),
|
macAddr: config.get("sys.mac")
|
};
|
return dxNfcCard.eidActive(options);
|
},
|
getConfig: function () {
|
return dxNfcCard.getConfig();
|
},
|
setConfig: function (options) {
|
dxNfcCard.updateConfig(options);
|
},
|
setCallbacks: function (callbacks) {
|
dxNfcCard.setCallbacks(callbacks);
|
},
|
loop: function () {
|
dxNfcCard.loop();
|
},
|
}
|
|
|
driver.face = {
|
options: {
|
det_max: 1,
|
liv_threshold: 5,
|
rec_timeout_ms: 5000,
|
det_timeout_ms: 100000,
|
nir: {
|
preview_width: dxDriver.DISPLAY.WIDTH * (120 / 600),
|
preview_height: dxDriver.DISPLAY.HEIGHT * (150 / 1024),
|
preview_top: dxDriver.DISPLAY.HEIGHT * (60 / 1024),
|
}
|
},
|
init: function () {
|
this.options.com_threshold = config.get("face.similarity")
|
this.options.liv_enable = config.get("face.livenessOff")
|
this.options.liv_threshold = config.get("face.livenessVal")
|
this.options.det_timeout_ms = config.get("face.recheck") === 1 ? 8000 : 100000
|
dxFacial.init(this.options);
|
// 默认关闭红外摄像头预览
|
this.capPreviewEnable(config.get("face.showNir"))
|
},
|
capPreviewEnable: function (enable) {
|
dxCamera.capPreviewEnable(1, enable);
|
},
|
getTrackingBox: function () {
|
let data = dxFacial.getDetectionData();
|
// data.push({ "id": 100, "status": 0, "rect": [20, 232, 110, 353], "qualityScore": 30, "livingScore": 0 })
|
// data.push({ "id": 99, "status": 0, "rect": [81, 519, 180, 649], "qualityScore": 30, "livingScore": 0 })
|
// data.push({ "id": 98, "status": 0, "rect": [110, 369, 207, 498], "qualityScore": 30, "livingScore": 0 })
|
// data.push({ "id": 97, "status": 0, "rect": [159, 249, 257, 377], "qualityScore": 30, "livingScore": 0 })
|
// data.push({ "id": 96, "status": 0, "rect": [196, 215, 296, 345], "qualityScore": 30, "livingScore": 0 })
|
// data.push({ "id": 95, "status": 0, "rect": [240, 208, 340, 341], "qualityScore": 30, "livingScore": 0 })
|
// data.push({ "id": 94, "status": 0, "rect": [303, 242, 403, 372], "qualityScore": 30, "livingScore": 0 })
|
// data.push({ "id": 93, "status": 0, "rect": [354, 317, 456, 446], "qualityScore": 30, "livingScore": 0 })
|
// data.push({ "id": 92, "status": 0, "rect": [306, 603, 376, 710], "qualityScore": 30, "livingScore": 0 })
|
return data
|
},
|
status: function (flag) {
|
dxFacial.setStatus(flag);
|
},
|
setCallbacks: function (callbacks) {
|
dxFacial.setCallbacks(callbacks);
|
},
|
loop: function () {
|
dxFacial.loop();
|
},
|
// 配置管理
|
setConfig: function (options) {
|
dxFacial.setConfig(options);
|
},
|
getConfig: function () {
|
return dxFacial.getConfig();
|
},
|
// 特征值管理
|
getFeaByCap: function (timeout) {
|
return dxFacial.getFeaByCap(timeout);
|
},
|
getFeaByFile: function (picPath) {
|
return dxFacial.getFeaByFile(picPath);
|
},
|
addFea: function (userId, feature) {
|
try {
|
let ret = dxFacial.addFea(userId, feature)
|
return ret;
|
} catch (error) {
|
logger.error(error)
|
return error.message;
|
}
|
|
// TODO 这个逻辑很奇怪,异常没有抛上去,必须try catch return
|
// logger.info("addFea start", userId, feature)
|
// let ret = dxFacial.addFea(userId, feature)
|
// logger.info("addFea ret", ret)
|
// return ret;
|
},
|
updateFea: function (userId, feature) {
|
try {
|
return dxFacial.updateFea(userId, feature);
|
} catch (error) {
|
logger.error(error)
|
return error.message;
|
}
|
},
|
clean: function () {
|
return dxFacial.cleanFea()
|
},
|
deleteFea: function (userId) {
|
return dxFacial.deleteFea(userId)
|
},
|
}
|
|
driver.display = {
|
setBacklight: function (backlight) {
|
dxDisplay.setBacklight(backlight)
|
},
|
}
|
|
driver.capcal = {
|
init: function () {
|
dxCapcal.init()
|
},
|
deinit: function () {
|
dxCapcal.deinit()
|
},
|
calculate: function (cnt) {
|
return dxCapcal.calculate(cnt)
|
},
|
getBox: function (cnt) {
|
return dxCapcal.getBox(cnt)
|
}
|
}
|
|
driver.ntp = {
|
init: function () {
|
if (!config.get("ntp.ntp")) {
|
let time = config.get('sys.time')
|
if (time) {
|
this.setTime(time)
|
}
|
} else {
|
ntp.startSync(config.get("ntp.server"))
|
}
|
},
|
setTime: function (timestamp) {
|
ntp.setTime(utils.formatUnixTimestamp(timestamp), true)
|
}
|
}
|
|
driver.uartBle = {
|
init: function () {
|
dxUartBle.init()
|
let bleKey = config.get("sys.bleKey") || "01234567890123456789012345678901"
|
dxUartBle.slave.setConfig(bleKey)
|
},
|
setCallbacks: function (callbacks) {
|
dxUartBle.slave.setCallbacks(callbacks)
|
},
|
loop: function () {
|
dxUartBle.loop()
|
},
|
send: function (data) {
|
let connId = dxMap.get("connId").get("connId")
|
if (connId) {
|
dxUartBle.slave.sendMessage(data, connId)
|
}
|
}
|
}
|
|
driver.uartCode = {
|
RECEIVE_MSG: '__UART_RECEIVE_MSG__',
|
init: function () {
|
if (dxDriver.DRIVER.MODEL == 'vf105') {
|
dxVgCode.init('/dev/ttySLB1', '115200-8-N-1')
|
} else if (dxDriver.DRIVER.MODEL == 'vf114') {
|
dxVgCode.init('/dev/ttySLB3', '115200-8-N-1')
|
}
|
},
|
setCallbacks: function (callbacks) {
|
dxVgCode.setCallbacks(callbacks)
|
},
|
loop: function () {
|
dxVgCode.loop()
|
}
|
}
|
|
driver.sync = {
|
// 异步转同步实现优化
|
request: function (topic, timeout = 2000) {
|
const map = dxMap.get("SYNC");
|
// 并发重复topic丢弃
|
if (map.get(topic)) {
|
logger.error("当前已有相同的topic正在等待,请稍后再试")
|
return;
|
}
|
map.put(topic, "waiting");
|
const interval = 10;
|
const maxCount = Math.ceil(timeout / interval);
|
let count = 0;
|
let data = "waiting";
|
while (count < maxCount) {
|
data = map.get(topic);
|
if (data !== "waiting") break;
|
std.sleep(interval);
|
count++;
|
}
|
// 只有在不是"waiting"时才返回data,否则返回undefined
|
map.del(topic);
|
if (data === "waiting" || data === undefined) {
|
return;
|
}
|
return data;
|
},
|
response: function (topic, data) {
|
const map = dxMap.get("SYNC");
|
// 只有在topic为"waiting"时才允许响应
|
if (map.get(topic) !== "waiting") {
|
logger.error("没有正在等待的topic,禁止回复")
|
return;
|
}
|
map.put(topic, data);
|
}
|
}
|
|
driver.net = {
|
RECONNECT: "__NET_RECONNECT__",
|
SCAN_WIFI: "__NET_SCAN_WIFI__",
|
WIFI_LIST: "__NET_WIFI_LIST__",
|
CONNECTED_CHANGED: "__NET_CONNECTED_CHANGED__",
|
init: () => {
|
bus.newWorker('netWorker', '/app/code/src/worker/netWorker.js')
|
},
|
reconnect: () => {
|
bus.fire(driver.net.RECONNECT)
|
},
|
getNetParam: net.getNetParam,
|
isConnected: net.isConnected,
|
getNetMac: net.getNetMac
|
}
|
|
driver.mqtt = {
|
REINIT: "__MQTT_REINIT__",
|
SEND_MSG: "__MQTT_SEND_MSG__",
|
RECEIVE_MSG: "__MQTT_RECEIVE_MSG__",
|
CONNECTED_CHANGED: "__MQTT_CONNECTED_CHANGED__",
|
RESTART_HEARTBEAT: "__MQTT_RESTART_HEARTBEAT__",
|
init: () => {
|
bus.newWorker('mqttWorker', '/app/code/src/worker/mqttWorker.js')
|
},
|
reinit: () => {
|
// 重连mqtt,针对换了mqtt连接信息时需要执行,没换不用重连
|
bus.fire(driver.mqtt.REINIT)
|
},
|
send: function (topic, payload) {
|
bus.fire(driver.mqtt.SEND_MSG, {
|
topic, payload
|
})
|
},
|
// 修改了心跳相关配置需要重启心跳定时器,调这个
|
restartHeartbeat: () => {
|
bus.fire(driver.mqtt.RESTART_HEARTBEAT)
|
},
|
isConnected: () => {
|
return mqtt.getNative() && mqtt.isConnected()
|
},
|
}
|
|
driver.gpio = {
|
init: function () {
|
gpio.init()
|
gpio.request(dxDriver.GPIO.RELAY0)
|
},
|
/**
|
* 打开继电器
|
* 打开继电器并在指定时间后自动关闭
|
*/
|
open: function () {
|
logger.info("[GPIO]: 打开继电器")
|
let result = gpio.setValue(dxDriver.GPIO.RELAY0, 1);
|
logger.info("[GPIO]: 打开继电器结果: " + result)
|
|
let relayTime = config.get("access.relayTime")
|
// 确保 relayTime 是一个有效的数字,默认为 10 秒
|
if (!relayTime || isNaN(relayTime)) {
|
relayTime = 10
|
} else {
|
relayTime = parseInt(relayTime)
|
}
|
logger.info("[GPIO]: 继电器延时关闭时间: " + relayTime + "秒")
|
|
std.setTimeout(() => {
|
logger.info("[GPIO]: 关闭继电器")
|
let closeResult = gpio.setValue(dxDriver.GPIO.RELAY0, 0);
|
logger.info("[GPIO]: 关闭继电器结果: " + closeResult)
|
}, relayTime * 1000)
|
},
|
/**
|
* 关闭继电器
|
* 立即关闭继电器
|
*/
|
close: function () {
|
gpio.setValue(dxDriver.GPIO.RELAY0, 0)
|
},
|
setValue: function (value) {
|
if (config.get("access.fireStatus") === 0) {
|
gpio.setValue(dxDriver.GPIO.RELAY0, value)
|
}
|
}
|
}
|
|
driver.gpiokey = {
|
RECEIVE_MSG: "__GPIOKEY_RECEIVE_MSG__",
|
TYPE: {
|
DOOR_SENSOR: 0, // 门磁
|
FIRE_ALARM: 1, // 火警
|
TAMPER_ALARM: 2, // 防拆
|
},
|
VALUE: {
|
OPEN: 1, // 开
|
CLOSE: 0, // 关
|
},
|
init: function () {
|
dxGpioKey.init()
|
// 默认需要延续火警的状态
|
if (config.get("access.fire") == 1 && config.get("access.fireStatus") == 1) {
|
std.setTimeout(() => {
|
bus.fire(driver.gpiokey.RECEIVE_MSG, { code: 1, value: 1 })
|
}, 5000)
|
}
|
},
|
sensorChanged: function (type, value) {
|
let prefix = config.get("mqttInfo.prefix") || ''
|
driver.mqtt.send(prefix + "access_device/v2/event/alarm", JSON.stringify(mqttService.mqttReply(std.genRandomStr(10), { type: type, value: value }, mqttService.CODE.S_000)))
|
},
|
loop: function () {
|
dxGpioKey.loop()
|
},
|
setCallbacks: function (callbacks) {
|
dxGpioKey.setCallbacks(callbacks);
|
},
|
statusConfig: function (fire) {
|
config.setAndSave("access.fire", fire)
|
if (fire === 0) {
|
// 从配置上关闭火警时,也需要把火警状态重置
|
config.setAndSave("access.fireStatus", 0)
|
// 关闭继电器
|
driver.gpio.close()
|
}
|
},
|
controlFire: function (fire) {
|
if (config.get("access.fire") == 1) {
|
if (fire == 1) {
|
// 火警触发
|
print('火警触发')
|
driver.gpio.open()
|
// 上报火警状态
|
bus.fire(driver.gpiokey.RECEIVE_MSG, { code: 1, value: 1 })
|
} else {
|
// 火警解除
|
print('火警解除')
|
// 从配置上关闭火警时,也需要把火警状态重置
|
config.setAndSave("access.fireStatus", 0)
|
// 关闭继电器
|
driver.gpio.close()
|
}
|
}
|
}
|
}
|
|
driver.finger = {
|
RECEIVE_MSG: "__FINGER_RECEIVE_MSG__",
|
flag: true,
|
// 指纹模块类型:根据设备型号选择(vf114 -> MZ,其它 -> ZAZ)
|
// 说明:driver.finger 对外统一为“0表示成功、非0表示失败;索引统一使用0-based”
|
_type: null, // 'mz' | 'zaz'
|
_impl: null, // fingerMz | fingerZaz
|
_total: 1024, // 统一对外的最大指纹数量
|
_isZaz: function () {
|
return (dxDriver.DRIVER.MODEL !== "vf114")
|
},
|
_ensureImpl: function () {
|
if (this._impl) return
|
if (this._isZaz()) {
|
this._type = "zaz"
|
this._impl = fingerZaz
|
this._total = 1024
|
} else {
|
this._type = "mz"
|
this._impl = fingerMz
|
this._total = 1024
|
}
|
},
|
_ok: function (bool) {
|
return bool ? 0 : -1
|
},
|
init: function () {
|
this._ensureImpl()
|
let options
|
if (this._type === "zaz") {
|
options = {
|
type: 3,
|
path: '/dev/ttySLB1',
|
baudrate: '115200-8-N-1'
|
}
|
} else {
|
options = {
|
id: 'fingerUart',
|
total: this._total,
|
timeout: 500,
|
type: '3',
|
path: '/dev/ttySLB0', //测试时是ttySLB0 生产时是ttySLB3替换的扫码模组
|
baudrate: '57600-8-N-2'
|
}
|
}
|
this._impl.init(options)
|
const statusMap = dxMap.get("FINGER_STATUS")
|
statusMap.put("status", "start")
|
this.controlLed("BLUE")
|
},
|
loop: function () {
|
const statusMap = dxMap.get("FINGER_STATUS")
|
// 检查是否正在进行指纹录入,如果是,则跳过指纹对比
|
const isFingerEntering = dxMap.get("UI") && dxMap.get("UI").get("isFingerEntering")
|
if(statusMap && statusMap.get("status") == "start" && !isFingerEntering){
|
try {
|
let index = driver.finger.compare(0, 1024)
|
if(index != -1 && index != -2){
|
bus.fire(driver.finger.RECEIVE_MSG, {type: 500, index: index})
|
}
|
} catch (error) {
|
// 指纹对比失败的错误日志可以忽略,因为这是正常的指纹验证失败情况
|
}
|
}
|
},
|
getIndex: function() {
|
this._ensureImpl()
|
if (this._type === "zaz") {
|
const ret = this._impl.getEmptyId(1, this._total)
|
return ret
|
}
|
return this._impl.getIndex()
|
},
|
getEnrollImage: function() {
|
this._ensureImpl()
|
if (this._type === "zaz") {
|
// ZAZ 无 enroll/verify 区分,复用 getImage
|
return this.getImage()
|
}
|
return this._impl.getEnrollImage()
|
},
|
getImage: function () {
|
this._ensureImpl()
|
if (this._type === "zaz") {
|
return this._ok(this._impl.getImage())
|
}
|
return this._impl.getImage()
|
},
|
start: function () {
|
const statusMap = dxMap.get("FINGER_STATUS")
|
statusMap.put("status", "start")
|
},
|
stop: function () {
|
const statusMap = dxMap.get("FINGER_STATUS")
|
statusMap.put("status", "stop")
|
std.sleep(200)
|
},
|
delete: function(fingerId) {
|
return this.deleteChar(fingerId, 1)
|
},
|
genChar: function(bufferId) {
|
try {
|
this._ensureImpl()
|
if (this._type === "zaz") {
|
// 移除多余的打印语句
|
return this._ok(this._impl.generate(bufferId - 1))
|
}
|
return this._impl.genChar(bufferId)
|
} catch (error) {
|
// 只在非录入状态下输出错误日志,避免录入过程中的冗余日志
|
const isFingerEntering = dxMap.get("UI") && dxMap.get("UI").get("isFingerEntering")
|
if (!isFingerEntering) {
|
logger.error("finger.genChar 生成特征失败: ", error.message)
|
}
|
return -1
|
}
|
},
|
regModel: function() {
|
this._ensureImpl()
|
if (this._type === "zaz") {
|
// 这里写死 (3, 0),合并3个特征,并存储到索引0
|
return this._ok(this._impl.merge(3, 0))
|
}
|
return this._impl.regModel()
|
},
|
deleteChar: function(fingerId, num) {
|
this._ensureImpl()
|
if (this._type === "zaz") {
|
return this._ok(this._impl.delChar(fingerId, fingerId))
|
}
|
return this._impl.deletChar(fingerId, num)
|
},
|
upChar: function(bufferId = 1) {
|
this._ensureImpl()
|
if (this._type === "zaz") {
|
const hex = this._impl.upChar(bufferId - 1)
|
if (!hex) return null
|
// 统一返回 Uint8Array/ArrayBuffer 语义,供 common.arrayBufferToHexString 处理
|
return common.hexStringToArrayBuffer(hex)
|
}
|
return this._impl.upChar(bufferId)
|
},
|
loadChar: function(index, bufferId = 1) {
|
this._ensureImpl()
|
if (this._type === "zaz") {
|
return this._ok(this._impl.loadChar(index, bufferId - 1))
|
}
|
return this._impl.loadChar(bufferId, index)
|
},
|
downChar: function(char, bufferId = 1) {
|
this._ensureImpl()
|
if (this._type === "zaz") {
|
// ZAZ 接收 hex string
|
let hex
|
if (typeof char === "string") {
|
hex = char
|
} else if (char instanceof ArrayBuffer) {
|
hex = common.arrayBufferToHexString(char)
|
} else {
|
// Uint8Array / 其它 array-like
|
hex = common.uint8ArrayToHexString(new Uint8Array(char))
|
}
|
return this._ok(this._impl.downChar(bufferId - 1, hex))
|
}
|
// MZ 接收 ArrayBuffer/Uint8Array:如果传入的是 hex string,这里转成 Uint8Array
|
let payload = char
|
if (typeof char === "string") {
|
payload = common.hexStringToUint8Array(char)
|
}
|
return this._impl.downChar(bufferId, payload)
|
},
|
search: function(bufferId, index, num) {
|
this._ensureImpl()
|
if (this._type === "zaz") {
|
const found = this._impl.search(bufferId - 1, 1, 1024)
|
if (found === false || found === null || found === undefined) {
|
return { code: 1, pageIndex: -1, score: 0 }
|
}
|
return { code: 0, pageIndex: found, score: 100 }
|
}
|
return this._impl.search(bufferId, index, num)
|
},
|
storeChar: function(index, bufferId = 1) {
|
this._ensureImpl()
|
if (this._type === "zaz") {
|
// 参数顺序相反:keyId(index) + bufferNum(bufferId)
|
return this._ok(this._impl.storeChar(index, bufferId - 1))
|
}
|
return this._impl.storeChar(bufferId, index)
|
},
|
insert: function(char) {
|
this.stop()
|
print("finger.insert 插入指纹数据: ", char)
|
let res = this.downChar(char, 1)
|
if (res != 0) {
|
return -1
|
}
|
let index = this.getIndex()
|
logger.info("finger.insert 找到的第一个未使用的索引: ", index)
|
res = this.storeChar(index, 1)
|
this.start()
|
return index
|
},
|
clear: function() {
|
this._ensureImpl()
|
if (this._type === "zaz") {
|
return this._ok(this._impl.delChar(1, this._total))
|
}
|
return this._impl.clearChar()
|
},
|
// 指纹对比,返回对比到的索引和得分
|
compare: function(index = 0, num = 0){
|
// 1,发送获取图像指令
|
// 2,生成特征(bufferId默认为1)
|
// 3,指纹搜索(bufferId默认为1)
|
let res = this.getImage()
|
if(res != 0){
|
return -1
|
}
|
res = this.genChar(1)
|
if(res != 0){
|
logger.info("finger.search 生成特征失败!")
|
return -2
|
}
|
res = this.search(1, index, num)
|
if(res != null && res.code != null && res.code == 0){
|
logger.info("搜索到指纹、指纹验证成功、指纹索引:" + res.pageIndex + ",指纹得分: " + res.score)
|
logger.info("finger.search: ", JSON.stringify(res))
|
return res.pageIndex
|
}
|
return -3
|
},
|
controlLed: function (color) {
|
if (driver.device.finger && this._type === "mz") {
|
try {
|
std.sleep(500)
|
fingerMz.controlLed(fingerMz.LED_COLOR[color])
|
} catch (error) {
|
logger.info(error)
|
}
|
}
|
}
|
}
|
|
driver.device = {
|
model: dxDriver.DRIVER.MODEL,
|
// 是否支持指纹(通过 /app/finger 标志文件判断;仅检测一次)
|
finger: (() => {
|
try {
|
return std.exist("/etc/app/finger.conf")
|
} catch (e) {
|
logger.error("检测指纹能力失败: ", e)
|
return false
|
}
|
})(),
|
}
|
|
driver.watchdog = {
|
MAIN_WORKER: 1,
|
CONTROLLER_WORKER: 2,
|
init: function () {
|
watchdog.init()
|
this.enable(this.MAIN_WORKER, true)
|
this.start(30000)
|
},
|
enable: function (channel, enable) {
|
watchdog.enable(channel, enable)
|
},
|
start: function (timeout) {
|
watchdog.start(timeout)
|
},
|
stop: function () {
|
watchdog.stop()
|
},
|
restart: function (channel) {
|
watchdog.restart(channel)
|
},
|
}
|
|
export default driver
|