:幀結(jié)構(gòu)、ASDU 類型與調(diào)試排錯指南)
簡介這份資料聚焦電力系統(tǒng) IEC-104 規(guī)約的報文解析面向從事電力自動化、SCADA 通信開發(fā)與調(diào)試的工程師及初學(xué)者。內(nèi)容圍繞常用報文類型展開逐字節(jié)說明其作用與含義幫助讀者在開發(fā)中快速定位問題、理解報文規(guī)則減少反復(fù)查閱標(biāo)準(zhǔn)文檔的時間成本。資源包共 11 個文件約 838KB包含 PDF 文檔與 HTML 頁面兩種瀏覽方式輔以 js 腳本、字體圖標(biāo)及樣式文件可直接打開 index.html 在瀏覽器中查看也可閱讀 PDF 版本。目前已有 8257 人學(xué)習(xí)下載說明其在電力通信領(lǐng)域具有較高的參考價值。讀者可借此掌握 104 報文的幀結(jié)構(gòu)、類型標(biāo)識與傳輸原因等關(guān)鍵知識點(diǎn)形成從報文捕獲到含義解讀的完整認(rèn)知適合作為日常開發(fā)調(diào)試的速查手冊與入門學(xué)習(xí)材料。1. 為什么一張 IEC-104 報文表能省掉半天抓包很多做電力自動化的工程師第一次接觸 104 規(guī)約都是在變電站后臺和主站對不上點(diǎn)的時候。抓包工具里刷出一屏68開頭的十六進(jìn)制盯著68 0E 00 00 00 00 46 01 03 00 01 00 00 00 00這種串完全不知道從哪看起。IEC-104 本質(zhì)是 IEC-60870-5-101 的 TCP/IP 封裝版本把串口上的 FT1.2 幀塞進(jìn) TCP 載荷用 APCI 做鏈路控制、ASDU 做業(yè)務(wù)數(shù)據(jù)。它跑在 2404 端口一個連接就是一條鏈路主站是控制方RTU 或測控裝置是被控方。真正讓人頭疼的不是協(xié)議本身而是報文類型太多總召喚、遙測、遙信、遙控、時鐘同步、電度召喚每種 ASDU 的類型標(biāo)識TypeID不同信息對象地址IOA的編排規(guī)則也不同。手里有一份按類型整理好的報文詳解配合抓包對照定位問題的時間能從半天壓到十幾分鐘。這篇內(nèi)容適合剛接手 104 調(diào)試的自動化工程師、做規(guī)約測試的軟件開發(fā)者以及需要寫 104 主站或從站模擬程序的人。2. IEC-104 幀結(jié)構(gòu)與 APCI 鏈路層報文拆解2.1 三種幀格式的判別方法104 的 APCI 只有 6 個字節(jié)但三種幀格式的區(qū)分全在這 6 個字節(jié)里。第一個字節(jié)固定是0x68第二個字節(jié)是 APDU 長度不含啟動符和長度字節(jié)本身。關(guān)鍵看第 3、4 字節(jié)的控制域幀類型控制域第 1 字節(jié)特征用途典型報文I 格式bit0 0傳輸 ASDU 數(shù)據(jù)68 0E 00 00 00 00 64 01 06 00 01 00 00 00 00 14S 格式bit01, bit10確認(rèn)收到 I 幀68 04 01 00 00 00U 格式bit01, bit11鏈路啟停、測試68 04 07 00 00 00STARTDT act判別順序很簡單先看控制域第一字節(jié)最低位為 0 就是 I 幀為 1 再看次低位為 0 是 S 幀為 1 是 U 幀。U 幀的六種功能碼STARTDT、STOPDT、TESTFR 的 act/confirm都落在控制域第一字節(jié)的高 6 位。2.2 用 Python 解析 APCI 頭部抓包拿到的原始字節(jié)流第一步就是把 APCI 剝出來。下面這段代碼處理 TCP 流里粘包的情況按長度字段切分 APDUimport struct def parse_apci(data: bytes): 解析 IEC-104 APCI 頭部返回幀類型和控制域信息 frames [] offset 0 while offset len(data): if data[offset] ! 0x68: offset 1 continue length data[offset 1] apdu data[offset: offset 2 length] if len(apdu) 2 length: break # 半包等下次數(shù)據(jù) ctrl1 apdu[2] if ctrl1 0x01 0: ftype I send_seq (apdu[2] | (apdu[3] 8)) 1 recv_seq (apdu[4] | (apdu[5] 8)) 1 info {type: ftype, tx: send_seq, rx: recv_seq, asdu: apdu[6:]} elif ctrl1 0x03 0x01: info {type: S, rx: (apdu[4] | (apdu[5] 8)) 1} else: info {type: U, func: ctrl1 0xFC} frames.append(info) offset 2 length return frameslength字段只統(tǒng)計控制域加 ASDU 的字節(jié)數(shù)不含啟動符和它自己所以切片時是2 length。I 幀的發(fā)送序號和接收序號各占 15 位低字節(jié)在前右移一位去掉格式位。U 幀的功能碼用ctrl1 0xFC取出高 6 位0x07是 STARTDT act0x0B是 STARTDT con0x13是 STOPDT act0x23是 STOPDT con0x43是 TESTFR act0x83是 TESTFR con。2.3 鏈路建立與序號確認(rèn)機(jī)制鏈路剛連上時雙方都處于停止?fàn)顟B(tài)主站必須先發(fā)68 04 07 00 00 00請求激活傳輸從站回68 04 0B 00 00 00確認(rèn)后才允許發(fā) I 幀。這個握手不做后面所有總召喚都會被丟棄這是新手最常見的坑。I 幀的序號是 15 位循環(huán)0 到 32767。發(fā)送方每發(fā)一個 I 幀 tx 加一接收方收到后用自己的 rx 記錄期望的下一個序號。當(dāng)接收方累計收到 8 個 I 幀默認(rèn)參數(shù) k12、w8就要回一個 S 幀確認(rèn)否則發(fā)送方窗口耗盡會停發(fā)。調(diào)試時如果看到 I 幀發(fā)到某個序號后卡住先查 S 幀有沒有正?;?。提示k 和 w 是可配置參數(shù)k 是發(fā)送方未確認(rèn) I 幀的最大數(shù)量w 是收到多少個 I 幀后必須發(fā) S 幀確認(rèn)。不同廠家默認(rèn)值可能不同對接前先確認(rèn)。3. ASDU 類型標(biāo)識與常用報文實戰(zhàn)解析3.1 總召喚與遙測遙信上送總召喚是調(diào)試時第一個要跑通的流程。主站發(fā)類型標(biāo)識 100C_IC_NA_1的 ASDU從站回 100 確認(rèn)然后依次上送類型 1單點(diǎn)遙信、9歸一化遙測、11標(biāo)度化遙測、13短浮點(diǎn)遙測最后再發(fā)一個 100 表示總召喚結(jié)束。一條典型的單點(diǎn)遙信報文68 0E 00 00 00 00 01 01 03 00 01 00 00 00 00 00。拆開看01是 TypeID單點(diǎn)信息01是可變結(jié)構(gòu)限定詞VSQ高 1 位表示是否連續(xù)低 7 位是信息對象個數(shù)這里 1 個03是傳送原因3 表示突發(fā)spontaneous00 01是公共地址00 01 00是信息對象地址 IOA最后一個00是遙信值bit0 表示分合。歸一化遙測的 TypeID 是 9值是兩個字節(jié)的有符號數(shù)實際工程值 原始值 × 系數(shù)。短浮點(diǎn)遙測 TypeID 是 13值占 4 字節(jié)IEEE 754 格式直接struct.unpack(f, ...)就能還原。3.2 遙控與時鐘同步報文遙控分四步選擇、選擇確認(rèn)、執(zhí)行、執(zhí)行確認(rèn)。TypeID 是 45C_SC_NA_1 單點(diǎn)遙控或 46C_DC_NA_1 雙點(diǎn)遙控。選擇和執(zhí)行靠傳送原因區(qū)分6 是激活7 是激活確認(rèn)8 是停止激活10 是激活終止。def build_control_cmd(ioa: int, value: bool, select: bool): 構(gòu)造單點(diǎn)遙控 ASDUselectTrue 為選擇False 為執(zhí)行 type_id 45 vsq 0x01 cot 6 if select else 6 # 激活 ca struct.pack(H, 1) ioa_bytes struct.pack(I, ioa)[:3] sco (0x01 if value else 0x00) | (0x80 if select else 0x00) asdu bytes([type_id, vsq, cot]) ca ioa_bytes bytes([sco]) apci bytes([0x68, len(asdu) 4, 0x00, 0x00, 0x00, 0x00]) return apci asduSCO 字節(jié)的 bit7 是選擇/執(zhí)行標(biāo)志1 為選擇0 為執(zhí)行bit0 是合分閘1 為合。時鐘同步用 TypeID 103C_CS_NA_1ASDU 里帶 7 字節(jié) CP56Time2a 時間前兩字節(jié)是毫秒后面依次是分、時、日、月、年。3.3 傳送原因與公共地址的對應(yīng)關(guān)系傳送原因COT是排查問題的關(guān)鍵字段常見值如下COT 值含義典型場景3突發(fā)遙信變位主動上送5被請求響應(yīng)總召喚6激活主站下發(fā)命令7激活確認(rèn)從站確認(rèn)收到命令10激活終止命令執(zhí)行完成20響應(yīng)站召喚總召喚數(shù)據(jù)公共地址CA一般 2 字節(jié)標(biāo)識不同的 RTU 或裝置。如果主站收到數(shù)據(jù)但點(diǎn)表對不上先核對 CA 和 IOA 是否和點(diǎn)表一致這兩個字段錯一個數(shù)據(jù)就映射到別的點(diǎn)位上。4. 104 報文調(diào)試排錯與性能優(yōu)化技巧4.1 常見異常報文定位鏈路建不起來先看 STARTDT 有沒有回 confirm。如果主站發(fā)了68 04 07 00 00 00但從站沒回68 04 0B 00 00 00檢查從站是否配置了允許建立連接、端口是否被占用、防火墻是否放行 2404??傉賳境瑫r看從站有沒有回類型 100 的激活確認(rèn)。如果確認(rèn)回了但數(shù)據(jù)不上送多半是點(diǎn)表配置為空或 IOA 越界。遙控失敗重點(diǎn)看選擇確認(rèn)和執(zhí)行確認(rèn)的 COT 是不是 7如果從站回的是否定確認(rèn)COT47說明命令被拒絕查遙控閉鎖或權(quán)限配置。序號錯亂是另一個高頻問題。如果主站收到的 I 幀 rx 序號和本地期望的不一致說明有丟包或重復(fù)。104 本身不帶重傳靠 TCP 保證可靠但 TCP 斷開重連后序號會重置主站必須重新發(fā) STARTDT。4.2 用 tcpdump 和 Wireshark 過濾 104 流量現(xiàn)場沒有專用工具時tcpdump 加 Wireshark 是最快的組合。在裝置側(cè)抓包# 抓取 2404 端口流量保存為 pcap 供 Wireshark 分析 tcpdump -i eth0 -w iec104.pcap tcp port 2404 # 實時查看 104 報文十六進(jìn)制 tcpdump -i eth0 -X tcp port 2404 and tcp[13] 8 ! 0第一條命令把流量存下來Wireshark 打開后直接能識別 IEC 60870-5-104 協(xié)議自動解析出 TypeID、COT、IOA。第二條只抓 PSH 標(biāo)志置位的包過濾掉純 ACK減少噪音。Wireshark 里可以用iec60870_asdu.typeid 100這樣的過濾器只看總召喚。4.3 批量測試與參數(shù)調(diào)優(yōu)做規(guī)約測試時經(jīng)常需要模擬從站批量上送數(shù)據(jù)。用 Python 起一個簡易從站循環(huán)構(gòu)造遙測幀import socket, time, struct def send_measure(sock, ioa, value): 發(fā)送短浮點(diǎn)遙測TypeID13 asdu bytes([13, 0x01, 0x03]) struct.pack(H, 1) asdu struct.pack(I, ioa)[:3] asdu struct.pack(f, value) bytes([0]) apci bytes([0x68, len(asdu) 4, 0x00, 0x00, 0x00, 0x00]) sock.send(apci asdu) s socket.create_connection((127.0.0.1, 2404)) for i in range(100): send_measure(s, 0x4001 i, 220.5 i * 0.1) time.sleep(0.05)struct.pack(f, value)把浮點(diǎn)數(shù)轉(zhuǎn)成 4 字節(jié)小端IOA 取 3 字節(jié)。批量發(fā)送時注意 k 窗口發(fā)太快會觸發(fā)流控實際測試中每發(fā) 8 幀插一個 S 幀確認(rèn)更穩(wěn)。參數(shù)調(diào)優(yōu)上k 值調(diào)大能提高吞吐但增加內(nèi)存占用w 值調(diào)小確認(rèn)更及時但增加網(wǎng)絡(luò)開銷一般保持默認(rèn)即可除非鏈路質(zhì)量差需要調(diào)整。注意模擬從站時公共地址和 IOA 必須和主站點(diǎn)表嚴(yán)格對應(yīng)否則主站會丟棄或映射錯誤。測試前先導(dǎo)出點(diǎn)表核對一遍。本文還有配套的精品資源點(diǎn)擊獲取