Add .bin file parsing details
This commit is contained in:
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
Reference in New Issue
Block a user