/** * 驱动模块文件 * 包含系统所有硬件驱动的初始化和操作方法,是系统与硬件交互的核心模块 */ import * as os from "os" import capturer from '../dxmodules/dxCapturer.js' import cameraCalibration from '../dxmodules/dxCameraCalibration.js' import face from '../dxmodules/dxFace.js' import std from '../dxmodules/dxStd.js' import common from '../dxmodules/dxCommon.js' import utils from './common/utils/utils.js' import alsa from '../dxmodules/dxAlsa.js' import config from '../dxmodules/dxConfig.js' import pwm from '../dxmodules/dxPwm.js' import net from '../dxmodules/dxNet.js' import ntp from '../dxmodules/dxNtp.js' import mqtt from '../dxmodules/dxMqtt.js' import dxMap from '../dxmodules/dxMap.js' import logger from '../dxmodules/dxLogger.js' import sqliteService from "./service/sqliteService.js" import mqttService from "./service/mqttService.js" import gpio from "../dxmodules/dxGpio.js" import map from "../dxmodules/dxMap.js" import eid from "../dxmodules/dxEid.js" import nfc from "../dxmodules/dxNfc.js" import bus from "../dxmodules/dxEventBus.js" import dxUart from "../dxmodules/dxUart.js" import watchdog from "../dxmodules/dxWatchdog.js" import base64 from "../dxmodules/dxBase64.js" import dxGpioKey from "../dxmodules/dxGpioKey.js" import dxDriver from "../dxmodules/dxDriver.js" const driver = {} /** * 音频驱动模块 * 负责音频播放和语音合成 */ driver.alsa = alsa /** * 配置驱动模块 * 负责初始化系统配置,设置系统基本信息 */ driver.config = { /** * 初始化配置 * 初始化配置模块,设置系统MAC、UUID、SN等基本信息 */ init: function () { config.init() let mac = common.getUuid2mac(19) let uuid = common.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) } config.save() } } /** * 屏幕驱动模块 * 负责屏幕相关的事件触发和操作 */ driver.screen = { /** * 通行失败 * 触发通行失败事件 */ accessFail: function () { bus.fire('accessRes', false) }, /** * 通行成功 * 触发通行成功事件 */ accessSuccess: function () { bus.fire('accessRes', true) }, /** * 升级 * 触发升级事件 * @param {object} data - 升级数据 */ upgrade: function (data) { bus.fire('upgrade', data) }, /** * 获取卡片 * 播放读卡声音并触发获取卡片事件 * @param {string} card - 卡片信息 */ getCard: function (card) { driver.alsa.play(`/app/code/resource/${config.get("base.language") == "CN" ? "CN" : "EN"}/wav/read.wav`) bus.fire('getCard', card) }, /** * 隐藏SN * 触发隐藏SN事件 * @param {object} data - 事件数据 */ hideSn: function (data) { bus.fire('hideSn', data) }, /** * 应用模式 * 触发应用模式事件 * @param {object} data - 模式数据 */ appMode: function (data) { bus.fire('appMode', data) }, /** * 隐藏IP * 触发隐藏IP事件 * @param {object} data - 事件数据 */ hideIp: function (data) { bus.fire('hideIp', data) }, /** * 切换语言 * 触发语言切换事件 */ changeLanguage: function () { bus.fire('changeLanguage') } } /** * SQLite驱动模块 * 负责数据库初始化和管理 */ driver.sqlite = { /** * 初始化数据库 * 确保数据库路径存在并初始化SQLite服务 */ init: function () { std.ensurePathExists('/app/data/db/app.db') sqliteService.init('/app/data/db/app.db') } } /** * PWM驱动模块 * 负责控制补光灯的亮度 */ driver.pwm = { /** * 初始化PWM * 初始化白色补光灯和红外补光灯的PWM通道 */ init: function () { // 白灯 let luminanceWhite = config.get('base.luminanceWhite') ?? 80 pwm.request(dxDriver.PWM.WHITE_SUPPLEMENT_CHANNEL); pwm.setPeriodByChannel(dxDriver.PWM.WHITE_SUPPLEMENT_CHANNEL, dxDriver.PWM.WHITE_SUPPLEMENT_PERIOD_NS) pwm.enable(dxDriver.PWM.WHITE_SUPPLEMENT_CHANNEL, true); pwm.setDutyByChannel(dxDriver.PWM.WHITE_SUPPLEMENT_CHANNEL, dxDriver.PWM.WHITE_SUPPLEMENT_PERIOD_NS - (dxDriver.PWM.WHITE_SUPPLEMENT_PERIOD_NS * (luminanceWhite / 100))) // 红外 let luminanceNir = config.get('base.luminanceNir') ?? 80 pwm.request(dxDriver.PWM.NIR_SUPPLEMENT_CHANNEL); pwm.setPeriodByChannel(dxDriver.PWM.NIR_SUPPLEMENT_CHANNEL, dxDriver.PWM.NIR_SUPPLEMENT_PERIOD_NS) pwm.enable(dxDriver.PWM.NIR_SUPPLEMENT_CHANNEL, true); pwm.setDutyByChannel(dxDriver.PWM.NIR_SUPPLEMENT_CHANNEL, dxDriver.PWM.NIR_SUPPLEMENT_PERIOD_NS - (dxDriver.PWM.NIR_SUPPLEMENT_PERIOD_NS * (luminanceNir / 100))) }, /** * 调节白色补光灯亮度 * @param {number} value - 亮度值,范围0-100 */ luminanceWhite: function (value) { if (value < 0 || value > 100) { logger.error("[driver.pwm]: value should be between 0 and 100") return } pwm.setDutyByChannel(dxDriver.PWM.WHITE_SUPPLEMENT_CHANNEL, dxDriver.PWM.WHITE_SUPPLEMENT_PERIOD_NS - (dxDriver.PWM.WHITE_SUPPLEMENT_PERIOD_NS * (value / 100))) }, /** * 调节红外补光灯亮度 * @param {number} value - 亮度值,范围0-100 */ luminanceNir: function (value) { if (value < 0 || value > 100) { logger.error("[driver.pwm]: value should be between 0 and 100") return } pwm.setDutyByChannel(dxDriver.PWM.NIR_SUPPLEMENT_CHANNEL, dxDriver.PWM.NIR_SUPPLEMENT_PERIOD_NS - (dxDriver.PWM.NIR_SUPPLEMENT_PERIOD_NS * (value / 100))) } } /** * ALSA驱动模块 * 负责音频播放和音量控制 */ driver.alsa = { /** * 初始化音频 * 初始化ALSA音频模块并设置音量 */ init: function () { alsa.init() this.volume(config.get("base.volume")) }, /** * 播放音频文件 * @param {string} src - 音频文件路径 */ play: function (src) { alsa.play(src) }, /** * 文本转语音播放 * @param {string} text - 要播放的文本 */ ttsPlay: function (text) { alsa.ttsPlay(text) }, /** * 获取或设置音量 * @param {number} [volume] - 音量值,范围1-100 * @returns {number} 当前音量值(当未提供参数时) */ volume: function (volume) { if (volume === undefined || volume === null) { return alsa.getVolume() } else { function mapScore(input) { // 确保输入值在1-100之间 if (input < 1 || input > 100) { throw new Error('输入值必须在1到100之间'); } if (input < 60 && input > 30) { input = input * 1.2 } if (input < 30 && input > 1) { input = input * 2 } return input } alsa.setVolume(mapScore(volume)) } } } /** * 摄像头驱动模块 * 负责摄像头的初始化和操作,包括彩色摄像头和红外摄像头 */ driver.capturer = { /** * 彩色摄像头配置 */ options1: { id: "rgb", path: dxDriver.CAPTURER.RGB_PATH, width: dxDriver.CAPTURER.RGB_WIDTH, height: dxDriver.CAPTURER.RGB_HEIGHT, preview_width: dxDriver.CAPTURER.RGB_HEIGHT, preview_height: dxDriver.CAPTURER.RGB_WIDTH, preview_mode: 2, preview_screen_index: 0 // 先后顺序,数字越大越在前面 }, /** * 红外摄像头配置 */ options2: { id: "nir", path: dxDriver.CAPTURER.NIR_PATH, width: dxDriver.CAPTURER.NIR_WIDTH, height: dxDriver.CAPTURER.NIR_HEIGHT, preview_width: 150, preview_height: 200, preview_mode: 1, preview_left: 605, preview_top: 80, preview_screen_index: 1 // 先后顺序,数字越大越在前面 }, /** * 初始化摄像头 * 初始化彩色摄像头和红外摄像头 */ init: function () { capturer.worker.beforeLoop(this.options1) capturer.worker.beforeLoop(this.options2) this.showNir(config.get("face.showNir")) }, /** * 显示或隐藏红外摄像头预览 * @param {boolean} enable - 是否启用红外摄像头预览 */ showNir: function (enable) { capturer.capturerEnable(enable, this.options2.id) }, /** * 将图片数据转换为图像 * @param {string} base64Data - Base64编码的图片数据 * @returns {number} 图像ID */ pictureDataToImage: function (base64Data) { return capturer.pictureDataToImage(base64Data, base64Data.length, 1) }, /** * 将图像保存为文件 * @param {number} imageId - 图像ID * @param {string} savePath - 保存路径 * @returns {boolean} 是否保存成功 */ imageToPictureFile: function (imageId, savePath) { return capturer.imageToPictureFile(imageId, 1, 0, 24, savePath) }, /** * 将图像保存为文件(高质量) * @param {number} imageId - 图像ID * @param {string} savePath - 保存路径 * @returns {boolean} 是否保存成功 */ imageToPictureFile2: function (imageId, savePath) { return capturer.imageToPictureFile(imageId, 1, 0, 100, savePath) }, /** * 调整图像分辨率 * @param {number} imageId - 图像ID * @param {number} width - 目标宽度 * @param {number} height - 目标高度 * @returns {number} 调整后的图像ID */ imageResizeResolution: function (imageId, width, height) { return capturer.imageResizeResolution(imageId, width, height, 0) }, /** * 摄像头循环 * 执行摄像头的循环操作 */ loop: function () { capturer.worker.loop(this.options1) capturer.worker.loop(this.options2) } } /** * NFC驱动模块 * 负责NFC卡片的读取和处理 */ driver.nfc = { /** * NFC配置选项 */ options: { m1: true, psam: false }, /** * 初始化NFC * 初始化NFC模块,根据配置决定是否启用 */ init: function () { if (!config.get('sys.nfc')) { logger.debug("刷卡已关闭") return } this.options.useEid = config.get("sys.nfcIdentityCardEnable") == 3 ? 1 : 0 nfc.worker.beforeLoop(this.options) }, /** * 初始化EID(电子身份证) * 更新EID配置 */ eidInit: function () { if (!config.get('sys.nfc')) { return } if (config.get("sys.nfcIdentityCardEnable") == 3) { nfc.eidUpdateConfig({ appid: "1621503", sn: config.get("sys.sn"), device_model: config.get("sys.appVersion") }) } }, /** * NFC循环 * 执行NFC的循环操作,根据配置决定是否启用 */ loop: function () { if (!config.get('sys.nfc')) { this.loop = () => { } } else { this.loop = () => nfc.worker.loop(this.options) } } } /** * 人脸识别驱动模块 * 负责人脸识别、注册和相关功能的管理 */ driver.face = { /** * 初始化人脸识别 * 初始化人脸模块,设置相关参数和配置 */ init: function () { common.systemBrief('mkdir -p /app/data/user/temp/') let options = { dbPath: "/app/data/db/face.db", rgbPath: "/dev/video3", nirPath: "/dev/video0", capturerRgbId: "rgb", capturerNirId: "nir", dbMax: 5000, //人脸注册上限 score: config.get("face.similarity"), picPath: "/app/data/user/temp", gThumbnailHeight: 1280 / 6, gThumbnailWidth: 800 / 6, // 是否开启重检 recgFaceattrEnable: 1, // 活体开关 livingCheckEnable: config.get("face.livenessOff"), // 活体检测阈值 livingScore: config.get("face.livenessVal"), // 口罩检测开关 detectMaskEnable: config.get("face.detectMask"), // 重检间隔 recheckIntervalTime: 5000, // 检测超时 detectTimeoutTime: 1000 } face.worker.beforeLoop(options) // 默认为人脸识别模式 this.mode(0) // 关闭所有人脸功能 this.status(false) // 屏幕亮度 this.setDisplayBacklight(config.get("base.brightness")) this.screenStatus(1) // 补光灯状态跟踪 let isLightOn = true // 屏幕亮度自动调节 std.setInterval(() => { // 熄屏判断 let screenOff = map.get("screenOff") if (screenOff.get("status") == 1) { this.setDisplayBacklight(0) this.screenStatus(0) // 关闭补光灯(仅当补光灯当前是开启状态时) if (isLightOn) { driver.pwm.luminanceWhite(0) driver.pwm.luminanceNir(0) logger.info("[driver.face]: 熄屏,关闭补光灯") isLightOn = false } } // 停止熄屏 if (screenOff.get("status") != 1) { if (config.get("base.brightnessAuto") == 1) { // 自动调节屏幕亮度 let brightness = Math.floor(face.getEnvBrightness() / 10) brightness = brightness > 100 ? 100 : brightness this.setDisplayBacklight(brightness) } else { this.setDisplayBacklight(config.get("base.brightness")) } // 开启补光灯(仅当补光灯当前是关闭状态时) if (!isLightOn) { let luminanceWhite = config.get('base.luminanceWhite') ?? 80 let luminanceNir = config.get('base.luminanceNir') ?? 80 driver.pwm.luminanceWhite(luminanceWhite) driver.pwm.luminanceNir(luminanceNir) logger.info(`[driver.face]: 退出熄屏,开启补光灯(白灯: ${luminanceWhite}%, 红外: ${luminanceNir}%)`) isLightOn = true } } }, 1000) }, /** * 获取人脸跟踪框 * @returns {object} 跟踪框信息 */ getTrackingBox: function () { return face.getTrackingBox() }, /** * 人脸识别循环 * 执行人脸识别的循环操作 */ loop: function () { // 检查屏幕是否处于熄屏状态 let screenOff = map.get("screenOff") if (screenOff && screenOff.get("status") == 1) { // 熄屏状态下不进行人脸识别 return } face.worker.loop() }, /** * 人脸线程启用开关 * @param {boolean} flag - 是否启用人脸检测 */ status: function (flag) { console.log('---人脸检测' + (flag ? '开启' : '暂停') + '---'); face.faceSetEnable(flag) }, /** * 设置人脸识别模式 * @param {number} value - 模式值,0为识别模式,1为注册模式 */ mode: function (value) { console.log('---人脸' + (value ? '注册' : '识别') + '模式---'); face.setRecgMode(value) }, /** * 人脸注册 * @param {string} id - 用户ID * @param {string} feature - 人脸特征 * @returns {boolean} 是否注册成功 */ reg: function (id, feature) { return face.addFaceFeatures(id, feature); }, /** * 更新人脸配置 * @param {object} options - 配置选项 */ faceUpdateConfig: function (options) { console.log("更新人脸配置", JSON.stringify(options)); face.faceUpdateConfig(options) }, /** * 设置屏幕亮度 * @param {number} brightness - 亮度值 */ setDisplayBacklight: function (brightness) { brightness = brightness < 2 ? 2 : brightness face.setDisplayBacklight(brightness) }, /** * 通过图片文件注册人脸 * @param {string} userId - 用户ID * @param {string} picPath - 图片路径 * @returns {boolean} 是否注册成功 */ registerFaceByPicFile: function (userId, picPath) { return face.registerFaceByPicFile(userId, picPath) }, /** * 清空人脸数据 * @returns {boolean} 是否清空成功 */ clean: function () { // 清空人脸,需要在初始化人脸组件之前才能执行,否则报错 face.faceFeaturesClean() common.systemBrief("rm -rf /app/data/db/face.db") return !std.exist("/app/data/db/face.db") }, /** * 删除指定用户的人脸数据 * @param {string} userId - 用户ID * @returns {boolean} 是否删除成功 */ delete: function (userId) { return face.deleteFaceFeatures(userId) }, /** * 设置屏幕状态 * @param {boolean} status - 是否启用屏幕 */ screenStatus: function (status) { if (status) { face.setPowerMode(0) } else { face.setPowerMode(1) } face.setEnableStatus(status) }, /** * 将文件转换为base64编码 * @param {string} filePath - 文件路径 * @returns {string} Base64编码的文件内容 */ fileToBase64: function (filePath) { function fileToUint8Array(filename) { // 读取文件 const file = std.open(filename, "rb"); if (!file) { throw new Error("无法打开文件"); } // 获取文件大小 const size = std.seek(file, 0, std.SEEK_END) std.seek(file, 0, std.SEEK_SET) // 检查文件大小是否有效 if (size <= 0) { std.close(file); throw new Error("文件大小无效"); } // 创建 ArrayBuffer 并读取文件内容 const buffer = new ArrayBuffer(size); const array = new Uint8Array(buffer); std.read(file, array.buffer, 0, size); std.close(file); return array; } try { // 检查文件路径是否存在 if (!filePath) { throw new Error("文件路径为空"); } const data = fileToUint8Array(filePath); return base64.fromUint8Array(data); } catch (error) { logger.info("文件转Base64失败: " + error.message); return ""; } } } /** * 网络驱动模块 * 负责网络连接和管理 */ driver.net = { /** * 初始化网络 * 初始化网络模块,设置网络配置 */ init: function () { let dns = config.get("net.dns").split(",") let option = { type: config.get("net.type"), dhcp: config.get("net.dhcp"), ip: config.get("net.ip"), gateway: config.get("net.gateway"), netmask: config.get("net.mask"), dns0: dns[0], dns1: dns[1], macAddr: common.getUuid2mac() } logger.info("更新联网配置:", JSON.stringify(option)); net.worker.beforeLoop(option) config.set("net.mac", common.getUuid2mac()) if (config.get("net.type") == 2) { //wifi取配置文件去连接 let ssid = utils.isEmpty(config.get('net.ssid')) ? "ssid" : config.get('net.ssid') let psk = utils.isEmpty(config.get('net.psk')) ? "psk" : config.get('net.psk') driver.net.netConnectWifiSsid(ssid, psk) } // 解决网络切换状态不对 std.setInterval(() => { let status = net.getStatus() if (status.status != map.get("NET").get("status")) { status.type = config.get("net.type") bus.fire(net.STATUS_CHANGE, status) } }, 1000) }, /** * 切换网络类型 * 切换网络类型并配置相应的网络参数 */ changeNetType: function () { // 加锁 if (map.get("NET").get("changeType") == "Y") { return } map.get("NET").put("changeType", "Y") let type = config.get("net.type") logger.info("切换网络", type); [1, 2, 4].filter(v => v != type).forEach(v => { logger.info("关闭网卡", v, net.cardEnable(v, false)); }) logger.info("设置主网卡", type, net.setMasterCard(type)); logger.info("开启网卡", type, net.cardEnable(type, true)); if (type == 2) { //wifi取配置文件去连接 let ssid = utils.isEmpty(config.get('net.ssid')) ? "ssid" : config.get('net.ssid') let psk = utils.isEmpty(config.get('net.psk')) ? "psk" : config.get('net.psk') logger.info("连接wifi", ssid, psk); net.netConnectWifiSsid(ssid, psk) // 等待WiFi连接成功后再设置网络模式 std.setTimeout(() => { let dns = config.get("net.dns").split(",") net.setModeByCard(type, config.get("net.dhcp"), config.get("net.dhcp") == 1 ? { ip: config.get("net.ip"), gateway: config.get("net.gateway"), netmask: config.get("net.mask"), dns0: dns[0], dns1: dns[1], } : undefined) }, 3000); // 等待3秒让WiFi连接成功 } else if (type == 1) { // 以太网直接设置网络模式 let dns = config.get("net.dns").split(",") net.setModeByCard(type, config.get("net.dhcp"), config.get("net.dhcp") == 1 ? { ip: config.get("net.ip"), gateway: config.get("net.gateway"), netmask: config.get("net.mask"), dns0: dns[0], dns1: dns[1], } : undefined) } map.get("NET").del("changeType") }, /** * 初始化EID网络 * 退出网络并重启相关服务 */ eidInit: function () { net.exit(); common.systemWithRes(`pkill -9 -f 'wpa_supplicant|udhcpc'`, 5) }, /** * 获取网络状态 * @returns {boolean} 是否连接成功 */ getStatus: function () { let status = net.getStatus() if (status.connected == true && status.status == 4) { return true } else { return false } }, /** * 连接WiFi * @param {string} ssid - WiFi名称 * @param {string} psk - WiFi密码 */ netConnectWifiSsid: function (ssid, psk) { net.netConnectWifiSsid(ssid, psk, "") }, /** * 获取WiFi列表 * @returns {array} WiFi列表 */ netGetWifiSsidList: function () { if (!driver.net.getStatus()) { //如果 wifi 连接失败 获取列表会失败需要先销毁 net.netDisconnetWifi() } let result = net.netGetWifiSsidList(1000, 5) if (!result || !result.results || result.results.length === 0) { return []; } let wifiList = []; // 初始化wifiList为数组 result.results.forEach(element => wifiList.push(element.ssid)); // 使用push方法添加ssid到数组 return wifiList; }, /** * 重置网卡 */ cardReset: function () { // net.netCardReset(2,1) }, /** * 网络循环 * 执行网络的循环操作 */ loop: function () { net.worker.loop() } } /** * NTP驱动模块 * 负责网络时间同步 */ driver.ntp = { /** * NTP循环 * 初始化NTP模块并执行时间同步操作 */ loop: function () { // 每秒钟判断时间,如果时差大于2秒则进行了对时 let last = new Date().getTime() dxMap.get("NTP_SYNC").put("syncTime", last) std.setInterval(() => { let now = new Date().getTime() let diff = now - last if (diff > 2000) { dxMap.get("NTP_SYNC").put("syncTime", now) last = now } }, 1000) ntp.beforeLoop(config.get("ntp.server"), 9999999999999) this.ntpHour = config.get('ntp.hour') this.flag = true driver.ntp.loop = () => { if (config.get("ntp.ntp")) { ntp.loop() if (new Date().getHours() == this.ntpHour && this.flag) { // 定时同步,立即同步一次时间 ntp.syncnow = true this.flag = false } if (new Date().getHours() != this.ntpHour) { // 等过了这个小时再次允许对时 this.flag = true } } } } } /** * 同步驱动模块 * 提供异步转同步的实现 */ driver.sync = { /** * 异步转同步请求 * @param {string} topic - 主题 * @param {number} timeout - 超时时间(毫秒) * @returns {any} 响应数据 */ request: function (topic, timeout) { let map = dxMap.get("SYNC") let count = 0 let data = map.get(topic) while (utils.isEmpty(data) && count * 10 < timeout) { data = map.get(topic) std.sleep(10) count += 1 } let res = map.get(topic) map.del(topic) return res }, /** * 同步响应 * @param {string} topic - 主题 * @param {any} data - 响应数据 */ response: function (topic, data) { let map = dxMap.get("SYNC") map.put(topic, data) } } /** * MQTT驱动模块 * 负责MQTT通信和消息处理 */ driver.mqtt = { /** * 初始化MQTT * 初始化MQTT模块,设置连接参数 */ init: function () { mqtt.run({ mqttAddr: config.get("mqtt.addr"), clientId: config.get('mqtt.clientId'), subs: mqttService.getTopics(), username: config.get("mqtt.username"), password: config.get("mqtt.password"), qos: config.get("mqtt.qos"), willTopic: config.get("mqtt.willTopic"), willMessage: JSON.stringify({ "uuid": config.get("sys.uuid") }) }) }, /** * 初始化EID的MQTT * 销毁MQTT连接 */ eidInit: function () { mqtt.destroy() }, /** * 发送MQTT消息 * @param {string} topic - 消息主题 * @param {any} payload - 消息载荷 */ send: function (topic, payload,) { logger.info("[driver.mqtt] send :", topic) mqtt.send(topic, payload) }, /** * 获取在线检查 * @returns {any} 在线检查结果 */ getOnlinecheck: function () { let timeout = config.get("mqtt.timeout") timeout = utils.isEmpty(timeout) ? 2000 : timeout return driver.sync.request("mqtt.getOnlinecheck", timeout) }, /** * 在线检查回复 * @param {any} data - 回复数据 */ getOnlinecheckReply: function (data) { driver.sync.response("mqtt.getOnlinecheck", data) }, /** * 获取MQTT连接状态 * @returns {boolean} 是否连接成功 */ getStatus: function () { return mqtt.isConnected() }, /** * MQTT心跳 * 发送心跳消息,保持连接 */ heartbeat: function () { if (utils.isEmpty(this.heart_en)) { let heart_en = config.get('sys.heart_en') this.heart_en = utils.isEmpty(heart_en) ? 0 : heart_en let heart_time = config.get('sys.heart_time') this.heart_time = utils.isEmpty(heart_time) ? 30 : heart_time < 30 ? 30 : heart_time } if (utils.isEmpty(this.lastHeartbeat)) { this.lastHeartbeat = 0 } if (this.heart_en === 1 && (new Date().getTime() - this.lastHeartbeat >= (this.heart_time * 1000))) { this.lastHeartbeat = new Date().getTime() driver.mqtt.send("access_device/v2/event/heartbeat", JSON.stringify(mqttService.mqttReply(std.genRandomStr(10), undefined, mqttService.CODE.S_000))) } } } /** * GPIO驱动模块 * 负责GPIO设备的控制,主要是继电器控制 */ driver.gpio = { /** * 初始化GPIO * 初始化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") std.setTimeout(() => { logger.info("[GPIO]: 关闭继电器") let closeResult = gpio.setValue(dxDriver.GPIO.RELAY0, 0); logger.info("[GPIO]: 关闭继电器结果: " + closeResult) }, relayTime) }, /** * 关闭继电器 * 立即关闭继电器 */ close: function () { gpio.setValue(dxDriver.GPIO.RELAY0, 0) } } /** * UART485驱动模块 * 负责UART485通信 */ driver.uart485 = { /** * UART485 ID */ id: 'uart485', /** * 初始化UART485 * 初始化UART485模块并设置通信参数 */ init: function () { dxUart.runvg({ id: this.id, type: dxUart.TYPE.UART, path: '/dev/ttySLB2', result: 0, passThrough: false }) std.sleep(2000) dxUart.ioctl(6, '115200-8-N-1', this.id) }, /** * 控制UART485 * @param {string} data - 控制数据 */ ioctl: function (data) { dxUart.ioctl(6, data, this.id) }, /** * 发送数据 * @param {string} data - 要发送的数据 */ send: function (data) { dxUart.send(data, this.id) }, /** * 发送VG数据 * @param {object|string} data - 要发送的数据 */ sendVg: function (data) { if (typeof data == 'object') { data.length = data.length ? data.length : (data.data ? data.data.length / 2 : 0) } dxUart.sendVg(data, this.id) } } /** * UARTCode驱动模块 * 负责UART条码扫描通信 */ driver.uartCode = { /** * UARTCode ID */ id: 'uartCode', /** * 初始化UARTCode * 初始化UARTCode模块并设置通信参数 */ init: function () { dxUart.runvg({ id: this.id, type: dxUart.TYPE.UART, path: '/dev/ttySLB1', result: 0, passThrough: false }) std.sleep(500) dxUart.ioctl(6, '115200-8-N-1', this.id) }, /** * 控制UARTCode * @param {string} data - 控制数据 */ ioctl: function (data) { dxUart.ioctl(6, data, this.id) }, /** * 发送数据 * @param {string} data - 要发送的数据 */ send: function (data) { dxUart.send(data, this.id) }, /** * 发送VG数据 * @param {object|string} data - 要发送的数据 */ sendVg: function (data) { if (typeof data == 'object') { data.length = data.length ? data.length : (data.data ? data.data.length / 2 : 0) } dxUart.sendVg(data, this.id) }, } /** * EID驱动模块 * 负责电子身份证相关操作 */ driver.eid = { /** * EID ID */ id: "eid", /** * 激活EID * @param {string} sn - 设备SN * @param {string} version - 版本号 * @param {string} mac - MAC地址 * @param {string} codeMsg - 激活码 * @returns {boolean} 是否激活成功 */ active: function (sn, version, mac, codeMsg) { return eid.active(sn, version, mac, codeMsg) }, /** * 获取EID版本 * @returns {string} EID版本 */ getVerion: function () { return eid.getVersion() } } /** * GPIO按键驱动模块 * 负责GPIO按键的初始化和循环处理 */ driver.gpiokey = { /** * 初始化GPIO按键 * 初始化GPIO按键模块 */ init: function () { dxGpioKey.worker.beforeLoop() }, /** * GPIO按键循环 * 执行GPIO按键的循环操作 */ loop: function () { dxGpioKey.worker.loop() }, } /** * 看门狗驱动模块 * 负责系统看门狗的初始化和喂狗操作 */ driver.watchdog = { /** * 初始化看门狗 * 初始化看门狗模块 */ init: function () { // watchdog.open(1) // watchdog.enable(1) // watchdog.start(20000) }, /** * 看门狗循环 * 执行看门狗的循环操作 */ loop: function () { // watchdog.loop(1) }, /** * 喂狗 * 向看门狗发送喂狗信号,防止系统重启 * @param {string} flag - 喂狗标志 * @param {number} timeout - 超时时间 */ feed: function (flag, timeout) { // if (utils.isEmpty(this["feedTime" + flag]) || new Date().getTime() - this["feedTime" + flag] > 2000) { // // 降低喂狗频率,间隔2秒喂一次 // this["feedTime" + flag] = new Date().getTime() // watchdog.feed(flag, timeout) // } } } /** * 自动重启驱动模块 * 负责系统的自动重启功能 */ driver.autoRestart = { /** * 上次重启检查的小时数 */ lastRestartCheck: new Date().getHours(), // 初始化为当前小时数,而不是0 /** * 初始化自动重启 * 初始化自动重启模块,设置定时重启功能 */ init: function () { // std.setInterval(() => { // 检查是否需要整点重启 // const now = new Date() // const currentHour = now.getHours() // // 只有当小时数等于设定值,且不是上次检查过的小时时才执行 // if (currentHour === 3 && currentHour !== this.lastRestartCheck && now.getMinutes() === 0) { // common.systemBrief('reboot') // } // // 更新上次检查的小时数 // this.lastRestartCheck = currentHour // }, 60000) } } export default driver