memory parity error

本文记录了一台HPML350服务器在启动过程中遇到蓝屏错误NMI:ParityCheck/MemoryParityError的问题,通过更换内存、重装系统等尝试后,最终发现是由于阵列卡上的灰尘导致的故障,清洁灰尘后问题得以解决。

一台HP ML350服务器,操作系统为Windows 2003,前一段时间突然在启动过程中蓝屏

报错

NMI: Parity Check / Memory Parity Error

从字面理解以为是内存出问题了,重新插拔内存替换但是无效,重装系统依然报错

奇怪的是隔了一天自己又好了

最近又出现问题,刷新了bios无效,最后发现阵列卡上有很多灰尘,拔下阵列卡吸了灰尘再插上问题解决

看来好多问题不能只从字面理解错误的根源

转载于:https://www.cnblogs.com/dqw3721/archive/2009/05/16/1458137.html

// ========== 功能码映射表 ========== const fcMap = { 1: "读线圈状态 (Read Coils)", 2: "读离散输入 (Read Discrete Inputs)", 3: "读保持寄存器 (Read Holding Registers)", 4: "读输入寄存器 (Read Input Registers)", 5: "写单个线圈 (Write Single Coil)", 6: "写单个寄存器 (Write Single Register)", 15: "写多个线圈 (Write Multiple Coils)", 16: "写多个寄存器 (Write Multiple Registers)" }; // ========== 工具函数 ========== const readAddrQty = (buf) => ({ address: buf.readUInt16BE(0), quantity: buf.readUInt16BE(2) }); function buildParsedFrame(buf) { if (!Buffer.isBuffer(buf) || buf.length < 8) { return { type: "Invalid Frame", raw: buf?.toString("hex") }; } const transactionId = buf.readUInt16BE(0); const protocolId = buf.readUInt16BE(2); const length = buf.readUInt16BE(4); // number of bytes following this field (unitId + pdu) const unitId = buf.readUInt8(6); const functionCode = buf.readUInt8(7); const data = buf.slice(8); const desc = fcMap[functionCode & 0x7F] || "未知功能码"; const isException = (functionCode & 0x80) !== 0; let direction = "Request"; // 默认为请求 let parsed = {}; try { // ======== 判断方向更准确的方式:基于 FC 和数据格式 ========= if (isException) { direction = "Response"; } else { // 对于读命令,响应的数据第一个字节是 byte count if ([1, 2, 3, 4].includes(functionCode & 0x7F)) { if (data.length >= 1 && data[0] === data.length - 1) { direction = "Response"; } } // 写命令的响应通常是 echo 地址+值,长度固定 else if ([5, 6].includes(functionCode)) { if (data.length === 4) direction = "Response"; } // 批量写响应只返回地址和数量(4字节) else if ([15, 16].includes(functionCode)) { if (data.length === 4) direction = "Response"; } } // ======== 异常响应解析 ======== if (isException) { const exceptionCode = data.length > 0 ? data.readUInt8(0) : null; parsed = { direction: "Response", type: "异常响应 (Exception)", exceptionCode, exceptionMsg: getExceptionMessage(exceptionCode) }; } // ======== 请求帧解析 ======== else if (direction === "Request") { switch (functionCode) { case 1: case 2: case 3: case 4: if (data.length >= 4) { const { address, quantity } = readAddrQty(data); // 标准规定 quantity 不能超过 0x7D0 (2000) 等限制可加校验 parsed = { type: desc, address, quantity }; } else { parsed = { type: "Malformed Read Request", raw: data.toString("hex") }; } break; case 5: if (data.length >= 4) { const addr = data.readUInt16BE(0); const val = data.readUInt16BE(2); parsed = { type: desc, address: addr, value: val === 0xFF00 // Modbus 规范要求写线圈时 ON=0xFF00, OFF=0x0000 }; } else { parsed = { type: "Malformed Write Single Coil", raw: data.toString("hex") }; } break; case 6: if (data.length >= 4) { parsed = { type: desc, address: data.readUInt16BE(0), value: data.readUInt16BE(2) }; } else { parsed = { type: "Malformed Write Single Register", raw: data.toString("hex") }; } break; case 15: if (data.length >= 5) { const addr = data.readUInt16BE(0); const qty = data.readUInt16BE(2); const byteCount = data.readUInt8(4); // 数量合法性检查 if (qty === 0 || qty > 1968) { parsed = { type: "Invalid Quantity", quantity: qty, raw: data.toString("hex") }; break; } const expectedBytes = Math.ceil(qty / 8); if (byteCount !== expectedBytes) { parsed = { type: "Byte count mismatch", expected: expectedBytes, actual: byteCount, raw: data.toString("hex") }; break; } if (data.length < 5 + byteCount) { parsed = { type: "Truncated Data", raw: data.toString("hex") }; break; } const values = []; for (let i = 0; i < byteCount; i++) { const b = data[5 + i]; for (let j = 0; j < 8; j++) { if (values.length < qty) { // 注意:低位在前(LSB),即 bit0 是第一个线圈 values.push(Boolean((b >> j) & 1)); } } } parsed = { type: desc, address: addr, quantity: qty, values }; } else { parsed = { type: "Malformed Write Multiple Coils", raw: data.toString("hex") }; } break; case 16: if (data.length >= 5) { const addr = data.readUInt16BE(0); const qty = data.readUInt16BE(2); const byteCount = data.readUInt8(4); if (qty === 0 || qty > 123) { parsed = { type: "Invalid Quantity", quantity: qty, raw: data.toString("hex") }; break; } if (byteCount !== qty * 2) { parsed = { type: "Byte count mismatch", expected: qty * 2, actual: byteCount, raw: data.toString("hex") }; break; } if (data.length < 5 + byteCount) { parsed = { type: "Truncated Data", raw: data.toString("hex") }; break; } const values = []; for (let i = 0; i < qty; i++) { values.push(data.readUInt16BE(5 + i * 2)); } parsed = { type: desc, address: addr, quantity: qty, values }; } else { parsed = { type: "Malformed Write Multiple Registers", raw: data.toString("hex") }; } break; default: parsed = { type: "Unsupported Function Code", functionCode, raw: data.toString("hex") }; } } // ======== 响应帧解析 ======== else if (direction === "Response") { switch (functionCode) { case 1: case 2: if (data.length >= 1) { const byteCount = data.readUInt8(0); if (data.length !== 1 + byteCount) { parsed = { type: "Data length mismatch", raw: data.toString("hex") }; break; } const values = []; for (let i = 0; i < byteCount; i++) { const b = data[1 + i]; for (let j = 0; j < 8; j++) { if (values.length < 2000) { // 安全上限 values.push(Boolean((b >> j) & 1)); // LSB first } } } parsed = { type: `${desc} 响应`, byteCount, values }; } else { parsed = { type: "Malformed Response", raw: data.toString("hex") }; } break; case 3: case 4: if (data.length >= 1) { const byteCount = data.readUInt8(0); if (byteCount % 2 !== 0) { parsed = { type: "Odd byte count in register response", byteCount }; break; } const regCount = byteCount / 2; const values = []; for (let i = 0; i < regCount; i++) { if (1 + i * 2 + 1 < data.length) { values.push(data.readUInt16BE(1 + i * 2)); } } parsed = { type: `${desc} 响应`, byteCount, values }; } else { parsed = { type: "Malformed Response", raw: data.toString("hex") }; } break; case 5: case 6: case 15: case 16: if (data.length === 4) { parsed = { type: `${desc} 响应`, address: data.readUInt16BE(0), quantity: data.readUInt16BE(2) }; } else { parsed = { type: "Malformed Write Response", raw: data.toString("hex") }; } break; default: parsed = { type: "Unknown Response", raw: data.toString("hex") }; } } } catch (err) { parsed = { type: "Parse Error", error: err.message, raw: buf.toString("hex") }; } // ======== MBAP 长度一致性检查 ======== const pduLength = buf.length - 6; // unitId + PDU if (Math.abs(pduLength - length) > 1) { parsed.mbapWarning = `MBAP长度不符 (expected=${length}, actual=${pduLength})`; } // ======== 地址标签映射支持 ======== const map = global.get("modbusMap") || {}; if (parsed.address !== undefined && map[parsed.address]) { parsed.tagName = map[parsed.address]; } return { transactionId, protocolId, length, unitId, functionCode, description: desc, direction, ...parsed }; } // 辅助函数:异常码解释 function getExceptionMessage(code) { const messages = { 1: "Illegal Function", 2: "Illegal Data Address", 3: "Illegal Data Value", 4: "Slave Device Failure", 5: "Acknowledge", 6: "Slave Device Busy", 7: "Negative Acknowledge", 8: "Memory Parity Error", 10: "Gateway Path Unavailable", 11: "Gateway Target Device Failed to Respond" }; return messages[code] || "Unknown Exception"; } // ========== 主逻辑 ========== const buf = msg.payload; if (!Buffer.isBuffer(buf)) { node.warn("Payload is not a Buffer"); return null; } const frames = []; let offset = 0; while (offset < buf.length) { if (offset + 8 > buf.length) { node.warn("Incomplete frame header — waiting for more data"); break; } const len = buf.readUInt16BE(offset + 4); const totalFrameLength = 6 + len; // MBAP (6字节) + 后续内容 const end = offset + totalFrameLength; if (end > buf.length) { node.warn(`Incomplete Modbus frame detected (need ${end - buf.length} more bytes)`); break; } const frame = buf.slice(offset, end); frames.push(buildParsedFrame(frame)); offset = end; } if (frames.length === 0) { node.status({ fill: "red", shape: "dot", text: "No complete frame" }); return null; } node.status({ fill: "green", shape: "dot", text: `${frames.length} frame(s), FC${frames[frames.length - 1]?.functionCode}` }); msg.payload = frames.length === 1 ? frames[0] : frames; return msg; 优化代码并修正错误
最新发布
11-01
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值