在完成了前面的工作后,我們就可以實現有針對性的應用了,首先我們來實現Modbus TCP的服務器端應用。當然我們不是做具體的應用,而是對Modbus TCP的服務器端應用進行封裝以供有需要時調用。
這里我們不涉及TCP的協議,這部分與Modbus沒有必然聯系,我們只是在其應用層運行Modbus協議而已。
對於Modbus TCP的服務器我們需要實現幾個功能:首先是對接收到客戶端命令進行解析,我們只實現前面提到的8中常用的功能嗎的支持。其次在解析完成后,我們要實現對應各種功能碼的操作。具體架構如下:
1、命令解析
服務器作為被動端接收到客戶端的請求后,安裝請求進行處理。所以服務器接收到信息后首先對其進行解析,這里我們只需要一個解析函數就可以完成,當在具體應用中時只要將接收到的信息調用這個函數解析就可以了。
/*解析接收到的信息,返回響應命令的長度*/
uint16_t ParsingClientAccessCommand(uint8_t *receivedMessage,uint8_t *respondBytes)
其實對外來說只有這一個函數時可見的。當我們要開發一個TCP Server的應用時,就調用這個函數。
2、命令處理
命令解析出來了之后,按不同的功能碼來進行不同的處理,我們支持8種功能碼,每種功能嗎都對應處理部分,很多時候大家都會在解析的時候根據解析結果處理,這勢必需要一個很大的解析函數。為了簡化操作,我們將每個功能碼對應的處理部分都封裝為一個函數。然后使用一個函數指針數組來動態調用這些函數,從而簡化這些函數。
首先我們需要8個處理對應個功能碼操作的函數:
/*處理讀線圈狀態命令*/
static uint16_t HandleReadCoilStatusCommand(uint16_t startAddress,uint16_t quantity,uint8_t *receivedMessage,uint8_t *respondBytes)
/*處理讀輸入狀態命令*/
static uint16_t HandleReadInputStatusCommand(uint16_t startAddress,uint16_t quantity,uint8_t *receivedMessage,uint8_t *respondBytes)
/*處理讀保持寄存器命令*/
static uint16_t HandleReadHoldingRegisterCommand(uint16_t startAddress,uint16_t quantity,uint8_t *receivedMessage,uint8_t *respondBytes)
/*處理讀輸入寄存器命令*/
static uint16_t HandleReadInputRegisterCommand(uint16_t startAddress,uint16_t quantity,uint8_t *receivedMessage,uint8_t *respondBytes)
/*處理寫單個線圈命令*/
static uint16_t HandleWriteSingleCoilCommand(uint16_t coilAddress,uint16_t coilValue,uint8_t *receivedMessage,uint8_t *respondBytes)
/*處理寫單個寄存器命令*/
static uint16_t HandleWriteSingleRegisterCommand(uint16_t registerAddress,uint16_t registerValue,uint8_t *receivedMessage,uint8_t *respondBytes)
/*處理寫多個線圈狀態*/
static uint16_t HandleWriteMultipleCoilCommand(uint16_t startAddress,uint16_t quantity,uint8_t *receivedMessage,uint8_t *respondBytes)
/*處理寫多個寄存器狀態*/
static uint16_t HandleWriteMultipleRegisterCommand(uint16_t startAddress,uint16_t quantity,uint8_t *receivedMessage,uint8_t *respondBytes)
然后我們定義一個函數指針數組來調用這下函數:
uint16_t (*HandleClientCommand[])(uint16_t,uint16_t,uint8_t *,uint8_t *)={HandleReadCoilStatusCommand,
HandleReadInputStatusCommand,
HandleReadHoldingRegisterCommand,
HandleReadInputRegisterCommand,
HandleWriteSingleCoilCommand,
HandleWriteSingleRegisterCommand,
HandleWriteMultipleCoilCommand,
HandleWriteMultipleRegisterCommand};
3、響應的生成
對於響應命令的生成其實在第二篇中已經說過了,需要說明的是各種寫數據的具體數值以及獲得讀數據的各種具體數值我們將在單獨的文件中去實現,因為這部分TCP和RTU是相同的,我們將在后續的篇章中說明。