@iotize/tap
Version:
IoTize Device client for Javascript
869 lines • 71.5 kB
JavaScript
import { asciiStringToByteBuffer, bufferToHexString, hexStringToBuffer, } from '@iotize/common/byte-converter';
import { KaitaiStreamWriter } from '@iotize/common/byte-stream';
import { DotAccessor } from '@iotize/common/data-accessor';
import { HostProtocol, SpecialFeature } from '@iotize/tap';
import { ADMIN_USER, ANONYMOUS_USER, isSpecialUser, } from '@iotize/tap/configurator';
import { SecurityOptionsConverter, SerialSettings, SlaveServerRawConfig, tapnpassConverters, TapnpassProtocolConfigurationConverter, TargetCanProtocolConfiguration, VariableType, } from '@iotize/tap/service/all';
import { converters } from '@iotize/tap/service/core';
import { parse } from 'fast-xml-parser';
import { IoTizeStudioError } from '../errors';
import { toEnumType } from '../util';
import { LowPowerOptimizationLevelMapping, NetworkModeMapping, NFCParingModeMapping, NFC_CONNECTION_PRIORITY_MAPPING, S3P_CONFIG_MODE_MAPPING, TargetProtocolMapping, WIFI_KEY_VISIBILITY_MAPPING, WIFI_PROTOCOL_MAPPING, WIFI_SSID_VISIBILITY_MAPPING, } from './mapping';
import { convertToVariableType, fromMapping, isTruthy } from './utility';
export function xmlToJson(xml) {
return parse(xml, {
attributeNamePrefix: '',
ignoreAttributes: false,
});
}
export function convertIoTizeStudioConfigToTapConfig(fileContent) {
// console.log('File content', fileContent);
const config = new IoTizeStudioToTapConfigConverter().convert(new DotAccessor(xmlToJson(fileContent)));
return config;
}
function isHexString(input) {
if (typeof input !== 'string') {
return false;
}
return input.match(/^(0x)?([a-fA-F0-9])*$/);
}
export function decodeInitialVariableValue(value) {
const values = value
.split(';')
.reduce((prev, v) => {
if (v.length === 0) {
return prev;
}
if (v.startsWith('0x')) {
prev.push(v);
}
else {
prev.push(parseFloat(v));
}
return prev;
}, []);
return values.length > 0
? values.length === 1
? values[0]
: values
: undefined;
}
function addNodeValueIfExist(data, config, mapping, method = 'string') {
Object.entries(mapping).forEach(([iotzName, apiName]) => {
var _a;
const value = (_a = data
.get(iotzName, undefined)) === null || _a === void 0 ? void 0 : _a.value('Name', method, undefined);
if (value) {
config[apiName] = value;
}
});
}
function addAttributeIfExist(data, config, iotzName, apiName, method) {
const value = data === null || data === void 0 ? void 0 : data.value(iotzName, method, undefined);
if (value !== undefined && value !== '') {
config[apiName] = value;
}
}
function addAttributesIfExists(data, config, mapping, method = 'string') {
Object.entries(mapping).forEach(([iotzName, apiName]) => {
addAttributeIfExist(data, config, iotzName, apiName, method);
});
}
/**
* Convert an IoTize studio configuration file to TapConfiguratorConfig
*/
export class IoTizeStudioToTapConfigConverter {
constructor(options = {
strict: false,
}, host) {
this.options = options;
this.host = host;
/**
* Errors reported during convertion when strict mode is disabled
*/
this.warnings = [];
this.modbusSerialConfigConverter = new TapnpassProtocolConfigurationConverter();
}
convert(root) {
const config = root.get('IOTizeConfiguration');
const appConfigNode = config.get('IOTizeApp');
const wifiConfigNode = appConfigNode.get('WIFI_Info', undefined);
const bundles = config.list('IOTizeBundle', []);
const profiles = config.list('IOTizeProfile', []);
const versionString = config.value('Version', 'string', '1.0.0');
const result = {
version: versionString,
application: this.readApplicationConfig(appConfigNode),
data: {
bundles: this.readBundlesConfig(bundles),
profiles: this.readProfilesConfig(profiles),
},
cloud: this.readCloudConfig(appConfigNode),
jvm: this.readJvmConfig(config),
wireless: {
options: this.readWirelessOptionsConfig(appConfigNode),
protocols: {
wifi: this.readWifiConfig(wifiConfigNode),
mqtt: this.readMqttConfig(wifiConfigNode),
ble: this.readBleConfig(appConfigNode),
lora: this.readLoraConfig(appConfigNode),
nfc: this.readNfcConfig(appConfigNode),
},
},
tap: this.readTapConfig(appConfigNode),
target: this.readTargetConfig(appConfigNode),
};
const slaveServerConfig = this.readSlaveServerConfig(appConfigNode);
if (slaveServerConfig) {
result.slaveServer = slaveServerConfig;
}
const ethernet = this.readEthernetConfig(appConfigNode);
if (ethernet) {
result.ports = {
ethernet,
};
}
if (this.warnings.length > 0) {
// TODO
}
return result;
}
reportError(error, message = error.message) {
if (this.options.strict) {
throw error;
}
this.warnings.push({
error: error,
message,
});
}
readSlaveServerConfig(appConfig) {
if (!appConfig) {
return undefined;
}
const channel = appConfig.value('MBS_Com_Channel', 'number', 0);
switch (channel) {
case SlaveServerRawConfig.Channel.CAN:
return {
type: 'CAN',
config: this.readCanProtocolConfig(appConfig),
};
case SlaveServerRawConfig.Channel.MODBUS_RTU:
const targetProtocolConfDataLen = appConfig.value('MBSProtocolConfDataLen', 'number', 0);
let protocolData = hexStringToBuffer(appConfig.value('MBSProtocolConfData', 'string', ''));
return {
type: 'MODBUS_RTU',
config: this._protocolDataToJsonConfig(protocolData, targetProtocolConfDataLen),
};
case SlaveServerRawConfig.Channel.MODBUS_TCP:
return {
type: 'MODBUS_TCP',
config: {
port: appConfig.value('MBS_ModbusTCP_Port', 'number', 502),
firstRegisterAddress: appConfig.value('MBS_ModbusTCP_Addr0', 'number', 0),
},
};
case SlaveServerRawConfig.Channel.SPI:
return {
type: 'SPI',
};
case SlaveServerRawConfig.Channel.DISABLED:
return undefined;
default:
throw new Error('Invalid config'); // TODO proper error
}
}
readMqttConfig(cloudServicesConfig) {
var _a;
if (!cloudServicesConfig) {
return undefined;
}
const config = {};
addNodeValueIfExist(cloudServicesConfig, config, {
CloudHostName: 'brokerHostname',
CloudServiceName: 'brokerPort',
CloudMQTT_UID: 'password',
GUI_DevNetkey: 'relayNetKey',
GUI_DevMQTT_ClientID: 'clientId',
CloudMQTT_USERNAME: 'username',
});
const brokerCertificate = this.readFileContentAsHexString((_a = cloudServicesConfig
.get('AWSRootCertificate', undefined)) === null || _a === void 0 ? void 0 : _a.value('Name', 'string', undefined));
if (brokerCertificate) {
config.brokerCertificate = brokerCertificate;
}
return config;
}
readLoraConfig(appConfigNode) {
return {
config: undefined,
ids: undefined,
};
}
readBleConfig(appConfigNode) {
return {};
}
readNfcConfig(appConfigNode) {
return {
autoLogProfileId: appConfigNode.value('NFCLogin', 'number', undefined),
connectionPriority: fromMapping(appConfigNode, 'NFCInterruptionLock', NFC_CONNECTION_PRIORITY_MAPPING, undefined),
};
}
readWifiConfig(wifiConfigNode) {
if (!wifiConfigNode) {
return undefined;
}
const mode = fromMapping(wifiConfigNode, 'Network', NetworkModeMapping, 'P2P');
const isAP = mode === 'PEER_TO_PEER';
const config = {
mode,
};
addAttributeIfExist(wifiConfigNode, config, 'ModuleIPMask', 'mask', 'string');
addAttributeIfExist(wifiConfigNode, config, 'ModuleIPGateway', 'gatewayIp', 'string');
addAttributeIfExist(wifiConfigNode, config, 'ModuleIPAddress', 'ip', 'string');
addAttributeIfExist(wifiConfigNode, config, 'Wifi_TxLevel', 'txPower', 'number');
const keyVisibility = fromMapping(wifiConfigNode, 'Wifi_WEPKey_Hidden', WIFI_KEY_VISIBILITY_MAPPING, undefined);
if (keyVisibility !== undefined) {
config.keyVisibility = keyVisibility;
}
const protocol = fromMapping(wifiConfigNode, 'Wifi_Protocol', WIFI_PROTOCOL_MAPPING, undefined);
if (protocol) {
config.protocol = protocol;
}
addAttributeIfExist(wifiConfigNode, config, 'Wifi_Region', 'countryCode', 'number');
const ssidVisibility = fromMapping(wifiConfigNode, 'Wifi_SSID_Hidden', WIFI_SSID_VISIBILITY_MAPPING, undefined);
if (ssidVisibility) {
config.ssidVisibility = ssidVisibility;
}
addAttributeIfExist(wifiConfigNode, config, isAP ? 'Module_AP_SSID' : 'ModuleSSID', 'ssid', 'string');
addAttributeIfExist(wifiConfigNode, config, isAP ? 'Module_AP_WEPKey' : 'ModuleWEPKey', 'key', 'string');
return config;
}
toAuthorizedHostProtocols(value) {
if (!value || value === 'ALL' || value === 'FFFF') {
return undefined;
}
if (isHexString(value)) {
const encodedValue = hexStringToBuffer(value);
return converters.hostProtocolArray.decode(encodedValue).map((p) => {
return HostProtocol[p];
});
}
else {
return value.split(',').reduce((prev, value) => {
value = value.trim();
try {
// TODO check it's a read HostProtocolConfig...
prev.push(value); //stringToEnum<HostProtocolConfig>(HostProtocolConfig, value));
}
catch (err) {
this.reportError(err);
}
return prev;
}, []);
}
}
readAuthorizedHostProtocols(appConfigNode) {
let availableHostProtocols = undefined;
const hostProtocolString = appConfigNode.value('HostProtocol', 'string', undefined);
try {
availableHostProtocols =
this.toAuthorizedHostProtocols(hostProtocolString);
}
catch (err) {
this.reportError(err, `Cannot convert HostProtocol value "${hostProtocolString}"`);
}
return availableHostProtocols && availableHostProtocols.length > 0
? availableHostProtocols
: undefined;
}
readWirelessOptionsConfig(appConfigNode) {
const wirelessOptionsConfig = {
inactivityTimeout: appConfigNode.value('LowPowerHostTimeout', 'number', 0),
};
const authorizedProtocols = this.readAuthorizedHostProtocols(appConfigNode);
if (authorizedProtocols) {
wirelessOptionsConfig.authorizedProtocols = authorizedProtocols;
}
const nfcPairingMode = fromMapping(appConfigNode, 'NFCPairingMandatory', NFCParingModeMapping, undefined);
const blePairing = appConfigNode.value('BLEPairingRequest', 'boolean', undefined);
if (nfcPairingMode !== undefined || blePairing !== undefined) {
wirelessOptionsConfig.pairing = {
blePairing,
nfcPairingMode,
};
}
return wirelessOptionsConfig;
}
readJvmConfig(config) {
const appConfigNode = config.get('IOTizeApp');
const envNode = config.get('GUI_Environment', undefined);
const bcbFile = appConfigNode.value('JVM_Custom_Code', 'string', undefined);
const useJvm = envNode === null || envNode === void 0 ? void 0 : envNode.value('UseInternalJVM', 'boolean', false);
if (!useJvm) {
return undefined;
}
return {
code: bcbFile ? this.readFileContentAsHexString(bcbFile) : undefined,
// profileId: appConfigNode.value('TODO', 'number', undefined) // TODO
};
}
readEthernetConfig(accessor) {
const data = {};
addAttributesIfExists(accessor, data, {
EthernetIPAddress: 'ip',
EthernetIPGateway: 'gatewayIp',
EthernetIPMask: 'ipMask',
});
if (Object.keys(data).length === 0) {
return undefined;
}
return data;
}
readFileContentAsHexString(path) {
if (!path) {
return undefined;
}
if (!this.host) {
this.reportError(new Error(`External file reference "${path}" cannot be resolved`));
}
if (this.host) {
try {
const fileContent = this.host.getFileContent(path);
return '0x' + bufferToHexString(fileContent);
}
catch (err) {
this.reportError(err);
}
}
return undefined;
}
readCloudConfig(appConfigNode) {
const cloudService = appConfigNode.get('CloudServices', undefined);
// TODO cloud services
// if (cloudService?.has('CloudMQTT_UID')) {
// let url = '';
// const cloudHostName = cloudService.get('CloudHostName', undefined);
// const cloudServiceName = cloudService.get('CloudServiceName', undefined);
// if (cloudHostName) {
// url = `mqtt://${cloudHostName.value('Name', 'string', '')}:${cloudServiceName?.value('Name', 'string', '') || ''}`;
// }
// // cloud = {
// // // password: cloudService
// // // .get('CloudMQTT_UID', undefined)
// // // ?.value('Name', 'string', '') || '',
// // uploadPeriod: ,
// // url
// // };
// }
const wifiNode = appConfigNode.get('WIFI_Info', undefined);
const cloudConfig = {};
const dataLogConfig = {};
if (wifiNode) {
addAttributesIfExists(wifiNode, dataLogConfig, {
Cloud_Publish_Topic: 'mqttPublishTopic',
Cloud_Subscribe_Topic: 'mqttSubscribeTopic',
});
}
if (cloudService) {
addAttributesIfExists(cloudService, dataLogConfig, {
CloudMqttPeriod: 'uploadPeriod',
}, 'number');
}
if (Object.keys(dataLogConfig).length > 0) {
cloudConfig.dataLog = dataLogConfig;
}
if (Object.keys(cloudConfig).length > 0) {
return cloudConfig;
}
else {
return undefined;
}
}
readApplicationConfig(appConfigNode) {
const appPath = appConfigNode.has('GUI_Path')
? appConfigNode.value('GUI_Path', 'string', '')
: appConfigNode.value('Path', 'string', '');
// const appPathInfo = this.appPathConverter.decode(appPath);
const config = {
name: appConfigNode.value('Name', 'string', 'Tap'),
universalLink: appConfigNode.value('WebLink', 'string', ''),
uri: appPath,
};
const productCode = appConfigNode.value('ProductCode', 'string', undefined);
if (productCode !== undefined) {
config.productCode = productCode;
}
const additionalData = appConfigNode.value('Data', 'string', undefined);
if (additionalData !== undefined) {
config.data = `0x${bufferToHexString(asciiStringToByteBuffer(additionalData))}`;
}
return config;
}
readTapConfig(appConfigNode) {
var _a, _b;
const lockSettingsEncoded = appConfigNode.value('InterfaceLock', 'number', 0);
const lockOptions = new SecurityOptionsConverter().decode(Uint8Array.from([0, lockSettingsEncoded])); // TODO pad instead
const tapOptions = {
security: lockOptions,
powerOptimization: fromMapping(appConfigNode, 'LowPowerLevel', LowPowerOptimizationLevelMapping, undefined),
scram: {
hashIteration: appConfigNode.value('Scram_Hash_It', 'number', 5000),
},
certificate: {
publicKey: this.readFileContentAsHexString((_a = appConfigNode
.get('DeviceCertificate', undefined)) === null || _a === void 0 ? void 0 : _a.value('Name', 'string', undefined)),
privateKey: this.readFileContentAsHexString((_b = appConfigNode
.get('DevicePrivateKey', undefined)) === null || _b === void 0 ? void 0 : _b.value('Name', 'string', undefined)),
},
};
const timeZoneStr = appConfigNode.value('TimeZoneStr', 'string', undefined);
const ntpServer = appConfigNode.value('NTP_URL', 'string', undefined);
if (timeZoneStr || ntpServer) {
tapOptions.time = {
zone: timeZoneStr,
ntpServer,
};
}
return tapOptions;
}
readTapTimeConfig(appConfigNode) {
const zone = appConfigNode.value('TimeZoneStr', 'string', undefined);
const ntpServer = appConfigNode.value('NTP_URL', 'string', undefined);
if (zone || ntpServer) {
return {
zone,
ntpServer,
};
}
return undefined;
}
readTargetConfig(appConfig) {
const firmwareVersion = appConfig.value('Firmware', 'string', undefined);
if (appConfig.value('GUI_TargetType', 'string', '0') === '1') {
return {
type: 'TAPNPASS',
protocol: {
config: this.readTapnpassTargetProtocolConfig(appConfig),
},
firmwareVersion,
};
}
else {
const protocol = this.readMCUTargetProtocol(appConfig);
if (!protocol) {
return undefined;
}
return {
type: 'MCU',
protocol,
firmwareVersion,
};
}
// if (appConfig.has('USB_Aliases')) {
// data.type = "TAPNPASS";
// (data as TapNPassTargetConfig).usb = this._convertUsbData(appConfig);
// }
}
readTargetProtocol(appConfig) {
// const targetProtocolString = appConfig.value('TargetProtocol', 'string', 'SWD');
return fromMapping(appConfig, 'TargetProtocol', TargetProtocolMapping, 'NONE');
}
readTapnpassTargetProtocol(appConfig) {
const targetProtocol = this.readTargetProtocol(appConfig);
switch (targetProtocol) {
case 'SERIAL':
const serialConfig = {
type: 'SERIAL',
config: this.readTapnpassTargetProtocolConfig(appConfig),
};
return serialConfig;
case 'MODBUS':
const modbusConfig = {
type: 'MODBUS',
config: this.readTapnpassTargetProtocolConfig(appConfig),
};
return modbusConfig;
default:
throw new Error(`Illegal target protocol "${targetProtocol === null || targetProtocol === void 0 ? void 0 : targetProtocol.toString()}" for TapNPass target type.`);
}
}
readTapnpassTargetProtocolConfig(appConfig) {
const targetProtocolConfDataLen = appConfig.value('TargetProtocolConfDataLen', 'number', 0);
const protocolData = hexStringToBuffer(appConfig.value('TargetProtocolConfData', 'string', ''));
return this._protocolDataToJsonConfig(protocolData, targetProtocolConfDataLen);
}
readMCUTargetProtocol(appConfig) {
const targetProtocol = this.readTargetProtocol(appConfig);
switch (targetProtocol) {
case 'SWD':
return {
type: targetProtocol,
};
case 'CUSTOM':
return {
type: 'CUSTOM',
// config: '0xTODO'
};
case 'MODBUS':
return {
type: 'MODBUS',
config: this.readModbusProtocolConfig(appConfig),
};
case 'S3P':
return {
type: 'S3P',
config: this.readS3PProtocolConfig(appConfig),
};
case 'SERIAL':
const serialConfig = {
type: 'SERIAL',
config: this.readTapnpassTargetProtocolConfig(appConfig),
};
return serialConfig;
case 'NONE':
return undefined;
case 'DIRECT_IO':
return {
type: 'DIRECT_IO',
};
case 'CAN':
return {
type: 'CAN',
config: this.readCanProtocolConfig(appConfig),
};
case 'MODBUS_TCP':
return {
type: 'MODBUS_TCP',
config: this.readModbusTcpProtocolConfig(appConfig),
};
case 'JTAG':
default:
throw new Error(`Target protocol convertion from "${targetProtocol === null || targetProtocol === void 0 ? void 0 : targetProtocol.toString()}" is not supported yet.`);
}
}
readSerialProtocolConfig(appConfig) {
const config = this.readModbusProtocolConfig(appConfig);
if (!config) {
return undefined;
}
return config === null || config === void 0 ? void 0 : config.serial;
}
readS3PProtocolConfig(appConfig) {
return {
mode: fromMapping(appConfig, 'S3Pmode', S3P_CONFIG_MODE_MAPPING) || 'EMULATION',
delay: appConfig.value('S3PDelay', 'number', 1),
};
}
/**
* CAN_Freqkbps="0" CAN_Mode="1" CAN_Filter="1" CAN_Code="305419896" CAN_Mask="2596069104"
* @param appConfig
* @returns
*/
readCanProtocolConfig(appConfig) {
return {
frequency: appConfig.value('CAN_Freqkbps', 'number', 25),
mode: fromMapping(appConfig, 'CAN_Mode', TargetCanProtocolConfiguration.Mode) || 'NORMAL',
filter: fromMapping(appConfig, 'CAN_Filter', TargetCanProtocolConfiguration.Filter) || 'SINGLE',
code: toHexNumberConfig(appConfig.value('CAN_Code', 'number', 0x0)),
mask: toHexNumberConfig(appConfig.value('CAN_Mask', 'number', 0xffffffff)),
};
}
readModbusTcpProtocolConfig(node) {
const data = {
modbus: {},
};
addAttributesIfExists(node, data['modbus'], {
ModbusTCPDefSlaveAddr: 'defaultSlaveAddress',
});
addAttributesIfExists(node, data['modbus'], {
ModbusTCPAddr0: 'firstRegisterAddress',
ModbusTCPPort: 'port',
ModbusTCPTimeout: 'timeout',
}, 'number');
if (Object.keys(data).length === 0) {
return undefined;
}
return data;
}
readModbusProtocolConfig(appConfig) {
const config = this.readTapnpassTargetProtocolConfig(appConfig);
const partialSerial = config.serial;
delete partialSerial.identification;
delete partialSerial.physicalPort;
delete partialSerial.hardwareFlowControl;
delete partialSerial.ledStatus;
return {
modbus: config.modbus,
serial: config.serial,
};
}
toEnumKey(value, mapping) {
// if (value === undefined) {
// return defaultValue;
// }
if (!(value in mapping)) {
this.reportError(new Error(`Cannot find corresponding key for value "${value.toString()}". Available keys: ${Object.keys(mapping).join(', ')}`));
}
return mapping[value];
}
// _convertUsbData(appConfig: IAccessor): UsbConfig {
// let aliases: UsbAlias[] = [];
// let usbAliasesAcccessor = appConfig.get('USB_Aliases');
// for (let aliasNum = 0; ; aliasNum++) {
// let aliasName = `Alias${aliasNum}`;
// if (!usbAliasesAcccessor.has(aliasName)) {
// break;
// }
// let usbAliasRawData = hexStringToBuffer(usbAliasesAcccessor.value(aliasName));
// aliases.push(this._convertUsbAlias(usbAliasRawData));
// }
// return {
// aliases: aliases
// };
// }
// private _convertUsbAlias(data: Uint8Array): UsbAlias {
// return this.usbAliasConverter.decode(data);
// }
readProfilesConfig(profiles) {
const results = [];
for (let i = 0; i < profiles.length; i++) {
const xmlProfile = profiles[i];
const name = xmlProfile.value('Name');
let profile;
if (name === ANONYMOUS_USER.username) {
continue;
}
else if (isSpecialUser(name)) {
const specialConfig = {
username: xmlProfile.value('Name', 'string'),
lifeTime: xmlProfile.value('LifeTime', 'number', 0),
key: this.readUserKey(xmlProfile),
};
profile = specialConfig;
}
else {
const userConfig = {
username: xmlProfile.value('Name', 'string', ''),
id: xmlProfile.value('Id', 'number', 0),
lifeTime: xmlProfile.value('LifeTime', 'number', 0),
key: this.readUserKey(xmlProfile),
};
profile = userConfig;
}
const subProfilesConfig = xmlProfile.list('IOTizeUser', []);
if (subProfilesConfig.length > 0) {
const subProfiles = this.readUserProfile(subProfilesConfig);
profile.users = subProfiles;
}
results.push(profile);
}
return results;
}
readUserKey(xmlProfile) {
const scramPwd = xmlProfile.value('Scram_Pwd', 'string', undefined);
if (scramPwd) {
// let userSalt = xmlProfile.value('Scram_User_Salt', 'number');
// specialConfig.salt = userSalt;
return `0x${scramPwd}`;
}
else {
const key = xmlProfile.value('Pwd', 'string', undefined);
if (key) {
return `0x${key}`;
}
}
return undefined;
}
readUserProfile(subProfilesConfig) {
const users = [];
for (let i = 0; i < subProfilesConfig.length; i++) {
const xmlUserConfig = subProfilesConfig[i];
const user = {
username: xmlUserConfig.value('Name', 'string', ''),
id: xmlUserConfig.value('Id', 'number', 0),
key: this.readUserKey(xmlUserConfig),
};
users.push(user);
}
return users;
}
readBundlesConfig(xmlBundles) {
const result = [];
for (let i = 0; i < xmlBundles.length; i++) {
const xmlBundle = xmlBundles[i];
let aclsXml = [];
const aclContainer = xmlBundle.get('IOTizeAccessControl', undefined);
if (aclContainer) {
aclsXml = aclContainer.list('IOTizeACL', []);
}
const acls = {};
for (let j = 0; j < aclsXml.length; j++) {
const aclXml = aclsXml[j];
const profileName = aclXml.value('ProfileName');
if (profileName === ADMIN_USER.username) {
continue;
}
const rights = aclXml.value('Rights');
acls[profileName] = {
read: rights.includes('read'),
write: rights.includes('write'),
};
}
const bundleConfig = {
name: xmlBundle.value('GUI_Name'),
id: parseInt(xmlBundle.value('Id')),
variables: this.readVariablesConfig(xmlBundle.list('IOTizeVariable', [])),
acls,
dataLog: {
period: xmlBundle.value('DataLogPeriod', 'number', 0),
},
features: this.readSpecialFeatures(xmlBundle.list('Feature', [])),
};
result.push(bundleConfig);
}
return result;
}
readSpecialFeatures(featuresXml) {
if (featuresXml.length > 0) {
const result = [];
for (let i = 0; i < featuresXml.length; i++) {
const featureId = featuresXml[i].value('FeatureResId', 'number');
if (featureId in SpecialFeature) {
const value = SpecialFeature[featureId]; // TODO check
result.push(value);
}
else {
throw new Error(`Unexpected feature id: ${featureId}`);
}
}
return result;
}
else {
return undefined;
}
}
readVariablesConfig(variables) {
const result = [];
for (let i = 0; i < variables.length; i++) {
const xmlVariable = variables[i];
const id = xmlVariable.value('Id', 'number');
const length = xmlVariable.value('Quantity', 'number', 1);
const dataType = toEnumType(convertToVariableType(xmlVariable), VariableType.Data);
const name = xmlVariable.value('GUI_Name', 'string', '');
const unit = xmlVariable.value('GUI_DispUnit', 'string', '') || undefined;
let meta;
if (name || unit) {
meta = {
name,
unit,
};
}
const isInTapStatic = isTruthy(xmlVariable.value('IsInTap', 'string', '0'));
const IsInTapVolatile = isTruthy(xmlVariable.value('IsInTapVolatile', 'string', '0'));
if (IsInTapVolatile || isInTapStatic) {
const initialValueString = xmlVariable.value('InTap_InitialValueString', 'string', '');
const initialValue = decodeInitialVariableValue(initialValueString);
const inTapVariable = {
domain: IsInTapVolatile ? 'IN_TAP_VOLATIL' : 'IN_TAP_STATIC',
id,
length,
dataType,
meta,
value: initialValue,
};
result.push(inTapVariable);
}
else {
// if (isModbusTargetConfig){
// const modbusVariableConfig: ModbusVariableConfig = {
// domain: 'TARGET',
// modbusAddress: {
// },
// id,
// length,
// dataType,
// name,
// unit
// };
// result.push(variableConfig);
// }
// else {
const varAddress = parseInt(xmlVariable.value('Address', 'string'));
if (isNaN(varAddress)) {
throw new Error(`Failed to parse variable ${name} #${id}: address is not a number.`);
}
const variableConfig = {
domain: 'TARGET',
address: toHexNumberConfig(varAddress),
id,
length,
dataType,
meta,
};
result.push(variableConfig);
// }
}
}
return result;
}
_protocolDataToJsonConfig(protocolData, targetProtocolConfDataLen) {
if (targetProtocolConfDataLen === 0) {
return {
modbus: {
offsetFirstRegister: false,
slave: 0,
},
serial: {
baudRate: 115200,
bitParity: 'EVEN',
dataBits: '_8',
handshakeDelimiter: 'NONE',
hardwareFlowControl: 'NONE',
identification: false,
ledStatus: true,
physicalPort: 'AUTO',
stopBits: 'ONE',
timeout: 255,
},
usb: {
aliases: [],
},
};
}
if (protocolData.length < 8) {
throw IoTizeStudioError.invalidKeyValue('TargetProtocolConfData', // TODO change key
'Protocol configuration data should be at least 8 bytes');
}
const ctr1 = protocolData.slice(0, 4);
const ctr2 = protocolData.slice(4, 8);
const remaining = protocolData.slice(8);
// KaitaiStreamWriter.mergeArrays(ctr2, ctr1).reverse(),
protocolData = KaitaiStreamWriter.mergeArrays(ctr1.reverse(), ctr2.reverse(), remaining);
const PROTOCOL_CONF_CTR_LENGHT = 8;
const reorderedProtocolData = KaitaiStreamWriter.mergeArrays(protocolData.slice(0, PROTOCOL_CONF_CTR_LENGHT).reverse(), protocolData.slice(PROTOCOL_CONF_CTR_LENGHT));
const protocolConf = tapnpassConverters.tapnpassProtocolConfiguration.decode(reorderedProtocolData);
const serial = protocolConf.serial;
const usb = protocolConf.usb;
return {
modbus: protocolConf.modbus,
serial: {
baudRate: serial.baudRate,
bitParity: this.toEnumKey(serial.bitParity, SerialSettings.BitParity),
dataBits: this.toEnumKey(serial.dataBits, SerialSettings.DataBits),
handshakeDelimiter: this.toEnumKey(serial.handshakeDelimiter, SerialSettings.HandshakeDelimiter),
hardwareFlowControl: this.toEnumKey(serial.hardwareFlowControl, SerialSettings.HardwareFlowControl),
physicalPort: this.toEnumKey(serial.physicalPort, SerialSettings.PhysicalPort),
stopBits: this.toEnumKey(serial.stopBits, SerialSettings.StopBits),
timeout: serial.timeout,
identification: false,
ledStatus: false,
},
usb,
};
}
}
function toHexNumberConfig(v) {
return '0x' + v.toString(16);
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW90aXplLXN0dWRpby10by10YXAtY29uZmlnLWNvbnZlcnRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL2NvbmZpZy9pb3RpemUtc3R1ZGlvL3NyYy9saWIvaW90aXplLXN0dWRpby1jb25maWctY29udmVydGVyL2lvdGl6ZS1zdHVkaW8tdG8tdGFwLWNvbmZpZy1jb252ZXJ0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLHVCQUF1QixFQUN2QixpQkFBaUIsRUFDakIsaUJBQWlCLEdBQ2xCLE1BQU0sK0JBQStCLENBQUM7QUFDdkMsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDaEUsT0FBTyxFQUFFLFdBQVcsRUFBYSxNQUFNLDhCQUE4QixDQUFDO0FBQ3RFLE9BQU8sRUFBRSxZQUFZLEVBQUUsY0FBYyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBMkMzRCxPQUFPLEVBQ0wsVUFBVSxFQUNWLGNBQWMsRUFDZCxhQUFhLEdBQ2QsTUFBTSwwQkFBMEIsQ0FBQztBQUNsQyxPQUFPLEVBR0wsd0JBQXdCLEVBQ3hCLGNBQWMsRUFDZCxvQkFBb0IsRUFDcEIsa0JBQWtCLEVBQ2xCLHNDQUFzQyxFQUN0Qyw4QkFBOEIsRUFDOUIsWUFBWSxHQUNiLE1BQU0seUJBQXlCLENBQUM7QUFDakMsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ3RELE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUN4QyxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDOUMsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUNyQyxPQUFPLEVBQ0wsZ0NBQWdDLEVBQ2hDLGtCQUFrQixFQUNsQixvQkFBb0IsRUFDcEIsK0JBQStCLEVBQy9CLHVCQUF1QixFQUN2QixxQkFBcUIsRUFDckIsMkJB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