2026年1月15日 星期四

RFID Reader-driven Polling(輪詢協議)

 

在 RFID 領域中,Reader-driven Polling(輪詢協議)是最基礎且直覺的存取方法。

Polling 是由讀取器(Reader)依序點名每一個已知的標籤(Tag)。

在業界常見的場景中,這通常用於讀取器已經擁有「標籤白名單」的情況,或者是在確定性要求極高的工業自動化環境中。

RFID Polling Protocol 模擬器實作

這個程式模擬讀取器按照列表順序發送「查詢指令」,標籤收到後給予「應答(ACK)」。


Polling 模式的核心原理

  1. 無碰撞(No Collision): 與 ALOHA 不同,Polling 由讀取器嚴格控制「誰該說話」。在模擬器中,你可以看到讀取器一次只會與一條虛線(連線)互動,這消除了標籤同時發送訊號導致的衝突。

  2. 確定性(Deterministic): 讀取器知道它要讀取哪些標籤。這在自動化倉儲(例如輸送帶上的五個固定位置)非常有用,因為讀取器可以精確計算掃描完所有標籤所需的時間。

  3. 主要缺點: 如果環境中有「新出現」的標籤(不在名單內),Polling 模式將無法發現它。這就是為什麼現代 RFID 協議(如 EPC Gen2)通常結合了 Slotted ALOHA 來發現新標籤,再用 Polling/Query 來讀取詳細資料。



import tkinter as tk
from tkinter import ttk
import time
from threading import Thread

class RFIDPollingSimulator:
    def __init__(self, root):
        self.root = root
        self.root.title("RFID Reader-Driven Polling 模擬器")
        
        # 預設標籤庫 (模擬 Reader 擁有的清單)
        self.tag_inventory = {
            "TAG-001": {"status": "Waiting", "data": "Sensor_Data_A"},
            "TAG-002": {"status": "Waiting", "data": "Sensor_Data_B"},
            "TAG-003": {"status": "Waiting", "data": "Sensor_Data_C"},
            "TAG-004": {"status": "Waiting", "data": "Sensor_Data_D"}
        }
        
        self.is_running = False
        self.current_polling_idx = -1
        self.step_mode = tk.BooleanVar(value=True)
        self.step_trigger = False
        
        self.setup_ui()

    def setup_ui(self):
        # 頂部控制區
        ctrl_frame = tk.Frame(self.root, padx=10, pady=10)
        ctrl_frame.pack(fill="x")

        self.btn_start = tk.Button(ctrl_frame, text="開始輪詢 (Start Polling)", command=self.start_polling, bg="#e3f2fd")
        self.btn_start.pack(side=tk.LEFT, padx=5)

        tk.Checkbutton(ctrl_frame, text="手動單步執行", variable=self.step_mode).pack(side=tk.LEFT, padx=10)

        self.btn_next = tk.Button(ctrl_frame, text="下一個標籤 >>", command=self.next_step, state=tk.DISABLED)
        self.btn_next.pack(side=tk.LEFT, padx=5)

        # 中間:視覺化展示區
        self.canvas = tk.Canvas(self.root, width=600, height=250, bg="white", highlightthickness=1, highlightbackground="#ddd")
        self.canvas.pack(pady=10, padx=10)
        
        # 繪製 Reader
        self.reader_rect = self.canvas.create_rectangle(220, 20, 380, 60, fill="#1976d2", outline="#0d47a1")
        self.canvas.create_text(300, 40, text="RFID READER", fill="white", font=("Arial", 10, "bold"))
        
        # 繪製標籤與連線
        self.tag_shapes = {}
        self.tag_lines = {}
        tags_keys = list(self.tag_inventory.keys())
        for i, tid in enumerate(tags_keys):
            x = 80 + (i * 140)
            line = self.canvas.create_line(300, 60, x, 160, dash=(4, 4), state=tk.HIDDEN, fill="#aaa")
            tag = self.canvas.create_oval(x-35, 160, x+35, 200, fill="#f5f5f5", outline="#9e9e9e", width=2)
            self.canvas.create_text(x, 180, text=tid, font=("Arial", 9))
            self.tag_shapes[tid] = tag
            self.tag_lines[tid] = line

        # 底部:狀態表格
        self.tree = ttk.Treeview(self.root, columns=("ID", "Status", "Content"), show="headings", height=5)
        self.tree.heading("ID", text="標籤 ID")
        self.tree.heading("Status", text="通訊狀態")
        self.tree.heading("Content", text="回傳資料")
        self.tree.column("ID", width=100)
        self.tree.column("Status", width=150)
        self.tree.pack(fill="x", padx=10, pady=10)
        
        for tid in self.tag_inventory:
            self.tree.insert("", tk.END, iid=tid, values=(tid, "等待中...", "---"))

    def next_step(self):
        self.step_trigger = True

    def start_polling(self):
        if self.is_running: return
        self.is_running = True
        self.btn_start.config(state=tk.DISABLED)
        self.btn_next.config(state=tk.NORMAL if self.step_mode.get() else tk.DISABLED)
        
        # 重設 UI
        for tid in self.tag_inventory:
            self.canvas.itemconfig(self.tag_shapes[tid], fill="#f5f5f5")
            self.canvas.itemconfig(self.tag_lines[tid], state=tk.HIDDEN)
            self.tree.item(tid, values=(tid, "等待中...", "---"))

        Thread(target=self.run_polling_logic, daemon=True).start()

    def run_polling_logic(self):
        tags_keys = list(self.tag_inventory.keys())
        
        for tid in tags_keys:
            if not self.is_running: break

            # 1. 準備查詢
            self.update_ui_node(tid, "querying")
            
            # 手動模式等待
            if self.step_mode.get():
                self.step_trigger = False
                while not self.step_trigger and self.is_running:
                    time.sleep(0.1)
            else:
                time.sleep(1.2)

            # 2. 模擬通訊
            self.update_ui_node(tid, "active")
            time.sleep(0.8)
            
            # 3. 獲取資料
            data = self.tag_inventory[tid]["data"]
            self.update_ui_node(tid, "completed", data)
            time.sleep(0.5)

        self.is_running = False
        self.root.after(0, self.reset_buttons)

    def update_ui_node(self, tid, state, data=None):
        def update():
            if state == "querying":
                self.canvas.itemconfig(self.tag_shapes[tid], fill="#fff9c4") # 黃色:詢問中
                self.tree.item(tid, values=(tid, "正在發送查詢...", "---"))
            elif state == "active":
                self.canvas.itemconfig(self.tag_shapes[tid], fill="#bbdefb") # 藍色:連線中
                self.canvas.itemconfig(self.tag_lines[tid], state=tk.NORMAL, fill="#1976d2")
                self.tree.item(tid, values=(tid, "標籤應答中 (ACK)", "---"))
            elif state == "completed":
                self.canvas.itemconfig(self.tag_shapes[tid], fill="#c8e6c9") # 綠色:完成
                self.canvas.itemconfig(self.tag_lines[tid], fill="#4caf50")
                self.tree.item(tid, values=(tid, "讀取成功", data))
        
        self.root.after(0, update)

    def reset_buttons(self):
        self.btn_start.config(state=tk.NORMAL)
        self.btn_next.config(state=tk.DISABLED)

if __name__ == "__main__":
    root = tk.Tk()
    app = RFIDPollingSimulator(root)
    root.mainloop()

沒有留言:

張貼留言

RFID 系統的Stream Cipher(串流加密)

  RFID 系統的Stream Cipher(串流加密) 在 RFID 系統中,由於標籤(Tag)的運算資源有限,通常會採用 Stream Cipher(串流加密) 。其原理是利用一個「金鑰(Key)」與「初始向量(IV)」生成一段無限長的偽隨機位元流(Key Stream),...