2025年11月7日 星期五

MIFARE 1K 卡片的防衝突與 SAK 判斷流程說明

 MIFARE 1K 卡片的防衝突與 SAK 判斷流程說明

 PDF 文件 (AN10834: MIFARE ISO/IEC 14443 PICC Selection) 詳細描述了符合 ISO/IEC 14443 Type A 標準的卡片(包括 MIFARE 1K)的啟動和選擇流程

1. 防衝突處理 (Anti-collision Procedure)

防衝突是確保在讀卡器 (PCD) 訊號範圍內有多張卡片 (PICC) 時,能夠唯一識別並選擇其中一張卡片的機制

  • 步驟 1:卡片詢問 (Card Polling)

    • 讀卡器 (PCD) 開啟 RF 載波並等待至少 5ms

    • 讀卡器發送 REQA (REQuest type A) 命令,詢問 Type A 卡片是否存在

      若 MIFARE 1K 卡片在場,將回覆 ATQA (Answer To reQuest type A)
  • 步驟 2:防衝突迴圈 (Anti-collision Loop)

    • 一旦收到 ATQA,即進入 **Card Activation(卡片啟動)**程序,其中包含防衝突迴圈

      防衝突程序旨在透過一系列 Select 命令來逐步解析卡片的 UID (Unique Identifier)
    • 此程序會持續進行,直到讀卡器唯一地識別出單一卡片的完整 UID,從而解決多卡衝突(例如,如果多張卡片同時在場)

2. SAK 值判斷流程 (SAK Value Judgment)

在成功完成防衝突迴圈,並透過 SELECT 命令選擇卡片後,卡片會回覆 SAK (Select AcKnowledge)。SAK 值用於指示卡片的類型和能力。

根據 PDF 文件中的 Figure 3(MIFARE Mini, 1K, 4K, UL... Card Activation)所示,MIFARE 1K 卡的判斷流程大致如下(流程圖的詳細位元檢查用於區分不同卡片類型)

  • 目的: 使用 SAK 值將 MIFARE 1K 與 MIFARE Mini、4K、Ultralight 或 ISO/IEC 14443-4 compliant 的卡片清楚地分離和選取

  • SAK 位元檢查:

    1. 檢查 SAK Bit 6(表示是否為 ISO/IEC 14443-4 協議層卡片)。MIFARE Classic 1K 不是 14443-4 卡片,因此此位元通常為 0 (Bit 6 = 0)

      檢查 SAK Bit 2(保留位元,Reserved for future use)。MIFARE 1K 在標準流程中,會遵循 Bit 2=0 的路徑
    2. 接下來會檢查 SAK 的其他位元 (如 Bit 5, Bit 1) 的組合,以準確區分 MIFARE 1KMIFARE 4KMIFARE Mini
  • 結果: 透過這組 SAK 檢查,讀卡器最終確認卡片類型為 MIFARE 1K card selected

  • 後續操作: 一旦確認為 MIFARE 1K,讀卡器通常會繼續執行 應用層相關的命令,例如進行 Authentication (認證) 才能讀取或寫入資料







import tkinter as tk

from tkinter import ttk


class Mifare1KFlowSimulator:

    def __init__(self, master):

        self.master = master

        master.title("MIFARE 1K 卡片選擇流程 (Tkinter 模擬)")


        # 狀態變數

        self.status_text = tk.StringVar()

        self.card_type_text = tk.StringVar()

        self.current_step = 0

        self.total_steps = 4


        # 初始化介面

        self.create_widgets()

        self.reset_flow()


    def create_widgets(self):

        # 標題

        ttk.Label(self.master, text="ISO/IEC 14443-A 卡片選擇流程", font=('Arial', 14, 'bold')).grid(row=0, column=0, columnspan=2, pady=10)

        

        # 狀態顯示 (步驟)

        ttk.Label(self.master, text="當前步驟:", font=('Arial', 10, 'bold')).grid(row=1, column=0, sticky='w', padx=10, pady=5)

        self.status_label = ttk.Label(self.master, textvariable=self.status_text, wraplength=400, justify=tk.LEFT, font=('Arial', 10))

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


        # 結果顯示 (卡片類型/SAK判斷)

        ttk.Label(self.master, text="判斷結果:", font=('Arial', 10, 'bold')).grid(row=2, column=0, sticky='w', padx=10, pady=5)

        self.card_type_label = ttk.Label(self.master, textvariable=self.card_type_text, font=('Arial', 12, 'bold'), foreground='blue')

        self.card_type_label.grid(row=2, column=1, sticky='w', pady=5)

        

        # 操作按鈕

        self.next_button = ttk.Button(self.master, text="執行下一步", command=self.next_step)

        self.next_button.grid(row=3, column=0, pady=10, padx=10, sticky='e')

        

        self.reset_button = ttk.Button(self.master, text="重置流程", command=self.reset_flow)

        self.reset_button.grid(row=3, column=1, pady=10, padx=10, sticky='w')


    def reset_flow(self):

        self.current_step = 0

        self.status_text.set("準備就緒。點擊 '執行下一步' 開始卡片詢問 (REQA)。")

        self.card_type_text.set("---")

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


    def next_step(self):

        self.current_step += 1

        

        if self.current_step == 1:

            # 步驟 1: 卡片詢問 (Polling)

            self.status_text.set(

                f"[步驟 1/{self.total_steps}] 卡片詢問 (Card Polling):\n"

                f"PCD 發送 REQA 命令。MIFARE 1K 回覆 ATQA。\n"

                f"→ 流程:REQA -> ATQA [cite: 507, 530]"

            )

            self.card_type_text.set("收到 ATQA,卡片存在")


        elif self.current_step == 2:

            # 步驟 2: 防衝突迴圈 (Anti-collision Loop)

            self.status_text.set(

                f"[步驟 2/{self.total_steps}] 防衝突迴圈 (Anti-collision Loop):\n"

                f"PCD 通過多次 SELECT 命令解析卡片 UID,從而唯一選擇單一卡片。\n"

                f"→ 流程:完成單卡選擇,準備判斷 SAK [cite: 537, 780]"

            )

            self.card_type_text.set("單卡 UID 確定,等待 SAK 判斷")


        elif self.current_step == 3:

            # 步驟 3: SAK 值判斷 (SAK Judgment)

            self.status_text.set(

                f"[步驟 3/{self.total_steps}] SAK 值判斷 (Select AcKnowledge):\n"

                f"PCD 接收 SAK 值,並依據 SAK 位元組合(如 SAK bit 6=0, SAK bits 1, 5 等)來確認卡片類型。\n"

                f"→ 判斷結果:此卡為 MIFARE Classic 1K "

            )

            self.card_type_text.set("卡片類型:MIFARE 1K 確定")


        elif self.current_step == 4:

            # 步驟 4: 應用程序啟動 (Application Start)

            self.status_text.set(

                f"[步驟 4/{self.total_steps}] 應用程序啟動:\n"

                f"卡片選擇完成。對於 MIFARE 1K,下一步是執行應用層指令,如讀寫前的 **認證 (Authentication)**。\n"

                f"→ 流程完成:可進行資料交易 [cite: 612, 635]"

            )

            self.card_type_text.set("MIFARE 1K 選擇成功,可執行認證!")

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


        else:

            self.status_text.set("流程結束。請點擊 '重置流程' 重新開始。")

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


if __name__ == "__main__":

    root = tk.Tk()

    app = Mifare1KFlowSimulator(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...