💻 Programming — 2026年4月

↩ programming overview

2026-04-07 c pracetice tags:[c]

1. Bitwise Operation (位元運算)

考點分析: SSD Tool 需要頻繁組裝 NVMe Command 或操作硬體 Register。位元運算是絕對的必考題。 常見題目: 請寫出 Macro (巨集) 來 Set (設為1)、Clear (設為0) 以及 Toggle (反轉) 變數 a 的第 n 個 bit。

解答:

#define SET_BIT(a, n)    ((a) |= (1 << (n)))
#define CLEAR_BIT(a, n)  ((a) &= ~(1 << (n)))
#define TOGGLE_BIT(a, n) ((a) ^= (1 << (n)))
#define CHECK_BIT(a, n)  (!!((a) & (1 << (n)))) // 判斷第 n 個 bit 是否為 1

在組裝 NVMe 64 bytes Submission Queue Entry (SQE) 時,經常需要精準操作特定 bit (例如 FUA bit 或 PRP offset),熟練 Bitwise 是開發 Validation Tool 的基本功。


2. Struct Memory Alignment (結構體記憶體對齊)

考點分析: 當上層 Python 透過 ctypes 呼叫底層 C DLL 時,如果兩邊的記憶體對齊 (Padding) 不一致,傳遞的資料結構就會錯位,導致 Segmentation Fault 或硬體拒絕指令。 常見題目: 請問以下 Struct 的 size 是多少?為什麼?如何讓它變成緊密排列 (Packed)?

struct TestStruct {
    char a;
    int b;
    char c;
};

答:Size 在 32/64 bit 系統中通常是 12 bytes (而非 6 bytes)。因為編譯器為了 CPU 讀取效率,會進行 Data Structure Padding (對齊 4 bytes)。

解法 (如何變為 6 bytes):使用 #pragma pack 指令。

#pragma pack(push, 1) // 強制 1 byte 對齊
struct TestStruct {
    char a;
    int b;
    char c;
};
#pragma pack(pop) // 恢復預設對齊

3. Pointer & Memory Management (指標與記憶體管理)

考點分析: 測試軟體常需要配置大區塊的記憶體來模擬 Host 端的 Data Buffer,用來驗證 SSD 的讀寫資料正確性 (Data Comparison)。 常見題目: 指標的加減運算,以及 malloc 後沒有 free 會怎樣?

問:

int *ptr = (int *)malloc(10 * sizeof(int));
ptr++; // ptr 移動了多少 bytes?

解答:ptr 會移動 4 bytes (假設 int 是 4 bytes)。指標的加減是基於其指向的型態大小。


4. volatile 關鍵字的應用

考點分析: 面試官想確認你懂不懂「軟體與硬體交界處」的行為。 常見題目: 什麼是 volatile?在什麼情況下必須使用?

應用場景: 讀取 SSD Controller 的 Hardware Register 狀態,或是 Polling NVMe Completion Queue (CQ) Doorbell 的值。


架構視野展現 (MP Tool 開發模式)

graph TD
    subgraph Host Application
        A[Python / C# UI] -->|ctypes / PInvoke| B(C/C++ DLL Dynamic Library)
    end

    subgraph Middle Layer
        B -->|Struct Parsing & Bitwise| C[NVMe Command Construction]
        C -->|DeviceIoControl| D[Windows NVMe Driver / JMicron Vendor Driver]
    end

    subgraph Hardware Layer
        D -->|PCIe / USB| E[(JMicron Bridge Controller / SSD)]
    end

2026-04-07 PySerial 實戰:UART 通訊與 Deadlock tags:[python]

PySerial 核心觀念與高頻踩坑點 pyserial 本身是執行緒安全 (Thread-safe) 的,意味著你可以從不同的 Thread 同時呼叫 read/write。但「模組安全不代表你的系統設計安全」。Deadlock 通常發生在 I/O 阻塞 (Blocking) 與不當的鎖 (Lock) 競爭。

1. 致命傷:無 Timeout 的 Blocking I/O

import serial
ser = serial.Serial('/dev/tty.usbserial', 115200) # 在 Mac M1 上通常長這樣
data = ser.readline() # 🚨 致命錯誤:如果硬體死機不吐 Log,這行會永久卡死

防禦解法:設定嚴格的 Timeout 機制 永遠不要相信硬體。必須設定 timeout (Read) 與 write_timeout (Write)。

ser = serial.Serial(
    port='/dev/tty.usbserial',
    baudrate=115200,
    timeout=1.0,        # 讀取超時 (秒),時間到就算沒資料也會 return
    write_timeout=1.0   # 寫入超時,防禦硬體 Flow Control (CTS/RTS) 卡死
)

2. 如何徹底避免 Deadlock?

Deadlock 的經典場景:Main Thread 等待 Worker Thread 結束 (join),但 Worker Thread 因為硬體沒回應卡在 ser.read(),且剛好握著某個 threading.Lock 不放,導致全域當機。

防禦架構:非阻塞讀取 (Non-blocking) + Queue 解耦 不要讓主程式直接操作 UART,也不要用單一的 Mutex Lock 去包住 I/O 操作。唯一最佳實踐是:開設一個獨立的 Daemon Thread 專職讀取,並利用 queue.Queue 與主程式溝通。

import serial
import threading
import queue
import time

class UartMonitor:
    def __init__(self, port, baudrate):
        self.ser = serial.Serial(port, baudrate, timeout=0.1)
        self.log_queue = queue.Queue(maxsize=1000)
        self.running = True
        
        # 啟動背景監聽執行緒 (Daemon=True 確保主程式結束時它會自動關閉)
        self.rx_thread = threading.Thread(target=self._read_loop, daemon=True)
        self.rx_thread.start()

    def _read_loop(self):
        while self.running:
            try:
                # 檢查 Buffer 內是否有資料,避免無謂的 read 阻塞
                if self.ser.in_waiting > 0:
                    raw_data = self.ser.read(self.ser.in_waiting)
                    # 放入 Queue,若滿了不會卡死 (timeout 防護)
                    self.log_queue.put(raw_data, timeout=0.1) 
                else:
                    time.sleep(0.01) # 讓出 CPU 資源,避免 100% 佔用
            except Exception as e:
                print(f"UART Error: {e}")
                self.running = False

    def get_logs(self):
        logs = []
        while not self.log_queue.empty():
            logs.append(self.log_queue.get())
        return logs

    def close(self):
        self.running = False
        self.rx_thread.join(timeout=1.0) # 設定 join 的 timeout 避免主執行緒卡死
        self.ser.close()

###3. 系統架構

graph TD
    subgraph Hardware DUT
        A[SSD / Bridge IC] -->|UART TX| B(Serial Port)
    end

    subgraph Python Tool Architecture
        B -->|in_waiting & read| C[Daemon RX Thread]
        C -->|Queue.put| D[(Thread-Safe Queue)]
        
        E[Main Thread / UI] -->|Queue.get| D
        E -->|Regex Analysis| F[Log Parser / Error Detector]
    end
    
    style C fill:#f9f,stroke:#333,stroke-width:2px
    style D fill:#bbf,stroke:#333,stroke-width:2px

2026-04-13 Kivy App Layout tags:[python, kivy]

重點

程式碼片段

# 範例
from kivy.app import App

問題與解法

| 問題 | 解法 | |——|——| | | |


📅 範本區塊

## YYYY-MM-DD 主題 tags:[語言, 主題]

重點

程式碼片段

// code here

問題與解法

| 問題 | 解法 | |——|——| | | |

參考資料

-


↩ programming overview