ljswitchboard-modbus_map
Version:
Library that allows easy parsing of the LabJack modbus map
482 lines (436 loc) • 13.2 kB
JavaScript
/**
* Logic for interfacing with the driver / register constants and config.
*
* Logic for parsing and re-indexing the LJM json file to increase access speed
* to register, static driver, and configuration information. This module
* provides access to objects that have re-indexed the constants file by address
* (number) and name (string).
*
* @author Chris Johnson (ChrisJohn404)
*/
var fs = require('fs'); //Load File System module
var os = require('os'); //Load OS module
var path = require('path');
var ljmmm_parse = require('ljmmm-parse');
var driver_const = require('ljswitchboard-ljm_driver_constants');
var array_registers = require('./array_registers').arrayRegisters;
var buffer_registers = require('./buffer_registers').bufferRegisters;
// Important constants:
// console.log(os.hostname());
// console.log(os.type());
// console.log(os.platform());
// console.log(os.arch());
// console.log(os.release());
var LJM_JSON_FILE_LOCATION;
var LJ_TEMPORARY_FILE_LOCATION;
if (process.platform === 'win32') {
var tFileModernPath = process.env.ALLUSERSPROFILE + '\\LabJack\\K3';
var tFileXPPath = process.env.ALLUSERSPROFILE + '\\Application Data\\LabJack\\K3';
var modernPath = process.env.ALLUSERSPROFILE + '\\LabJack\\LJM\\ljm_constants.json';
var xpPath = process.env.ALLUSERSPROFILE + '\\Application Data\\LabJack\\LJM\\ljm_constants.json';
var filePath = fs.existsSync(modernPath);
if (filePath) {
LJM_JSON_FILE_LOCATION = modernPath;
LJ_TEMPORARY_FILE_LOCATION = tFileModernPath;
}
else {
LJM_JSON_FILE_LOCATION = xpPath;
LJ_TEMPORARY_FILE_LOCATION = tFileXPPath;
}
} else {
LJM_JSON_FILE_LOCATION = '/usr/local/share/LabJack/LJM/ljm_constants.json';
LJ_TEMPORARY_FILE_LOCATION = '/usr/local/share/LabJack/K3';
}
var PARSE_BETA_REGISTERS = true;
var typeSizes = {
UINT64: 8,
INT32: 4,
STRING: 50,
UINT16: 2,
BYTE: 1,
UINT32: 4,
FLOAT32: 4
};
/**
* Error-reporting mechanism.
* @param {string/number} description error-description
*/
function JSONParsingError(description) {
this.description = description;
}
function zipArraysToObject(keys, values) {
var retObj = {};
var numKeys = keys.length;
for (var i=0; i<numKeys; i++) {
retObj[keys[i]] = values[i];
}
return retObj;
}
function extendBufferRegisters(constants) {
};
var retDict;
var retDictName;
var expandedConstants = [];
var minifiedConstants = [];
//Function that re-indexes the .json File Constants by their register
function reindexConstantsByRegister(constants) {
var numConstantsEntries = constants.length;
expandedConstants = [];
minifiedConstants = [];
var expandedBetaRegisters = [];
var entry;
var regAddresses;
var regNames;
constants.registers.forEach(function(reg){
minifiedConstants.push(reg);
});
constants.registers_beta.forEach(function(reg){
minifiedConstants.push(reg);
});
// get registers list
expandedConstants = ljmmm_parse.expandLJMMMEntriesSync(constants.registers);
// get beta_registers
expandedBetaRegisters = ljmmm_parse.expandLJMMMEntriesSync(constants.registers_beta);
// combine beta registers into normal register list
expandedBetaRegisters.forEach(function(betaRegister){
expandedConstants.push(betaRegister);
});
regAddresses = expandedConstants.map(function (e) { return parseInt(e.address);});
regNames = expandedConstants.map(function (e) { return e.name; });
retDict = zipArraysToObject(regAddresses, expandedConstants);
retDictName = zipArraysToObject(regNames, expandedConstants);
//Add Extra Special Registers that don't live in the json file
retDict[driver_const.T7_MA_EXF_KEY] = {
address:driver_const.T7_MA_EXF_KEY,
name:"T7_MA_EXF_KEY",
type:"UINT32",
devices:["T7", "T4"],
readwrite:"RW"
};
retDict[driver_const.T7_MA_EXF_WRITE] = {
address:driver_const.T7_MA_EXF_WRITE,
name:"T7_MA_EXF_WRITE",
type:"UINT32",
devices:["T7", "T4"],
readwrite:"RW"
};
retDict[driver_const.T7_MA_EXF_pWRITE] = {
address:driver_const.T7_MA_EXF_pWRITE,
name:"T7_MA_EXF_pWRITE",
type:"UINT32",
devices:["T7", "T4"],
readwrite:"RW"
};
retDict[driver_const.T7_MA_EXF_READ] = {
address:driver_const.T7_MA_EXF_READ,
name:"T7_MA_EXF_READ",
type:"UINT32",
devices:["T7", "T4"],
readwrite:"RW"
};
retDict[driver_const.T7_MA_EXF_pREAD] = {
address:driver_const.T7_MA_EXF_pREAD,
name:"T7_MA_EXF_pREAD",
type:"UINT32",
devices:["T7", "T4"],
readwrite:"RW"
};
retDict[driver_const.T7_MA_EXF_ERASE] = {
address:driver_const.T7_MA_EXF_ERASE,
name:"T7_MA_EXF_ERASE",
type:"UINT32",
devices:["T7", "T4"],
readwrite:"RW"
};
retDict[driver_const.T7_FLASH_CHIP_VERSION] = {
address:driver_const.T7_FLASH_CHIP_VERSION,
name:"T7_FLASH_CHIP_VERSION",
type:"UINT32",
devices:["T7"],
readwrite:"R"
};
retDictName["T7_MA_EXF_KEY"] = {
address:driver_const.T7_MA_EXF_KEY,
name:"T7_MA_EXF_KEY",
type:"UINT32",
devices:["T7", "T4"],
readwrite:"RW"
};
retDictName["T7_MA_EXF_WRITE"] = {
address:driver_const.T7_MA_EXF_WRITE,
name:"T7_MA_EXF_WRITE",
type:"UINT32",
devices:["T7", "T4"],
readwrite:"RW"
};
retDictName["T7_MA_EXF_pWRITE"] = {
address:driver_const.T7_MA_EXF_pWRITE,
name:"T7_MA_EXF_pWRITE",
type:"UINT32",
devices:["T7", "T4"],
readwrite:"RW"
};
retDictName["T7_MA_EXF_READ"] = {
address:driver_const.T7_MA_EXF_READ,
name:"T7_MA_EXF_READ",
type:"UINT32",
devices:["T7", "T4"],
readwrite:"RW"
};
retDictName["T7_MA_EXF_pREAD"] = {
address:driver_const.T7_MA_EXF_pREAD,
name:"T7_MA_EXF_pREAD",
type:"UINT32",
devices:["T7", "T4"],
readwrite:"RW"
};
retDictName["T7_MA_EXF_ERASE"] = {
address:driver_const.T7_MA_EXF_ERASE,
name:"T7_MA_EXF_ERASE",
type:"UINT32",
devices:["T7", "T4"],
readwrite:"RW"
};
retDictName["T7_FLASH_CHIP_VERSION"] = {
address:driver_const.T7_FLASH_CHIP_VERSION,
name:"T7_FLASH_CHIP_VERSION",
type:"UINT32",
devices:["T7"],
readwrite:"R"
};
// Fix the STREAM_ENABLE register so that it is a readable register.
var streamEnableAddr = retDictName['STREAM_ENABLE'].address;
retDict[streamEnableAddr].readWrite = 'RW';
retDictName['STREAM_ENABLE'].readwrite = 'RW';
return [retDict, retDictName, expandedConstants, minifiedConstants];
}
/**
* This function forces the creation of the bufferInfo attribute to registers
* that contains more information about them.
**/
var addMissingBufferRegisterInfoObject = function(options) {
var constantsData = options.constantsData;
var location = options.location;
var index = options.index;
var name = options.name;
var bufferInfo;
var addData = false;
// Search for a buffer's info
array_registers.forEach(function(arrayRegister) {
if(name === arrayRegister.data) {
bufferInfo = {
'size': arrayRegister.size,
};
var importTypeData = true;
if(arrayRegister.type) {
if(arrayRegister.type !== 'raw') {
bufferInfo.type = arrayRegister.type;
importTypeData = false;
}
}
if(importTypeData) {
bufferInfo.type = constantsData[location][index].type;
}
addData = true;
}
});
if(addData) {
constantsData[location][index].bufferInfo = bufferInfo;
}
};
/**
* This function forces the isBuffer register flag to be set for known buffer
* registers.
**/
var addMissingBufferRegisterFlags = function(constantsData) {
var i;
var registerName;
try {
for(i = 0; i < constantsData.registers.length; i++) {
registerName = constantsData.registers[i].name;
if(buffer_registers.indexOf(registerName) >= 0) {
constantsData.registers[i].isBuffer = true;
addMissingBufferRegisterInfoObject({
'constantsData': constantsData,
'location': 'registers',
'index': i,
'name': registerName,
});
}
}
for(i = 0; i < constantsData.registers_beta.length; i++) {
registerName = constantsData.registers_beta[i].name;
if(buffer_registers.indexOf(registerName) >= 0) {
constantsData.registers_beta[i].isBuffer = true;
addMissingBufferRegisterInfoObject({
'constantsData': constantsData,
'location': 'registers_beta',
'index': i,
'name': registerName,
});
}
}
} catch(err) {
console.log('Error adding missing buffer register flags', err, i);
}
return constantsData;
};
/**
* Object that parses the json file's & saves the two re-indexed dictionarys.
* @param {string} LJMJSONFileLocation location of 'ljm_constants.json'
* @throws {JSONParsingError} If [this condition is met]
*/
var parseConstants = function(LJMJSONFileLocation) {
//Load files into memory:
var constantsData = require(LJMJSONFileLocation);
addMissingBufferRegisterFlags(constantsData);
var indexedConstants = reindexConstantsByRegister(constantsData);
this.constantsByRegister = indexedConstants[0];
this.constantsByName = indexedConstants[1];
this.expandedConstants = indexedConstants[2];
this.minifiedConstants = indexedConstants[3];
this.origConstants = constantsData;
this.errorsByNumber = {};
this.errorsByName = {};
this.arrayRegisters = {};
var i;
for(i = 0; i < array_registers.length; i++) {
this.arrayRegisters[array_registers[i].name] = array_registers[i];
}
// Append custom "forcing error b/c device not connected" error
constantsData.errors.push({
'error': driver_const.LJN_DEVICE_NOT_CONNECTED,
'string': 'LJN_DEVICE_NOT_CONNECTED',
'description': 'The device is no longer connected, trying to reconnect.'
});
// Append custom "forcing error b/c device not connected" error
constantsData.errors.push({
'error': driver_const.LJN_UNEXPECTED_ASYNC_CALL_ERROR,
'string': 'LJN_UNEXPECTED_ASYNC_CALL_ERROR',
'description': 'The Asynchronous ffi library returned an unexpected error.'
});
// Append custom "forcing error b/c device not connected" error
constantsData.errors.push({
'error': driver_const.LJN_INVALID_IO_ATTEMPT,
'string': 'LJN_INVALID_IO_ATTEMPT',
'description': 'The device is no longer connected, trying to reconnect.'
});
constantsData.errors.push({
'error': driver_const.LJN_INVALID_ARGUMENTS,
'string': 'LJN_INVALID_ARGUMENTS',
'description': 'Invalid arguments were used to call a function.'
});
var numErrors = constantsData.errors.length;
for(i = 0; i < numErrors; i ++) {
this.errorsByNumber[constantsData.errors[i].error] = constantsData.errors[i];
this.errorsByName[constantsData.errors[i].string] = constantsData.errors[i];
}
this.getErrorInfo = function(err) {
var result;
if(isNaN(err)) {
result = self.errorsByName[err];
} else {
result = self.errorsByNumber[err];
}
if(typeof(result) === 'undefined') {
result = {
'error': -1,
'string': 'Unknown Error Numer'
};
}
return result;
};
this.getAddressInfo = function(address, direction) {
var regEntry;
//Get the Dictionary Entry
var isNumber = isNaN(address);
if(!isNumber) {
regEntry = self.constantsByRegister[address];
resolvedAddress = address;
} else if(isNumber) {
regEntry = self.constantsByName[address];
try {
resolvedAddress = regEntry.address;
}
catch (e) {
return {type: -1, directionValid: 0, typeString: "NA"};
}
//console.log(self.constantsByName);
}
//Create a deviceType Variable to save the deviceType number into
var validity;
try {
var readWrite = regEntry.readwrite;
} catch (e) {
return {type: -1, directionValid: 0, typeString: "NA"};
}
var deviceType;
if(regEntry.type == 'UINT16') {
deviceType = driver_const.LJM_UINT16;
} else if(regEntry.type == 'UINT32') {
deviceType = driver_const.LJM_UINT32;
} else if(regEntry.type == 'INT32') {
deviceType = driver_const.LJM_INT32;
} else if(regEntry.type == 'FLOAT32') {
deviceType = driver_const.LJM_FLOAT32;
} else if(regEntry.type == 'STRING') {
deviceType = driver_const.LJM_STRING;
} else if(regEntry.type == 'BYTE') {
deviceType = driver_const.LJM_BYTE;
} else if(regEntry.type == 'UINT64') {
deviceType = driver_const.LJM_UINT64;
}
var luaTypeInt;
if(regEntry.type == 'UINT16') {
luaTypeInt = 0;
} else if(regEntry.type == 'UINT32') {
luaTypeInt = 1;
} else if(regEntry.type == 'INT32') {
luaTypeInt = 2;
} else if(regEntry.type == 'FLOAT32') {
luaTypeInt = 3;
} else if(regEntry.type == 'STRING') {
luaTypeInt = 98;
} else if(regEntry.type == 'BYTE') {
luaTypeInt = 99;
} else if(regEntry.type == 'UINT64') {
luaTypeInt = -1;
}
// Save data to the regEntry
// regEntry.luaTypeInt = luaTypeInt;
if(regEntry.readwrite.indexOf(direction) != -1) {
validity = 1;
} else {
validity = 0;
}
var size = typeSizes[regEntry.type];
if(typeof(size) === 'undefined') {
size = 0;
}
return {
type: deviceType,
luaTypeInt: luaTypeInt,
directionValid: validity,
typeString: regEntry.type,
address: resolvedAddress,
size: size,
data: regEntry
};
};
this.isArrayRegister = function(address) {
if(typeof(self.arrayRegisters[address]) !== 'undefined') {
return true;
} else {
return false;
}
};
var self = this;
};
var constants = new parseConstants(LJM_JSON_FILE_LOCATION);
/**
* Makes the constants object available to other files
* @return {constants-object} link to the constants object
*/
exports.getConstants = function() {
return constants;
};