• 正文
    • 三、關(guān)于MC協(xié)議的整體實現(xiàn)
  • 相關(guān)推薦
申請入駐 產(chǎn)業(yè)圖譜

python實現(xiàn)MC協(xié)議(SLMP 3E幀)的TCP服務(wù)端(篇二)

2024/12/08
2287
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

python實現(xiàn)MC協(xié)議(SLMP 3E幀)的TCP服務(wù)端是一件稍微麻煩點的事情。它不像modbusTCP那樣,可以使用現(xiàn)成的pymodbus模塊去實現(xiàn)。但是,我們可以根據(jù)協(xié)議幀進行組包,自己去實現(xiàn)幀的格式,而這一切可以基于socket模塊。本文為第二篇。

二、讀寫保持寄存器的完整交互包

# 客戶端發(fā)送(讀) -》
50 00 00 FF FF 03 00 0C 00 10 00 01 04 00 00 00 00 00 A8 05 00
# 《- 服務(wù)端應(yīng)答
D0 00 00 FF FF 03 00 0C 00 00 00 73 00 00 00 00 00 00 00 00 00
# 客戶端發(fā)送(寫) -》
50 00 00 FF FF 03 00 16 00 10 00 01 14 00 00 0A 00 00 A8 05 00 4E 47 00 00 00 00 00 00 00 00
# 《- 服務(wù)端應(yīng)答
D0 00 00 FF FF 03 00 02 00 00 00

1、分析交互包

基于上述交互包,我們查閱官方文檔發(fā)現(xiàn)交互包使用的是二進制代碼。那么,二進制代碼與ASCII代碼有什么區(qū)別呢?

SLMP(Seamless Message Protocol)3E幀有兩種表示方式:二進制格式和ASCII格式。它們的區(qū)別在于數(shù)據(jù)的傳輸方式和呈現(xiàn)形式。

(1)二進制格式

在二進制格式中,SLMP 3E幀中的各個字段(如幀頭、副幀頭、命令碼、數(shù)據(jù)等)以二進制形式直接編碼和傳輸。數(shù)據(jù)在網(wǎng)絡(luò)中以原始的二進制位模式傳輸,這種方式效率較高,適用于網(wǎng)絡(luò)傳輸。二進制格式通常用于實際的網(wǎng)絡(luò)通信中,數(shù)據(jù)以二進制流的形式在網(wǎng)絡(luò)上傳輸。

(2)ASCII格式

在ASCII格式中,SLMP 3E幀中的各個字段被轉(zhuǎn)換成ASCII字符表示。數(shù)據(jù)以ASCII碼的文本形式進行傳輸,每個字節(jié)被轉(zhuǎn)換為兩個ASCII字符(通常是十六進制表示)。ASCII格式通常用于調(diào)試和人機界面中,方便人們查看和理解數(shù)據(jù)。

總的來說,二進制格式適用于機器之間的網(wǎng)絡(luò)通信,而ASCII格式適用于人機交互和調(diào)試過程中的數(shù)據(jù)顯示。選擇哪種格式取決于具體的應(yīng)用場景和需求。

因此,本文實現(xiàn)的是二進制格式,如果你會實現(xiàn)二進制格式,那么你也能實現(xiàn)ASCII格式。

2、讀寫保持寄存器的請求處理

(1)表頭

客戶端的兩個請求,相同部分都為50 00 00 FF FF 03 00,我們姑且稱之為表頭。

(2)讀/寫長度(協(xié)議幀的長度)

0C 00是固定長度(讀的時候報文都是這么長)與16 00 根據(jù)實際長度變化,表示后面數(shù)據(jù)的長度,例如前者,應(yīng)該以00 0C來看長度,表示后面有12個00那樣的長度。

(3)固定值

10 00

(4)讀/寫指令

01 04 / 01 14

(5)讀/寫寄存器地址

00 00 00 00 00 A8 05 00 /??00 00 0A 00 00 A8 05 00,其中寫的0A 00代表從第10個保持寄存器,05表示讀寫5個寄存器

3、讀寫保持寄存器的響應(yīng)處理

(1)表頭

客戶端的兩個請求,相同部分都為D0 00 00 FF FF 03 00,我們姑且稱之為表頭。

(2)長度(協(xié)議幀的長度)

讀:0C 00根據(jù)實際長度變化,寫:02 00 可以不變化。

(3)固定值

00 00

(4)讀/寫響應(yīng)

響應(yīng)實際讀到的數(shù)據(jù)?/ 無

4、程序設(shè)計

根據(jù)上述內(nèi)容,實現(xiàn)了一個定制MC服務(wù)器,能夠處理保持寄存器的讀寫請求,給出正確的響應(yīng)。

import socket
import struct

# 創(chuàng)建一個TCP/IP套接字
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 綁定套接字到特定地址和端口
server_address = ('192.168.1.188', 12345)  # 服務(wù)器地址和端口
server_socket.bind(server_address)

# 監(jiān)聽連接
server_socket.listen(1)

print('等待客戶端連接...')
connection, client_address = server_socket.accept()

print('客戶端已連接:', client_address)

def request_verdict(req_bytes_frame):  # req_bytes_frame是字節(jié)數(shù)據(jù)b'x02x00x08x00x00x00x00x00x10x00x01x01x02x03x04x03'
    command = req_bytes_frame.hex()[22:26]  # 轉(zhuǎn)成16進制字符串好數(shù)據(jù)處理
    if command in ["0104", "0401"]:  # 判斷讀寫
        return False # 讀
    elif command in ["0114", "1401"]:
        return True  # 寫
    else:
        raise ValueError("讀寫指令錯誤!")

def write_response_frame(req_bytes_frame):
    response = "D00000FFFF030002000000"  # 寫成功則返回這一串?dāng)?shù)據(jù)
    content = req_bytes_frame.hex()[42:]  # 看一下客戶端想寫的內(nèi)容
    print("客戶端想要寫入的內(nèi)容:", bytes.fromhex(content).decode())
    return bytes().fromhex(response)

def read_response_frame(req_bytes_frame, res_data):
    header = "D00000FFFF03000C000000"  # 讀的響應(yīng)頭
    nums = req_bytes_frame.hex()[38:42]  # 獲取客戶端想要讀的寄存器個數(shù)
    act_nums_hex = nums[2:] + nums[:2]  # 涉及大端序和小端序,需要轉(zhuǎn)一下
    act_nums = int(act_nums_hex, 16)  # 得到實際數(shù)量
    res_data_hex = ''.join([hex(ord(c))[2:].zfill(2) for c in res_data])  # 將要返回的數(shù)據(jù)轉(zhuǎn)成16進制字符串
    response = header + res_data_hex + '0'*(act_nums*2*2-len(res_data_hex))  # 根據(jù)請求數(shù)量返回對應(yīng)的內(nèi)容
    return bytes().fromhex(response)

try:
    while True:
        # 接收客戶端請求
        request = connection.recv(1024)
        print("001:", request)
        if request:
            flag = request_verdict(request)
            if flag:  # 響應(yīng)寫
                response = write_response_frame(request)
                print("002:",response)
            else:  # 響應(yīng)讀
                response = read_response_frame(request, "start")
                print("003:",response)
            connection.sendall(response)
finally:
    # 清理連接
    connection.close()

三、關(guān)于MC協(xié)議的整體實現(xiàn)

通過“二”,我們實現(xiàn)了一個基于MC協(xié)議的保持寄存器的讀寫服務(wù)器,但并沒有像pymodbus這種現(xiàn)成模塊那樣完整實現(xiàn),這里探討一下還可以做的事。

1、SLMP 3E幀實現(xiàn)步驟

實現(xiàn)SLMP(Seamless Message Protocol) 3E幀協(xié)議涉及到網(wǎng)絡(luò)通信、數(shù)據(jù)處理、錯誤處理等多個步驟。以下是實現(xiàn)SLMP 3E幀的一般步驟:

(1)建立TCP連接:

在服務(wù)端,監(jiān)聽指定端口(通常是4999)。
在客戶端,連接到服務(wù)端的IP地址和端口。
(2)接收請求:

服務(wù)端接收客戶端發(fā)送的SLMP 3E幀請求。
解析SLMP 3E幀,獲取命令碼、子命令碼、數(shù)據(jù)等信息。
(3)處理請求:

根據(jù)SLMP 3E幀中的命令碼和數(shù)據(jù),執(zhí)行相應(yīng)的操作,如讀取、寫入、控制等。
處理請求可能涉及到對PLC或其他設(shè)備進行讀寫操作,具體實現(xiàn)根據(jù)設(shè)備和應(yīng)用需求而定。
(4)生成響應(yīng):

根據(jù)請求處理的結(jié)果,生成SLMP 3E幀的響應(yīng)數(shù)據(jù)。
設(shè)置響應(yīng)幀的命令碼、子命令碼、數(shù)據(jù)等。
(5)發(fā)送響應(yīng):

將生成的SLMP 3E幀響應(yīng)數(shù)據(jù)發(fā)送回客戶端。
(6)錯誤處理:

在處理請求和生成響應(yīng)的過程中,可能出現(xiàn)各種錯誤,如無效命令、數(shù)據(jù)不合法等。
針對不同的錯誤情況,生成相應(yīng)的錯誤響應(yīng)幀。
(7)關(guān)閉連接:

當(dāng)通信結(jié)束或出現(xiàn)錯誤時,關(guān)閉TCP連接,釋放資源。
請注意,SLMP 3E幀協(xié)議具體的實現(xiàn)步驟和數(shù)據(jù)格式可能因具體設(shè)備和應(yīng)用而有所不同。在實際開發(fā)中,需要參考設(shè)備文檔和SLMP協(xié)議規(guī)范來進行具體的實現(xiàn)。

2、SLMP協(xié)議規(guī)范

查閱三菱PLC關(guān)于SLMP的文檔!

SLMP的詳細規(guī)范通常由設(shè)備廠商提供,以便開發(fā)者能夠正確地使用該協(xié)議與設(shè)備進行通信。規(guī)范文件通常包含SLMP協(xié)議的命令碼、數(shù)據(jù)格式、通信流程、錯誤處理等方面的詳細信息。

3、為什么會有SLMP協(xié)議

SLMP(Seamless Message Protocol)協(xié)議是為了在自動化領(lǐng)域(例如工業(yè)自動化、制造業(yè)、機器人技術(shù)等)中實現(xiàn)設(shè)備之間的無縫通信而設(shè)計的。它提供了一種標準化的通信協(xié)議,使不同廠商、不同類型的設(shè)備能夠在同一個網(wǎng)絡(luò)上進行通信,實現(xiàn)設(shè)備的互聯(lián)互通

在現(xiàn)代工業(yè)自動化系統(tǒng)中,通常涉及到各種各樣的設(shè)備,這些設(shè)備由不同的廠商制造,可能使用不同的通信協(xié)議和數(shù)據(jù)格式。為了實現(xiàn)這些設(shè)備之間的互聯(lián)互通,需要一種通用的、標準化的通信協(xié)議。SLMP就是為了滿足這種需求而被開發(fā)出來的。

SLMP協(xié)議的設(shè)計目標包括:

標準化通信: 提供一種通用的通信協(xié)議,使得不同廠商生產(chǎn)的設(shè)備可以在同一個網(wǎng)絡(luò)上進行通信。

靈活性: 允許不同類型的數(shù)據(jù)(例如狀態(tài)信息、控制命令等)通過同一個協(xié)議進行傳輸。

高效性: 設(shè)計為高效的通信協(xié)議,以滿足工業(yè)自動化系統(tǒng)對實時性和響應(yīng)速度的要求。

易用性: 設(shè)計為易于實現(xiàn)和配置,使得工程師能夠方便地將SLMP協(xié)議集成到他們的設(shè)備和系統(tǒng)中。

綜上所述,SLMP協(xié)議的存在使得不同類型的自動化設(shè)備能夠方便地相互通信,實現(xiàn)了工業(yè)自動化系統(tǒng)的互操作性和靈活性。

4、我是否可以自定義一套協(xié)議

你完全可以自定義一套通信協(xié)議,以滿足特定需求或者應(yīng)用場景。自定義通信協(xié)議通常涉及到以下幾個步驟:

確定通信需求: 首先,你需要明確通信雙方之間需要傳輸哪些數(shù)據(jù),以及數(shù)據(jù)的格式和類型。確定通信的數(shù)據(jù)結(jié)構(gòu)、命令類型、錯誤處理機制等。

選擇傳輸方式: 確定通信采用的傳輸方式,可以是基于串口的通信(例如RS-232、RS-485)、基于網(wǎng)絡(luò)的通信(例如TCP/IP、UDP)、無線通信(例如Wi-Fi、藍牙)等。

制定協(xié)議規(guī)范: 定義協(xié)議的數(shù)據(jù)幀格式,包括幀頭、幀尾、校驗碼等信息。確保通信雙方遵循相同的協(xié)議規(guī)范。

實現(xiàn)協(xié)議解析和封裝 在通信的發(fā)送端和接收端分別實現(xiàn)協(xié)議的封裝和解析邏輯。封裝就是將待發(fā)送的數(shù)據(jù)按照協(xié)議格式組織成數(shù)據(jù)幀,解析則是在接收端將接收到的數(shù)據(jù)幀按照協(xié)議格式解析成可處理的數(shù)據(jù)。

添加錯誤處理和安全性: 考慮數(shù)據(jù)傳輸中可能出現(xiàn)的錯誤情況,設(shè)計相應(yīng)的錯誤處理機制,確保數(shù)據(jù)的完整性和可靠性。如果通信需要保密性,可以考慮加密通信數(shù)據(jù)。

測試和驗證: 在實際環(huán)境中進行測試和驗證,確保自定義協(xié)議能夠正常工作,并且滿足通信需求。

請注意,自定義協(xié)議需要考慮通信的穩(wěn)定性、可靠性和安全性。在設(shè)計過程中,建議參考現(xiàn)有通信協(xié)議的設(shè)計經(jīng)驗,以及相關(guān)領(lǐng)域的最佳實踐。同時,文檔化自定義協(xié)議的規(guī)范,以便未來的維護和擴展。

相關(guān)推薦