2024-11-30 19:42:17 +08:00

398 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { globalLookup } from "@/hook/global";
/**
* @description 计算 value 的渲染格式
* @param {string} link
* @returns {number}
*/
function getValueFormatCode(link) {
const renderOptions = globalLookup.currentSignalRenderOptions;
if (renderOptions.has(link)) {
const option = renderOptions.get(link);
if (typeof option.valueFormat === 'number') {
return option.valueFormat;
}
}
// 默认 16 进制
return 2;
}
/**
* @description 高效计算 2 的 n 次方n可以是负数
* @param {number} n 整数
*/
function efficentPow2(n) {
if (n === 0) {
return 1;
}
if (n > 0) {
return 1 << n;
}
if (n < 0) {
return 1 / (1 << (-n));
}
}
/**
* @description 16进制数字转换成有符号浮点数
* @param {string} hex
* @returns {number}
*/
export function hexToSignedInt(hex) {
if (hex.length % 2 != 0) {
hex = "0" + hex;
}
var num = parseInt(hex, 16);
var maxVal = Math.pow(2, hex.length / 2 * 8);
if (num > maxVal / 2 - 1) {
num = num - maxVal
}
return num;
}
export class FormatValueRender {
/**
*
* @param {string} link 信号的ID
* @param {number} width 信号的位置宽度
* @param {string} replacer 位置不足的地方会用 replacer 补足,比如 ...
*/
constructor(link, width, replacer = '') {
this.formatCode = getValueFormatCode(link);
this.width = BigInt(width);
this.replacer = replacer;
}
/**
* @description 根据当前的设置进行数值的渲染
* @param {number} value 波形当前的数值
* @param {number} pos 当前的位置宽度
* @returns {string} 转换后需要渲染的字符串
*/
render(value, pos) {
const formatCode = this.formatCode;
switch (formatCode) {
// 二进制
case 0: return this.radixTransform(2, value, pos);
// 八进制
case 1: return this.radixTransform(8, value, pos);
// 十六进制
case 2: return this.radixTransform(16, value, pos);
// 有符号整型
case 3: return this.radixTransform(10, value, pos, true);
// 无符号整型
case 4: return this.radixTransform(10, value, pos);
// 半精度浮点数
case 5: return this.floatTransform(16, value, pos);
// 单精度浮点数
case 6: return this.floatTransform(32, value, pos);
// 双精度浮点数
case 7: return this.floatTransform(64, value, pos);
// 未知
default: return '?';
}
}
/**
* @description 整数的进制转换
* @param {number} radix 进制
* @param {number} value 值
* @param {number} pos 位置宽度
* @param {boolean} sign 是否是有符号数,默认为 false
*/
radixTransform(radix, value, pos, sign = false) {
const width = this.width;
const replacer = this.replacer;
switch (value) {
case 'x':
return 'x';
break;
case '?':
return '?';
break;
default:
value = BigInt(value);
break;
}
// 如果是有符号数
if (sign) {
if ((value >> (width - 1n)) & 1n) {
value = value - (2n ** width);
}
let valueString = value.toString(radix);
if (pos === -1 || valueString.length <= pos) {
return valueString;
}
const valSign = (value < 0) ? '-' : '';
if (pos === 1) {
return valSign;
}
if (pos === 2) {
return valSign + replacer;
}
return valSign + replacer + valueString.slice(2 - pos);
}
// 无符号的各类进制数字
let valueString = value.toString(radix);
// 如果是 2, 8, 16 进制,需要根据宽度自动完全前面的 0 的填充
let displayWidth, padding;
switch (radix) {
case 2:
displayWidth = Number(width);
padding = "0".repeat(displayWidth - valueString.length);
valueString = padding + valueString;
break;
case 8:
displayWidth = Math.ceil(Number(width) / 3);
padding = "0".repeat(displayWidth - valueString.length);
valueString = padding + valueString;
break;
case 16:
displayWidth = Math.ceil(Number(width) / 4);
padding = "0".repeat(displayWidth - valueString.length);
valueString = padding + valueString;
break;
default:
break;
}
if (pos === -1 || valueString.length <= pos) {
return valueString;
}
if (pos === 1) {
return replacer;
}
return replacer + valueString.slice(1 - pos);
}
/**
* @description IEEE 浮点数的转换
* 为什么没有 sign 参数?因为 IEEE 定义下的 float 第一个位置就是符号
* @param {number} fWidth 16 32 或者 64
* @param {number} value 值
* @param {number} pos 位置
*/
floatTransform(fWidth, value, pos) {
const replacer = this.replacer;
if (fWidth === 16) {
value = this.calcIEEEFloat(value, 5, 10);
} else if (fWidth === 32) {
value = this.calcIEEEFloat(value, 8, 23);
} else if (fWidth === 64) {
value = this.calcIEEEFloat(value, 11, 52);
}
const valueString = value.toString();
if (pos === -1 || valueString.length <= pos) {
return valueString;
}
const valSign = (value < 0) ? '-' : '';
if (pos === 1) {
return valSign;
}
if (pos === 2) {
return valSign + replacer;
}
return valSign + replacer + valueString.slice(2 - pos);
}
/**
* @description 根据 e 和 m 得到计算 IEEE 浮点数的函数,默认第一个位置代表符号
* @param {number} value 值
* @param {number} eWidth 代表指数部分的位数
* @param {number} mWidth 代表有效尾数的位数
* @returns {(value: number) => number}
*/
calcIEEEFloat(value, eWidth, mWidth) {
const offset = (1 << (eWidth - 1)) - 1;
const mFrac = 1 << mWidth;
// 计算参考博客https://blog.csdn.net/leo0308/article/details/117398166
let bits = value.toString(2);
const width = 1 + eWidth + mWidth;
// 应对 bits 长度和 预定长度不一致的情况
// 不足的地方补上 0否则进行截断
if (bits.length < width) {
bits = '0'.repeat(width - bits.length) + bits;
}
if (bits.length > width) {
bits = bits.substring(bits.length - width);
}
const s = parseInt(bits[0], 2);
const e = parseInt(bits.substring(1, 1 + eWidth), 2);
const m = parseInt(bits.substring(2 + eWidth), 2);
const sign = (s === 1) ? -1 : 1;
// 全 0
if (e === 0) {
return sign * efficentPow2(-offset + 1 - mWidth) * m;
}
// 全 1
if (e === ((1 << eWidth) - 1)) {
if (m === 0) {
return sign * Infinity;
}
return NaN;
}
return sign * efficentPow2(e - offset) * (1 + m / mFrac);
}
}
export class JSValueRender {
/**
*
* @param {string} link 信号的ID
* @param {number} width 信号的位置宽度
* @param {string} replacer 位置不足的地方会用 replacer 补足,比如 ...
*/
constructor(link, width) {
this.formatCode = getValueFormatCode(link);
this.width = BigInt(width);
}
/**
* @description 根据当前的设置进行数值的渲染
* @param {number} value 波形当前的数值
* @returns {string} 转换后需要渲染的字符串
*/
explainAsNumber(value) {
const formatCode = this.formatCode;
switch (formatCode) {
// 二进制
case 0: return this.radixTransform(2, value);
// 八进制
case 1: return this.radixTransform(8, value);
// 十六进制
case 2: return this.radixTransform(16, value);
// 有符号整型
case 3: return this.radixTransform(10, value, true);
// 无符号整型
case 4: return this.radixTransform(10, value);
// 半精度浮点数
case 5: return this.floatTransform(16, value);
// 单精度浮点数
case 6: return this.floatTransform(32, value);
// 双精度浮点数
case 7: return this.floatTransform(64, value);
// 未知
default: return '?';
}
}
/**
* @description 整数的进制转换
* @param {number} radix 进制
* @param {number} value 值
* @param {number} pos 位置宽度
* @param {boolean} sign 是否是有符号数,默认为 false
*/
radixTransform(radix, value, sign = false) {
const width = this.width;
const replacer = this.replacer;
switch (value) {
case 'x':
return -1;
break;
case '?':
return -1;
break;
default:
value = BigInt(value);
break;
}
// 如果是有符号数
if (sign) {
if ((value >> (width - 1n)) & 1n) {
value = value - (2n ** width);
}
return parseInt(value);
}
// 无符号的各类进制数字
return parseInt(value);
}
/**
* @description IEEE 浮点数的转换
* 为什么没有 sign 参数?因为 IEEE 定义下的 float 第一个位置就是符号
* @param {number} fWidth 16 32 或者 64
* @param {number} value 值
* @param {number} pos 位置
*/
floatTransform(fWidth, value) {
const replacer = this.replacer;
if (fWidth === 16) {
value = this.calcIEEEFloat(value, 5, 10);
} else if (fWidth === 32) {
value = this.calcIEEEFloat(value, 8, 23);
} else if (fWidth === 64) {
value = this.calcIEEEFloat(value, 11, 52);
}
return value;
}
/**
* @description 根据 e 和 m 得到计算 IEEE 浮点数的函数,默认第一个位置代表符号
* @param {number} value 值
* @param {number} eWidth 代表指数部分的位数
* @param {number} mWidth 代表有效尾数的位数
* @returns {(value: number) => number}
*/
calcIEEEFloat(value, eWidth, mWidth) {
const offset = (1 << (eWidth - 1)) - 1;
const mFrac = 1 << mWidth;
// 计算参考博客https://blog.csdn.net/leo0308/article/details/117398166
let bits = value.toString(2);
const width = 1 + eWidth + mWidth;
// 应对 bits 长度和 预定长度不一致的情况
// 不足的地方补上 0否则进行截断
if (bits.length < width) {
bits = '0'.repeat(width - bits.length) + bits;
}
if (bits.length > width) {
bits = bits.substring(bits.length - width);
}
const s = parseInt(bits[0], 2);
const e = parseInt(bits.substring(1, 1 + eWidth), 2);
const m = parseInt(bits.substring(2 + eWidth), 2);
const sign = (s === 1) ? -1 : 1;
// 全 0
if (e === 0) {
return sign * efficentPow2(-offset + 1 - mWidth) * m;
}
// 全 1
if (e === ((1 << eWidth) - 1)) {
if (m === 0) {
return sign * Infinity;
}
return NaN;
}
return sign * efficentPow2(e - offset) * (1 + m / mFrac);
}
}