Add .bin file parsing details

This commit is contained in:
accusys
2026-03-29 01:17:00 +08:00
parent 482be9db5f
commit 4cdd01202d
+183
View File
@@ -317,3 +317,186 @@ zout.write(byte[] data);
zout.closeEntry(); zout.closeEntry();
zout.close(); zout.close();
``` ```
---
## .bin 檔案解析
### 原始資料格式
控制器回傳的資料包含 **Header + Data**
```
┌─────────────────────────────────────────────┐
│ Controller Response │
├─────────┬───────────────────────────────────┤
│ Offset │ Description │
├─────────┼───────────────────────────────────┤
│ 0-2 │ Total Length (2 bytes) │
│ 3 │ (continuation?) │
│ 4-8 │ Unknown │
│ 9 │ Status (0x50 = Success) │
│ 10-11 │ Unknown │
│ 12 │ Page Code (0x60-0x64) │
│ 13-14 │ 0xFF 0xFF (flag) │
│ 15-18 │ Log Count (4 bytes) │
│ 19-22 │ Start Block (4 bytes) │
│ 23-26 │ Total Blocks (4 bytes) │
├─────────┴───────────────────────────────────┤
│ 15-511 │ Actual Data (496 bytes) │
└─────────┴───────────────────────────────────┘
```
### 寫入 .bin 檔案的程式碼
```java
// 從 reply[15] 開始,寫入 512 bytes
fileOut.write(reply, 15, 512);
```
所以 .bin 檔案內容是:
- **每筆 512 bytes**
- **包含 header 資訊**
### 解析方式
#### 1. 解析 Header
```python
def parse_bin_header(block):
# block 是 512 bytes
status = block[9] # 0x50 = Success
page_code = block[12] # 0x60-0x64
log_count = int.from_bytes(block[15:19], 'little')
start_block = int.from_bytes(block[19:23], 'little')
total_blocks = int.from_bytes(block[23:27], 'little')
data = block[15:] # 實際資料
return {
'status': status,
'page_code': page_code,
'log_count': log_count,
'start_block': start_block,
'total_blocks': total_blocks,
'data': data
}
```
#### 2. 解析各類型 Log
| Page Code | 類型 | 資料格式 |
|-----------|------|----------|
| 0x60 | EventPage.bin | 32 bytes/record |
| 0x61 | DebugPage.bin | 32 bytes/record |
| 0x62 | DiskMetadataPage.bin | 32 bytes/record |
| 0x63 | SpecialLogPage.bin | 48 bytes/record |
| 0x64 | TelMesPages.log | 40 bytes/record (特殊處理) |
#### 3. Python 解析範例
```python
import struct
import datetime
def parse_event_log(data):
"""解析 Event Page (0x60)"""
records = []
for i in range(0, len(data), 32):
if i + 32 > len(data):
break
record = data[i:i+32]
# 解析 timestamp (假設格式)
timestamp = struct.unpack('<I', record[0:4])[0]
event_id = struct.unpack('<H', record[4:6])[0]
message = record[6:].decode('ascii', errors='replace').rstrip('\x00')
records.append({
'timestamp': timestamp,
'event_id': event_id,
'message': message
})
return records
# 使用
with open('EventPage.bin', 'rb') as f:
data = f.read()
events = parse_event_log(data)
for e in events:
print(f"{e['event_id']}: {e['message']}")
```
#### 4. 用 Hexdump 查看
```bash
# 查看前 512 bytes
xxd -l 512 EventPage.bin
# 輸出範例:
00000000: 5001 0000 0000 0000 0000 5001 ff ff 0000 0000 P...........P....
00000010: 0000 0001 0000 0001 0000 0000 0000 0000 ................
00000020: 3031 3233 3435 3637 3839 3031 3233 3435 0123456789012345
00000030: 3637 3839 0000 0000 0000 0000 0000 0000 6789............
...
```
### TelMesPages.log 特殊處理
Page 0x64 有特殊處理:
- 原始:40 bytes/record
- 輸出:去除 null 字元 (0x00)
```java
// 寫入時的處理
for(int j=0; j < logs[i].length()/40; j++) {
for(int k=0; k<40; k++) {
data = (byte)fin.read();
if(data == 0x0a || skipNull == true) {
skipNull = true;
} else {
zout.write(data);
}
}
zout.write(0x0a); // 加上換行
}
```
### Rust 解析範例
```rust
use std::fs::File;
use std::io::Read;
#[derive(Debug)]
struct LogHeader {
status: u8,
page_code: u8,
log_count: u32,
start_block: u32,
total_blocks: u32,
}
fn parse_bin_header(block: &[u8; 512]) -> LogHeader {
LogHeader {
status: block[9],
page_code: block[12],
log_count: u32::from_le_bytes([block[15], block[16], block[17], block[18]]),
start_block: u32::from_le_bytes([block[19], block[20], block[21], block[22]]),
total_blocks: u32::from_le_bytes([block[23], block[24], block[25], block[26]]),
}
}
fn main() {
let mut file = File::open("EventPage.bin").unwrap();
let mut buffer = [0u8; 512];
let mut block_num = 0;
while file.read(&mut buffer).unwrap() > 0 {
let header = parse_bin_header(&buffer);
println!("Block {}: status={:02x}, page={:02x}",
block_num, header.status, header.page_code);
block_num += 1;
}
}
```