/**
|
* 驱动模块文件
|
* 包含系统所有硬件驱动的初始化和操作方法,是系统与硬件交互的核心模块
|
*/
|
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
|