2025年10月28日 星期二

循環冗餘檢查法(Cyclic Redundancy Check, CRC)

 循環冗餘檢查法(Cyclic Redundancy Check, CRC)


所謂循環冗餘檢查法(Cyclic Redundancy Check, CRC)是將所要傳送資料的位元串被一個生成多項式(Generator Polynomial)P(x)除,在得到商數和餘數後,把商數忽略,然後將餘數加至傳送資料位元串的最後面,變成一個新的資料位元串再傳送出去。在接收時將此資料位元串被傳送前的生成多項式P(x)除,除完結果若餘數為0,則代表傳送的資料串是正確的,若餘數不為0,則表示傳送資料串有錯誤發生。






import tkinter as tk

from tkinter import ttk, scrolledtext, messagebox


# --- I. CRC 核心計算邏輯 (與前面提供的相同) ---


def xor_operation(a, b):

    """執行二進制字串的互斥或 (XOR) 運算。"""

    result = []

    for bit_a, bit_b in zip(a, b):

        result.append('1' if bit_a != bit_b else '0')

    return "".join(result)


class CRC_Simulator:

    def __init__(self, data_bits, generator_bits):

        self.data_bits = data_bits

        self.generator_bits = generator_bits

        self.k = len(generator_bits)

        self.zeros_to_pad = self.k - 1

        self.dividend = data_bits + '0' * self.zeros_to_pad

        

        # 初始化模擬狀態

        self.current_index = 0

        self.current_remainder = list(self.dividend[:self.k])

        self.max_steps = len(self.dividend) - self.k + 1

        

    def get_initial_info(self):

        """返回初始設定資訊"""

        info = f"✅ 生成多項式 G(x) = {self.generator_bits} (位元數 k = {self.k})\n"

        info += f"✅ 原始資料 (Data): {self.data_bits}\n"

        info += f"✅ 補 {self.zeros_to_pad} 個 0,被除數 (Dividend): {self.dividend}\n"

        info += "----------------------------------------\n"

        return info


    def perform_next_step(self):

        """執行一步 CRC 除法 (XOR 運算)"""

        

        if self.current_index >= self.max_steps:

            return "DONE", f"🌟 最終 CRC 碼 (餘數 Remainder): {''.join(self.current_remainder)}\n🌟 傳送資料 (Data + CRC): {self.data_bits + ''.join(self.current_remainder)}"

        

        i = self.current_index

        current_block_str = "".join(self.current_remainder)

        log_entry = f"步驟 {i+1}:\n"

        log_entry += f"  當前區塊: {current_block_str}\n"


        if self.current_remainder[0] == '1':

            # 首位為 '1',與生成多項式進行 XOR

            division_bits = self.generator_bits

            xor_result = xor_operation(current_block_str, division_bits)

            log_entry += f"  除數 (G(x)): {division_bits}\n"

        else:

            # 首位為 '0',與 00...0 進行 XOR

            division_bits = '0' * self.k

            xor_result = xor_operation(current_block_str, division_bits)

            log_entry += f"  除數 (0...0): {division_bits}\n"


        log_entry += f"  餘數 XOR:    {xor_result}\n"


        # 準備下一輪的餘數:取 XOR 結果的第二位到最後一位

        next_remainder_partial = list(xor_result[1:])

        

        # 從被除數中引入下一個位元 (如果還有)

        if i + self.k < len(self.dividend):

            next_remainder_partial.append(self.dividend[i + self.k])

        

        self.current_remainder = next_remainder_partial

        log_entry += f"  下一區塊:   {''.join(self.current_remainder)}\n"

        log_entry += "----------------------------------------\n"


        self.current_index += 1

        return "STEP", log_entry


# --- II. Tkinter 介面邏輯 ---


class CRC_App:

    def __init__(self, master):

        self.master = master

        master.title("CRC 循環冗餘校驗 - 逐步模擬")


        # 初始化模擬器

        self.simulator = None

        self.is_running = False


        # --- 設定主框架 ---

        main_frame = ttk.Frame(master, padding="10")

        main_frame.pack(fill='both', expand=True)


        # --- 輸入區 ---

        input_frame = ttk.LabelFrame(main_frame, text="輸入參數", padding="10")

        input_frame.pack(fill='x', pady=5)


        # 資料輸入

        ttk.Label(input_frame, text="資料 (Data) 二進制:").grid(row=0, column=0, padx=5, pady=5, sticky='w')

        self.data_entry = ttk.Entry(input_frame, width=30)

        self.data_entry.grid(row=0, column=1, padx=5, pady=5, sticky='w')

        self.data_entry.insert(0, "10101010") # 範例資料


        # 多項式輸入

        ttk.Label(input_frame, text="多項式 (G(x)) 二進制:").grid(row=1, column=0, padx=5, pady=5, sticky='w')

        self.gen_entry = ttk.Entry(input_frame, width=30)

        self.gen_entry.grid(row=1, column=1, padx=5, pady=5, sticky='w')

        self.gen_entry.insert(0, "10111") # 範例多項式 (X^4+X^2+X+1)


        # --- 控制按鈕區 ---

        button_frame = ttk.Frame(main_frame)

        button_frame.pack(fill='x', pady=5)


        self.start_button = ttk.Button(button_frame, text="開始模擬", command=self.start_simulation)

        self.start_button.pack(side='left', padx=5, expand=True)


        self.next_step_button = ttk.Button(button_frame, text="執行下一步驟 (Clock)", command=self.perform_step, state=tk.DISABLED)

        self.next_step_button.pack(side='left', padx=5, expand=True)


        self.reset_button = ttk.Button(button_frame, text="重置", command=self.reset_simulation, state=tk.DISABLED)

        self.reset_button.pack(side='left', padx=5, expand=True)


        # --- 輸出區 (ScrolledText 用於顯示逐步結果) ---

        output_frame = ttk.LabelFrame(main_frame, text="CRC 計算過程輸出", padding="10")

        output_frame.pack(fill='both', expand=True, pady=5)


        self.output_text = scrolledtext.ScrolledText(output_frame, wrap=tk.WORD, width=60, height=20, font=('Consolas', 10))

        self.output_text.pack(fill='both', expand=True)

        self.output_text.insert(tk.END, "請輸入資料和多項式,然後點擊「開始模擬」按鈕。")


    def validate_binary(self, binary_str):

        """驗證輸入是否為非空的二進制字串"""

        if not binary_str:

            return False

        return all(c in '01' for c in binary_str)


    def start_simulation(self):

        """初始化並開始 CRC 模擬"""

        data = self.data_entry.get().strip()

        gen = self.gen_entry.get().strip()

        

        # 輸入驗證

        if not self.validate_binary(data) or not self.validate_binary(gen):

            messagebox.showerror("輸入錯誤", "資料和生成多項式必須是非空且僅包含 0 和 1 的二進制數字。")

            return

        

        if len(data) < len(gen):

            messagebox.showwarning("警告", "通常生成多項式 (G(x)) 的位元數應小於或等於資料位元數。")


        try:

            # 初始化模擬器

            self.simulator = CRC_Simulator(data, gen)

            self.is_running = True

            

            # 更新按鈕狀態

            self.start_button.config(state=tk.DISABLED)

            self.next_step_button.config(state=tk.NORMAL)

            self.reset_button.config(state=tk.NORMAL)

            

            # 清空並顯示初始資訊

            self.output_text.delete(1.0, tk.END)

            self.output_text.insert(tk.END, self.simulator.get_initial_info())

            

        except Exception as e:

            messagebox.showerror("錯誤", f"初始化錯誤: {e}")

            self.reset_simulation()


    def perform_step(self):

        """執行一步 CRC 計算並更新輸出"""

        if not self.is_running or not self.simulator:

            return


        status, log = self.simulator.perform_next_step()

        self.output_text.insert(tk.END, log)

        self.output_text.see(tk.END) # 滾動到最新輸出


        if status == "DONE":

            self.next_step_button.config(state=tk.DISABLED)

            self.is_running = False

            messagebox.showinfo("模擬結束", "CRC 計算完成!請查看輸出結果。")


    def reset_simulation(self):

        """重置所有狀態"""

        self.simulator = None

        self.is_running = False

        

        # 更新按鈕狀態

        self.start_button.config(state=tk.NORMAL)

        self.next_step_button.config(state=tk.DISABLED)

        self.reset_button.config(state=tk.DISABLED)

        

        # 清空輸出

        self.output_text.delete(1.0, tk.END)

        self.output_text.insert(tk.END, "模擬已重置。請輸入新的資料和多項式,然後點擊「開始模擬」。")


if __name__ == "__main__":

    root = tk.Tk()

    app = CRC_App(root)

    root.mainloop()


沒有留言:

張貼留言

ESP32 (ESP-IDF in VS Code) MFRC522 + MQTT + PYTHON TKinter +SQLite

 ESP32 (ESP-IDF in VS Code) MFRC522 + MQTT + PYTHON TKinter +SQLite  ESP32 VS Code 程式 ; PlatformIO Project Configuration File ; ;   Build op...