A:完成提交

This commit is contained in:
jimmy committed 2025-07-22 18:19:40 +08:00
1 parent 7daac20ddb
commit b93bda3113
4 files changed
+5420

No files matched your search

+461
View File
@@ -0,0 +1,461 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PLC数据转换工具</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
max-width: 1000px;
margin: 0 auto;
padding: 20px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
color: #333;
}
.container {
background: rgba(255, 255, 255, 0.95);
padding: 30px;
border-radius: 20px;
box-shadow: 0 15px 35px rgba(0,0,0,0.1);
backdrop-filter: blur(10px);
}
h1 {
color: #4a5568;
text-align: center;
margin-bottom: 30px;
font-size: 2.2em;
font-weight: 300;
}
.section {
background: #f8fafc;
border-radius: 12px;
padding: 25px;
margin-bottom: 25px;
border: 1px solid #e2e8f0;
transition: all 0.3s ease;
}
.section:hover {
box-shadow: 0 8px 25px rgba(0,0,0,0.1);
transform: translateY(-2px);
}
.section h3 {
color: #2d3748;
margin-bottom: 15px;
font-size: 1.3em;
display: flex;
align-items: center;
gap: 10px;
}
.icon {
width: 24px;
height: 24px;
background: linear-gradient(45deg, #667eea, #764ba2);
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: bold;
}
textarea {
width: 100%;
min-height: 80px;
padding: 15px;
border: 2px solid #e2e8f0;
border-radius: 8px;
font-family: 'Courier New', monospace;
font-size: 14px;
resize: vertical;
transition: border-color 0.3s ease;
}
textarea:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}
button {
background: linear-gradient(45deg, #667eea, #764ba2);
color: white;
border: none;
padding: 12px 24px;
border-radius: 8px;
cursor: pointer;
font-size: 16px;
font-weight: 500;
transition: all 0.3s ease;
margin: 10px 5px;
}
button:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
}
button:active {
transform: translateY(0);
}
.result {
background: linear-gradient(135deg, #e8f5e8, #f0f8ff);
border: 2px solid #48bb78;
border-radius: 8px;
padding: 15px;
margin-top: 15px;
font-family: 'Courier New', monospace;
white-space: pre-wrap;
word-break: break-word;
}
.error {
background: linear-gradient(135deg, #fed7d7, #ffeaea);
border: 2px solid #f56565;
color: #c53030;
}
.explanation {
background: linear-gradient(135deg, #e6fffa, #f0fff4);
border: 2px solid #38b2ac;
border-radius: 8px;
padding: 20px;
margin-top: 20px;
font-size: 14px;
line-height: 1.6;
}
.explanation h4 {
color: #2c7a7b;
margin-bottom: 10px;
}
.byte-order-options {
display: flex;
gap: 15px;
margin: 15px 0;
flex-wrap: wrap;
}
.radio-group {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 15px;
background: white;
border: 2px solid #e2e8f0;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s ease;
}
.radio-group:hover {
border-color: #667eea;
background: #f7fafc;
}
.radio-group input[type="radio"] {
margin: 0;
}
.radio-group.selected {
border-color: #667eea;
background: #eef2ff;
}
.example {
background: rgba(102, 126, 234, 0.1);
border-left: 4px solid #667eea;
padding: 15px;
margin: 15px 0;
border-radius: 0 8px 8px 0;
font-family: 'Courier New', monospace;
font-size: 13px;
}
</style>
</head>
<body>
<div class="container">
<h1>🔧 PLC数据转换工具</h1>
<div class="section">
<h3><span class="icon">📥</span>输入ushort数据</h3>
<textarea id="input" placeholder="请输入读取的ushort数组,用逗号分隔,例如:256,0,256,0,256,0,256,0,256,0">[256,0,256,0,256,0,256,0,256,0]</textarea>
<div>
<h4 style="margin-top: 20px; margin-bottom: 10px;">选择字节序模式:</h4>
<div class="byte-order-options">
<label class="radio-group selected">
<input type="radio" name="byteOrder" value="ABCD" checked>
<span>ABCD (大端序)</span>
</label>
<label class="radio-group">
<input type="radio" name="byteOrder" value="DCBA">
<span>DCBA (小端序)</span>
</label>
<label class="radio-group">
<input type="radio" name="byteOrder" value="BADC">
<span>BADC (混合序1)</span>
</label>
<label class="radio-group">
<input type="radio" name="byteOrder" value="CDAB">
<span>CDAB (混合序2)</span>
</label>
</div>
</div>
<button onclick="convertData()">🔄 转换数据</button>
<button onclick="testAllFormats()">🧪 测试所有格式</button>
<button onclick="clearAll()">🗑️ 清空</button>
</div>
<div class="section">
<h3><span class="icon">📤</span>转换结果</h3>
<div id="result"></div>
</div>
<div class="explanation">
<h4>📚 转换原理说明</h4>
<p><strong>问题分析:</strong></p>
<p>你写入了5个int值[1,1,1,1,1],但读取时得到了10个ushort值[256,0,256,0,256,0,256,0,256,0]。这是因为:</p>
<ul>
<li>每个32位int被拆分成2个16位ushort读取</li>
<li>存在字节序转换问题</li>
<li>256 (0x0100) 表明原本的0x01字节被放在了高位</li>
</ul>
<div class="example">
原始int: 1 (0x00000001)
内存布局: [01][00][00][00] (小端序)
按ushort读取:
- 第1个ushort: [00][01] → 256
- 第2个ushort: [00][00] → 0
</div>
<p><strong>字节序说明:</strong></p>
<ul>
<li><strong>ABCD (大端序):</strong> 高字节在前,低字节在后</li>
<li><strong>DCBA (小端序):</strong> 低字节在前,高字节在后</li>
<li><strong>BADC/CDAB:</strong> 字节对调的混合模式</li>
</ul>
</div>
</div>
<script>
// 更新单选按钮样式
document.querySelectorAll('input[name="byteOrder"]').forEach(radio => {
radio.addEventListener('change', function() {
document.querySelectorAll('.radio-group').forEach(group => {
group.classList.remove('selected');
});
this.closest('.radio-group').classList.add('selected');
});
});
function convertData() {
const input = document.getElementById('input').value.trim();
const byteOrder = document.querySelector('input[name="byteOrder"]:checked').value;
const resultDiv = document.getElementById('result');
try {
// 解析输入数据
let ushortArray;
if (input.startsWith('[') && input.endsWith(']')) {
ushortArray = JSON.parse(input);
} else {
ushortArray = input.split(',').map(x => parseInt(x.trim()));
}
if (ushortArray.length % 2 !== 0) {
throw new Error('ushort数组长度必须是偶数');
}
const intArray = convertUshortToInt(ushortArray, byteOrder);
resultDiv.innerHTML = `<div class="result">
<strong>转换结果:</strong>
原始ushort数组: [${ushortArray.join(', ')}]
转换后的int数组: [${intArray.join(', ')}]
<strong>详细转换过程:</strong>
${getConversionDetails(ushortArray, intArray, byteOrder)}
<strong>验证:</strong>
${verifyConversion(intArray, ushortArray, byteOrder)}
</div>`;
} catch (error) {
resultDiv.innerHTML = `<div class="result error">错误: ${error.message}</div>`;
}
}
function convertUshortToInt(ushortArray, byteOrder) {
const intArray = [];
for (let i = 0; i < ushortArray.length; i += 2) {
const low = ushortArray[i];
const high = ushortArray[i + 1];
let intValue;
switch (byteOrder) {
case 'ABCD': // 大端序:高字在前
intValue = (high << 16) | low;
break;
case 'DCBA': // 小端序:低字在前
intValue = (low << 16) | high;
break;
case 'BADC': // 字节对调1
intValue = ((low & 0xFF) << 24) | (((low >> 8) & 0xFF) << 16) |
((high & 0xFF) << 8) | ((high >> 8) & 0xFF);
break;
case 'CDAB': // 字节对调2
intValue = ((high & 0xFF) << 24) | (((high >> 8) & 0xFF) << 16) |
((low & 0xFF) << 8) | ((low >> 8) & 0xFF);
break;
}
// 处理有符号整数
if (intValue > 0x7FFFFFFF) {
intValue = intValue - 0x100000000;
}
intArray.push(intValue);
}
return intArray;
}
function getConversionDetails(ushortArray, intArray, byteOrder) {
let details = '';
for (let i = 0; i < ushortArray.length; i += 2) {
const low = ushortArray[i];
const high = ushortArray[i + 1];
const intValue = intArray[i / 2];
details += `第${i/2 + 1}个int: ushort[${i}]=${low}(0x${low.toString(16).padStart(4, '0')}), ushort[${i+1}]=${high}(0x${high.toString(16).padStart(4, '0')}) → int=${intValue}(0x${(intValue >>> 0).toString(16).padStart(8, '0')})\n`;
}
return details;
}
function verifyConversion(intArray, originalUshort, byteOrder) {
// 反向验证:将转换后的int再转回ushort看是否匹配
const backToUshort = [];
intArray.forEach(intValue => {
const uintValue = intValue >>> 0; // 转为无符号
switch (byteOrder) {
case 'ABCD':
backToUshort.push(uintValue & 0xFFFF);
backToUshort.push((uintValue >> 16) & 0xFFFF);
break;
case 'DCBA':
backToUshort.push((uintValue >> 16) & 0xFFFF);
backToUshort.push(uintValue & 0xFFFF);
break;
case 'BADC':
const b1 = (uintValue >> 24) & 0xFF;
const b2 = (uintValue >> 16) & 0xFF;
const b3 = (uintValue >> 8) & 0xFF;
const b4 = uintValue & 0xFF;
backToUshort.push((b1 << 8) | b2);
backToUshort.push((b3 << 8) | b4);
break;
case 'CDAB':
const c1 = (uintValue >> 24) & 0xFF;
const c2 = (uintValue >> 16) & 0xFF;
const c3 = (uintValue >> 8) & 0xFF;
const c4 = uintValue & 0xFF;
backToUshort.push((c3 << 8) | c4);
backToUshort.push((c1 << 8) | c2);
break;
}
});
const matches = JSON.stringify(backToUshort) === JSON.stringify(originalUshort);
return `反向转换: [${backToUshort.join(', ')}]\n匹配原始数据: ${matches ? '✅ 是' : '❌ 否'}`;
}
function testAllFormats() {
const input = document.getElementById('input').value.trim();
const resultDiv = document.getElementById('result');
try {
let ushortArray;
if (input.startsWith('[') && input.endsWith(']')) {
ushortArray = JSON.parse(input);
} else {
ushortArray = input.split(',').map(x => parseInt(x.trim()));
}
if (ushortArray.length % 2 !== 0) {
throw new Error('ushort数组长度必须是偶数');
}
let result = '<div class="result"><strong>🧪 所有字节序格式测试结果:</strong>\n\n';
['ABCD', 'DCBA', 'BADC', 'CDAB'].forEach(byteOrder => {
const intArray = convertUshortToInt(ushortArray, byteOrder);
const backToUshort = [];
// 反向验证
intArray.forEach(intValue => {
const uintValue = intValue >>> 0;
switch (byteOrder) {
case 'ABCD':
backToUshort.push(uintValue & 0xFFFF);
backToUshort.push((uintValue >> 16) & 0xFFFF);
break;
case 'DCBA':
backToUshort.push((uintValue >> 16) & 0xFFFF);
backToUshort.push(uintValue & 0xFFFF);
break;
case 'BADC':
const b1 = (uintValue >> 24) & 0xFF;
const b2 = (uintValue >> 16) & 0xFF;
const b3 = (uintValue >> 8) & 0xFF;
const b4 = uintValue & 0xFF;
backToUshort.push((b1 << 8) | b2);
backToUshort.push((b3 << 8) | b4);
break;
case 'CDAB':
const c1 = (uintValue >> 24) & 0xFF;
const c2 = (uintValue >> 16) & 0xFF;
const c3 = (uintValue >> 8) & 0xFF;
const c4 = uintValue & 0xFF;
backToUshort.push((c3 << 8) | c4);
backToUshort.push((c1 << 8) | c2);
break;
}
});
const matches = JSON.stringify(backToUshort) === JSON.stringify(ushortArray);
result += `${byteOrder}格式: [${intArray.join(', ')}] ${matches ? '✅' : '❌'}\n`;
});
result += '</div>';
resultDiv.innerHTML = result;
} catch (error) {
resultDiv.innerHTML = `<div class="result error">错误: ${error.message}</div>`;
}
}
function clearAll() {
document.getElementById('input').value = '';
document.getElementById('result').innerHTML = '';
}
// 页面加载时自动转换示例数据
window.onload = function() {
convertData();
};
</script>
</body>
</html>