/**
|
* dxVgCode Module.
|
* - UART based communication for Barcode Scanner device.
|
* - Encapsulates barcode scanner serial communication with a simple API interface.
|
* - Parses barcode scanner protocol frames (55AA...) and provides callback mechanism.
|
*/
|
// import dxChannel from './dxChannel.js'
|
// import dxLogger from './dxLogger.js'
|
// import dxDriver from './dxDriver.js'
|
// import dxMap from './dxMap.js'
|
|
import dxChannel from '../../../dxmodules/dxChannel.js'
|
import dxLogger from '../../../dxmodules/dxLogger.js'
|
import dxDriver from '../../../dxmodules/dxDriver.js'
|
import dxMap from '../../../dxmodules/dxMap.js'
|
|
const dxVgCode = {}
|
|
let handle_id = null
|
|
// Global callback functions
|
let g_callbacks = {
|
onMessage: null // Data reception callback
|
}
|
|
/**
|
* Initialize UART channel and store handle into dxMap (idempotent across threads).
|
* @param {string} options.path Serial port path
|
* @param {string} options.rate Baud rate configuration, e.g., '115200-8-N-1'
|
*/
|
dxVgCode.init = function (path, rate = '115200-8-N-1') {
|
if (!path) {
|
throw new Error("'path' should not be null or empty")
|
}
|
const vgMap = dxMap.get("dxVgCodeMap");
|
const inited = vgMap.get("inited");
|
if (inited === true) {
|
return;
|
}
|
handle_id = dxChannel.open(dxChannel.TYPE.UART, path);
|
dxChannel.ioctl(handle_id, dxChannel.IOC_SET_CMD.CHANNEL_IOC_SET_UART_PARAM, rate);
|
vgMap.put("handle_id", handle_id);
|
vgMap.put("inited", true);
|
}
|
|
/**
|
* Set callback functions
|
* @param {Object} callbacks Callback object
|
* @param {Function} callbacks.onMessage Data reception callback, receives barcode data
|
*/
|
dxVgCode.setCallbacks = function (callbacks) {
|
if (!callbacks || typeof callbacks.onMessage !== 'function') {
|
throw new Error('Callbacks must be an object with onMessage functions');
|
}
|
g_callbacks.onMessage = callbacks.onMessage;
|
}
|
|
/**
|
* Barcode scanner typically uses 55AA protocol frame format
|
*/
|
function processCommonProtocol() {
|
checkHandleId();
|
if (handle_id == null || handle_id == undefined) {
|
return;
|
}
|
|
// Read header (2 bytes)
|
const header = dxChannel.receive(handle_id, 2, 100);
|
if (!header || header.length !== 2) {
|
return;
|
}
|
|
// Check for 0x55 0xAA header
|
if (header[0] !== 85 || header[1] !== 170) {
|
// Not a valid header, ignore this byte sequence
|
return;
|
}
|
|
let pack = {};
|
|
// Read command byte (1 byte)
|
const cmdBuf = dxChannel.receive(handle_id, 1, 100);
|
if (!cmdBuf || cmdBuf.length !== 1) {
|
return;
|
}
|
pack.cmd = cmdBuf[0];
|
|
// Read length bytes (2 bytes, little-endian)
|
const lenBuf = dxChannel.receive(handle_id, 2, 100);
|
if (!lenBuf || lenBuf.length !== 2) {
|
return;
|
}
|
const length = lenBuf[0] | (lenBuf[1] << 8);
|
pack.length = length;
|
|
// Read data field
|
if (length > 0) {
|
const dataBuf = dxChannel.receive(handle_id, length, 500);
|
if (!dataBuf || dataBuf.length !== length) {
|
return;
|
}
|
pack.data = Array.from(dataBuf);
|
}
|
|
// Read BCC checksum (1 byte)
|
const bccBuf = dxChannel.receive(handle_id, 1, 100);
|
if (!bccBuf || bccBuf.length !== 1) {
|
return;
|
}
|
const receivedBcc = bccBuf[0];
|
|
// Calculate and verify BCC
|
const calculatedBcc = calculateBcc(pack.cmd, pack.length, pack.data);
|
if (receivedBcc !== calculatedBcc) {
|
return;
|
}
|
|
pack.bcc = receivedBcc
|
pack.cmd = int2hex(pack.cmd)
|
|
// Call callback function to process data
|
if (typeof g_callbacks.onMessage === 'function') {
|
try {
|
g_callbacks.onMessage(pack);
|
} catch (error) {
|
dxLogger.error('dxVgCode: callback error', error);
|
}
|
}
|
|
return true;
|
}
|
|
/**
|
* Polling handler function, should be called periodically in main loop
|
*/
|
dxVgCode.loop = function () {
|
processCommonProtocol();
|
}
|
|
/**
|
* Calculate BCC checksum
|
* @param {number} cmd Command byte
|
* @param {number} length Data length
|
* @param {Array} data Data array
|
* @returns {number} BCC value
|
*/
|
function calculateBcc(cmd, length, data) {
|
let bcc = 0x55;
|
bcc ^= 0xAA;
|
bcc ^= cmd;
|
bcc ^= (length & 0xFF);
|
bcc ^= ((length >> 8) & 0xFF);
|
|
if (data && data.length) {
|
for (let i = 0; i < data.length; i++) {
|
bcc ^= data[i];
|
}
|
}
|
|
return bcc;
|
}
|
|
/**
|
* Check and get handle ID
|
*/
|
function checkHandleId() {
|
if (handle_id == null || handle_id == undefined) {
|
handle_id = dxMap.get("dxVgCodeMap").get("handle_id");
|
}
|
}
|
|
/**
|
* Convert integer to hex string with 2-digit padding
|
* @param {number} num Integer to convert
|
* @returns {string} Hex string representation
|
*/
|
function int2hex(num) {
|
return num.toString(16).padStart(2, '0');
|
}
|
|
export default dxVgCode;
|