「規格書我們有,但廠商說沒有 SDK,你們能接嗎?」
這句話不是特例。每當門市系統要整合刷卡機、票證機、電子支付端末機,十之八九都是這個起點:一份 PDF、一條 RS-232 線、兩端各自等著對話。
序列埠協定整合是台灣門市 IT 的日常,卻幾乎沒有可查的公開技術文章。業界的知識全靠口耳相傳,或是下一個人重踩前一個人踩過的坑。這篇文章想做一件事:把這些坑寫出來。
我們最近完成了中華電信多元支付端末機與門市 POS 的 RS-232 串接——協定層實作、驗收工具建置、39 項驗收全數通過,加上一份 1,126 行的開發規格書,全部在單一工作日內完成。過程中從實機打出的電文裡整理出四個原廠規格書上查不到的細節。這篇文章的主體,就是那四件事,以及整個協定層怎麼設計。
序列埠協定的基本結構,以及它為什麼不能靠直覺做 #
RS-232 的物理層很簡單:一條線、一個 COM port、固定的 baud rate、資料位元、停止位元、奇偶校驗。但這個簡單的物理層上面跑的應用協定,每家廠商都有自己的設計,格式不互通,文件品質也參差不齊。
典型的刷卡機協定封包長這樣:
STX | 資料欄位 | ETX | LRC
STX(0x02)是封包開始,ETX(0x03)是結束,LRC 是縱向冗餘校驗碼,計算方式通常是把 STX 之後、ETX 之前所有位元組做 XOR,再 XOR 上 ETX。
光是這個基本結構,就有三個地方容易踩:
一、LRC 的計算範圍。有些規格書寫「含 ETX」,有些寫「不含 ETX」,有些圖示和文字描述互相矛盾。兩種算出來的值不同,卡機會直接回 NAK,你看到的只是「校驗碼錯」,不會告訴你哪邊多算或少算了一個位元組。
二、資料欄位的長度標記。部分協定在 STX 之後有一個 2-byte 或 4-byte 的長度欄位,標記「接下來有幾個位元組」。問題是:這個長度是「含 ETX」還是「不含 ETX」?「含 LRC」還是「不含 LRC」?規格書如果只說「Data Length」而不加說明,就必須從實機抓包反推。
三、欄位分隔符的處理。資料欄位內通常有多個子欄位,以特定分隔符(常見 0x1C 或固定長度填補)區隔。固定長度的設計看起來簡單,但「不足時用什麼填補」「是否允許全空」這兩件事幾乎不會被明確說明。
這三件事在規格書上多半能找到答案,只是要仔細讀、反覆比對圖示與文字。真正麻煩的,是規格書上根本找不到的部分。
ACK / NAK 狀態機:比規格書畫的更複雜 #
刷卡機協定是主從架構:POS 發送指令,卡機執行後回應。每一個交換週期的基本流程是:
- POS 送出封包
- 卡機驗證封包格式與校驗碼,送 ACK(0x06)或 NAK(0x15)
- POS 收到 ACK 後等待卡機的完整回應封包
- POS 驗證回應封包,送 ACK 確認收到
聽起來清晰,但狀態機設計的難點在邊界:
逾時要分兩段。第一段是「送出封包後等 ACK」的逾時,通常很短(數秒)。第二段是「收到 ACK 後等完整回應」的逾時,可能很長——持卡人在刷卡機前輸 PIN 碼的時間,加上通訊傳輸,可能超過 60 秒。這兩段逾時如果用同一個計時器,幾乎一定會在某個測試情境下出問題。
NAK 重送的上限必須是有限次。收到 NAK 可以重送,但要設上限。到達上限後,不能假設「卡機已處理」或「卡機未處理」——交易狀態是不明確的,必須有一個明確的不明態回報機制,讓上層應用決定下一步(通常是要求操作員確認)。
逾時與 NAK 是不同的失敗類型。逾時代表「我沒收到任何回應」;NAK 代表「卡機收到了但格式有問題」。這兩者的錯誤碼、後續處理邏輯、以及要不要重送,都應該分開設計,不能合併成一個「通訊失敗」就收尾。
規格書通常只畫正常路徑,偶爾提到一層重送,極少說清楚「到底哪種失敗算交易成立、哪種算交易取消」。這部分幾乎是每次串接都要自己設計的。
四個規格書上查不到、只有真機才知道的細節 #
這是這篇文章最核心的部分。以下四點全部來自實機測試,對照規格書前後找不到對應說明,事後整理成回饋文件回報給原廠。
第一:版本查詢指令的回應行為
規格書定義了一個版本查詢的交易型態。理論上,這是最安全的「熱身」指令——不涉及金流,只是確認通訊暢通。
但實機測試發現,版本查詢在某個特定韌體版本下,回應碼不是規格書定義的成功代碼,而是一個通常代表「格式錯誤」的代碼。換言之:封包格式完全正確、校驗碼也對,但回應告訴你「有問題」。
反覆驗證後確認:這是卡機端的已知行為,不是我們的封包有誤。正確處理方式是特判這個組合(特定交易型態 + 特定回應碼),視為版本查詢成功,繼續後續流程。
這件事的危險性:如果你沒做熱身測試,或熱身測試成功後直接上正式交易,永遠不會撞到這個邊界。等到真正部署後、某個版本的韌體更新觸發了這個行為,你只會看到「通訊失敗」,不知道問題出在哪。
第二:逾時回應碼的實際值
規格書定義了逾時時的回應碼。但實機打出來的值與規格書所寫不一致。
這直接影響應用層的判斷邏輯:如果你照規格書的值判斷「這是逾時」,實機回來的代碼不在預期清單裡,應用層可能把它歸進「交易狀態不明」,而非正確識別為「持卡人超時未操作,交易自動取消」。
兩種判斷的後果天差地遠。前者需要人工確認;後者可以自動重試或提示持卡人重新操作。
第三:自我測試腳本的 Host ID 定義
規格書的不同章節對「自我測試」所使用的 Host ID 有不同描述,且兩者互相矛盾。
自我測試是驗收流程的標準項目,如果 Host ID 填錯,卡機會拒絕執行,你會以為是通訊問題或格式問題,花時間排查根本不存在的 bug。
確認正確值的方式只有兩種:問原廠,或逐一試。我們的做法是兩個值都試,記錄哪個值讓測試通過。
第四:逾時容忍範圍的有效邊界
規格書定義了一個參數,可以設定刷卡機等待持卡人操作的逾時秒數,並標注了有效範圍。
實機測試發現,超出有效範圍的值不會被卡機拒絕(回 NAK),而是被靜默修正成邊界值後接受。也就是說:你設了一個你以為是 120 秒的逾時,但卡機實際執行的是 99 秒(假設規格書上界是 99)。
這種「接受但靜默修正」的行為在文件上完全沒有說明。如果你的驗收測試沒有明確驗這個邊界,你不會發現它。上線後的症狀會是「某些交易莫名逾時」,而且只在逾時設定靠近上限時發生。
我們怎麼設計驗收條件清單 #
39 項驗收能夠在一天內全數通過,關鍵不在速度,在方法:先寫清單,再讓清單驅動實作。
驗收清單的設計原則是「每一項都要有可執行的驗證步驟,以及明確的通過定義」。不寫「通訊正常」這種模糊項目,改寫「送出版本查詢封包,在 5 秒內收到 ACK,並在 30 秒內收到完整回應封包,回應碼符合規格書或已知偏差清單」。
驗收項目分幾個維度:
協定層健康:封包格式、校驗碼、逾時邊界、ACK/NAK 各種組合。
正常交易流程:信用卡、電子票證、電子支付等各種支付類型的完整流程,從發起到回應到確認。
異常與邊界:持卡人取消、卡片讀取失敗、逾時未操作、通訊中斷後的狀態確認。
結帳流程:日結、關班等管理型指令,這類指令在主流程驗收中容易被略過,但門市日常一定會用到。
每個項目有三個欄位:步驟、預期結果、實際結果。測試時填入,驗收完成後清單直接成為測試日誌,不需要另外整理文件。
這個「先寫清單再實作」的順序不是細節,是根本做法的差異。先實作再補測試,容易只測試「我知道能通過的路徑」;先寫清單,逼自己想清楚「什麼算通過」,才能在實作前就識別出所有邊界條件。
架構決策:為什麼選擇讓卡機主動觸發關班 #
串接過程中有一個值得記錄的架構取捨。
原本設計是由 POS 在關班時主動送出關班結帳指令給卡機。這個設計在紙上很直覺:收銀員按關班,POS 驅動卡機完成結算,再印出日結報表。
但實測發現,Windows 序列埠在某些負載下有難以預期的延遲。如果 POS 在等待卡機結帳的過程中沒有回應(例如 UI 凍結),收銀員不知道要等還是重試,容易觸發重複關班或跳過結帳。
最終決策是反轉主從關係:關班結帳由卡機端自行觸發,POS 負責接收結果、不介入流程。POS 端的 UI 改為「請在卡機上完成日結後按確認」。
這個選擇損失了自動化的便利性,但換來了更重要的東西:金流路徑不依賴 POS 的存活狀態。即使 POS 當機或 UI 凍結,卡機的結算流程不受影響,帳是對的。
支付系統設計有一條原則:金流路徑越短越可靠。這個決策是它的具體實踐。
為了讓這個改動不只活在程式碼裡,同步更新了門市操作 SOP,確保收銀員的操作預期與程式行為一致。架構決策如果沒有反映在操作文件上,遲早會在輪班交接或新人上線時出問題。
「文件與實機之間的落差」是可以系統化管理的 #
這類串接的瓶頸,從來不是工程量。實作協定層、寫狀態機、跑測試——這些給夠時間都能完成。
真正的瓶頸是:文件與實機之間的落差,要花多少時間填平。
落差有幾種來源:規格書的章節之間互相矛盾、圖示與文字不一致、某個行為只在特定韌體版本才出現、某個參數的邊界行為從未被記錄下來。這些都不是「工程師能力問題」,而是第三方硬體整合的結構性難題。
我們的應對方式有三個層次:
第一層:假設文件不完整,從實機驗證每一個邊界。不只測試正常路徑,對每個有「有效範圍」的參數都測邊界,對每個有多種說法的欄位都逐一驗收。
第二層:把落差記錄成文件。發現的每個「規格書上查不到」的行為,都要寫下來:原本怎麼理解、實機的實際行為是什麼、正確的處理方式是什麼。這份文件的受眾是六個月後維護這段程式碼的人——可能是你自己,可能是別人。
第三層:回饋給原廠。這次的四個細節,我們整理成實測回饋文件回報給中華電信。不只是禮貌,也是讓後續其他整合商不必重踩同樣的坑。
這套工法不限於刷卡機。任何需要對接第三方硬體規格的場合——工廠設備、感測器模組、舊系統遷移——同樣的思路都適用:先建驗收清單,讓清單驅動實作,把落差做成可交接的文件。
結語 #
RS-232 序列埠不是新技術,但它的整合細節幾乎沒有公開的技術沉澱。這種「業界都在做、但沒有人寫出來」的知識空白,正是這篇文章想填的位置。
如果你的團隊正在評估類似的串接——POS 與刷卡機、收銀系統與票證機、任何需要從規格書出發實作協定層的工作——這些方法論都可以直接搬用。有具體問題要討論的,歡迎找我們談。
