【Codesys-Runtime】-下位機組件代碼結構初探
今天我們把鏡頭再拉進一些,初步探索一下組件的相關內容:
- Codesys Runtime 軟件架構;
- Runtime 中包含哪些功能 or 組件;
- 組件內部的代碼結構長什么樣;
1-Codesys Runtime 軟件
Runtime 最主要的職責就是完成下面這些任務:
圖片
這七個功能是非常宏觀、籠統的總結。為了完成這些功能,在 PLC 中有很多個組件,一起協同配合,各司其職。
先來看一下官網中提供的一張組件結構圖,圖中最小的粒度就是組件:
圖片
可以看到,這是一個符合常規思路的分層、分模塊軟件架構。每一個方塊都代表一個組件。
有些功能模塊是由一個組件獨立完成的,有些功能模塊則是由幾個組件一起配合完成的。
Codesys Runtime 在不同的硬件平臺上部署的固件是有差異的,我們這里的測試平臺是 x86 Linux,下載的 Runtime 固件是 CODESYS Control for Linux SL,所以下面就來看一下這個版本的固件中都包含了哪些固件。
2-Runtime 中包含哪些功能 or 組件
方法一
最直接的方式就是在下位機的命令行窗口中,進入 /opt/codesyscontrol/ 目錄,手動啟動 bin/codesyscontrol.bin 可執行程序,在啟動階段的打印信息中,可以看到所有加載的組件。
因為組件比較多,這里只截取一部分:
圖片
上圖中每一行都是加載的一個組件,包括:名稱,Id號和版本信息,從名字上也可以大概猜測出來對應的功能。
方法二
通過上位機集成開發環境(IDE)來查看下位機中加載了哪些組件。
掃描設備-成功連接到下位機之后,在 【Device】標簽頁的左面,有【日志】選項,單擊一下就可以看到下位機的日志了。
在其中可以看到下位機中 Runtime 加載的所有組件(如果沒有顯示任何信息,點擊一下組件旁邊的綠色刷新按鈕):
圖片
我這里顯示加載的組件有(顯式的順序與加載的順序是相反的):
圖片
我們在上位機 IDE 中的每一次操作,只要該功能需要下位機來執行,就一定需要其中的某一個或某幾個組件來配合完成。
舉個例子-在上位機中執行【熱復位】動作:
1. 首先要通過網絡傳輸到下位機吧,這是由網絡部分的組件完成的,包括:CmpBlkDrvTcp/CmpBlkDrvUdp/CmpChannelXXX等組件;
2. 傳輸的數據一定是滿足特定協議的數據結構吧,數據解析工作是由組件 CmpBinTagUtil 完成的;
3. 數據解析之后,就是執行具體的功能了,比如:對程序里的變量進行復位,這就需要 CmpApp 等組件來完成。
【熱復位】這個功能,就像一個縱向的邏輯鏈條,這個鏈條把不同層次上的組件串接起來,一起配合完成具體的功能。
3- 組件內部的代碼結構長什么樣
在看代碼之前,有兩個前置問題需要說明一下,方便后續的理解。
為什么要關心組件里的代碼結構?
Codesys Runtime 的軟件架構設計的非常精巧,每一個組件之所以能完美的相互配合,就是因為每個組件都必須按照官方設計的代碼規則來編寫,也就是需要按照一套定義好的代碼結構來編寫、編譯,然后部署到下位機中才能被加載、執行。
Codesys 是一家非常牛X的方案提供商,當一個 PLC 廠家使用這套方案來開發 PLC 產品時,是需要進行二次開發的,讓 Codesys 的這套方案能夠與每一個不同型號的 PLC 硬件設備進行完美的融合。
所以,作為嵌入式開發工程師,一定要理解組件里的代碼結構。
當然了,剛開始的時候只需要照葫蘆畫瓢,遵守既定的代碼規則就行了。熟悉之后,可以再研究一下這些規則背后的設計思想。
什么是 Codesys Runtime 開發 SDK?
SDK 就是常規的意思:軟件開發包,里面包含的就是一些頭文件(.h),靜態庫(.a) 或者動態庫(.so)文件。
此外,為了方便開發者編寫的組件滿足特定的規則,SDK中還提供了一個助手工具(M4腳本程序),來簡化組件的編寫過程。
在 Codesys 幫助頁面上(https://content.helpme-codesys.com/zh-CHS/CODESYS%20Control/_rtsl_extension_extension_sdk.html),告訴我們在哪里可以找到 SDK:
默認情況下,您可以在以下位置找到擴展 SDK:
C:\Program Files\CODESYS <version>\CODESYS\CODESYS Control SL Extension Package\<version>\ExtensionSDK
.
SDK中內容如下:
圖片
在 src 目錄下,有一個模板文件 CmpFrame.c 。
此文件內容就是組件的基本代碼結構,如下圖所示(為了減少篇幅,這里只列出函數):
/*****************************************************************************
*Copyright:Copyright CODESYS Development GmbH
*Program:Extension API for the Linux SL products
******************************************************************************/
#include "CmpStd.h"
#include DEP_H
USE_STMT
DLL_DECL int CDECL ComponentEntry(INIT_STRUCT *pInitStruct)
{
return ERR_OK;
}
static int CDECL ExportFunctions(void)
{
/* Macro to export functions */
EXPORT_STMT;
return ERR_OK;
}
static int CDECL ImportFunctions(void)
{
/* Macro to import functions */
IMPORT_STMT;
return ERR_OK;
}
static RTS_UI32 CDECL CmpGetVersion(void)
{
return CMP_VERSION;
}
static RTS_RESULT CDECL HookFunction(RTS_UI32 ulHook, RTS_UINTPTR ulParam1, RTS_UINTPTR ulParam2)
{
return ERR_OK;
}
看起來似乎也沒有想象中那么復雜,是吧?
那是因為很多細節都隱藏在幾個宏定義中了,例如:USE_STMT,EXPORT_STMT,IMPORT_STMT。
當然了,作為剛入門的開發者,是沒有必要把這些規則背后的原理都理解清楚的。
我們只需要遵守這些規則,把注意力放在我們自己要實現的功能代碼上即可。
另外,上面的顯示的代碼結構只是一個組件需要滿足的最基本規則。
如果是一個功能比較特殊的組件,例如:一個IO設備驅動組件,那么它需要遵守的規則就會更多,也就是說:有更多的特定函數需要添加到組件中。