目錄
一、背景
二、可行性驗證
三、開發調試
一、背景
在一般場景下,只需一路IO連接,但稍微復雜的場景,就需要不同通訊周期的連接,這就需要有多組IO連接。
而大于一組的連接調試方法是一樣的,因此主要解決2組連接的代碼開發。
二、可行性驗證
在Eip Scanner Demo(主站)、PLC(從站)軟件上分別配置兩個生產者連接,驗證其數據收發可行性及穩定性。得到視頻及報文如下:
1、Enip
2、ForwardOpen 1
3、ForwardOpen 2
4、ForwardCloes 2
5、ForwardCloes 1
可見,進行了兩次ForwardOpen,建立了兩個生產者連接。
由上文可見,兩個生產者連接的ForwardOpen的不同點在于:
1、Connection Path 由PLC自動生成,直接配置到Ubuntu中
2、Connecte Serial Number 自由選擇,只要是兩個連接不同即可,見協議原文
3、Connection Parameter (可選,如果兩個收發字節數相同,則此項也相同)
因此,便可滿足上述要求情況下,將多生產者連接集成到一個SDK中。
但需要注意多線程下的單一物理網口的數據搶占問題。
三、開發調試
發現在_connectionMap中管理了所有的IO連接。
在forwardopen階段注冊_connectionMap,每開一個IO連接都會注冊一個_connectionMap進去
在handleConnections中,若IO連接不存在,則刪除掉
而在代碼中,無需在兩個連接的情況下守護兩個connectionManager,于是更改代碼如下:
int main() {。。。。parameters.o2tRealTimeFormat = true;parameters.t2oRealTimeFormat = true;parameters.originatorVendorId = 0xaa;parameters.connectionTimeoutMultiplier=2;parameters.priorityTimeTick=10;parameters.t2oNetworkConnectionParams |= NetworkConnectionParams::P2P;parameters.t2oNetworkConnectionParams |= NetworkConnectionParams::SCHEDULED_PRIORITY;parameters.t2oNetworkConnectionParams |= 0; //size of Assm100 =1parameters.o2tNetworkConnectionParams |= NetworkConnectionParams::P2P;parameters.o2tNetworkConnectionParams |= NetworkConnectionParams::SCHEDULED_PRIORITY;parameters.o2tNetworkConnectionParams |= 4; //size of Assm100 =1parameters.originatorSerialNumber = 0x012345;parameters.o2tRPI = 50000;parameters.t2oRPI = 50000;//50msparameters.transportTypeTrigger |= NetworkConnectionParams::CLASS1;parameters.transportTypeTrigger |= NetworkConnectionParams::TRIG_CYCLIC; std::chrono::milliseconds timeout(5000);
//connect oneauto si_1 = std::make_shared<SessionInfo>("192.168.2.88", 0xAF12,timeout,50000);ConnectionManager connectionManager_1;parameters.connectionPath = {0x20, 0x04,0x24, 0x01, 0x2C, 0x65, 0x2C, 0xFF}; parameters.connectionSerialNumber = 0xbebc;auto io_1 = connectionManager_1.forwardOpen(si_1, parameters);if (auto ptr = io_1.lock()) {ptr->setDataToSend(std::vector<uint8_t>(4));ptr->setReceiveDataListener([](auto realTimeHeader, auto sequence, auto data) {std::ostringstream ss;ss << "secNum=" << sequence << " data=";for (auto &byte : data) {ss << "[" << std::hex << (int) byte << "]";}Logger(LogLevel::INFO) << "Received: " << ss.str();});ptr->setCloseListener([]() {Logger(LogLevel::INFO) << "Closed";});}//connect twoauto si_2 = std::make_shared<SessionInfo>("192.168.2.88", 0xAF12,timeout,50050);//ConnectionManager connectionManager_2;parameters.connectionPath = {0x20, 0x04,0x24, 0x01, 0x2C, 0x64, 0x2C, 0x6E}; parameters.connectionSerialNumber = 0x275D;//auto io_2 = connectionManager_2.forwardOpen(si_2, parameters);auto io_2 = connectionManager_1.forwardOpen(si_2, parameters);if (auto ptr = io_2.lock()) {ptr->setDataToSend(std::vector<uint8_t>(4));ptr->setReceiveDataListener([](auto realTimeHeader, auto sequence, auto data) {std::ostringstream ss;ss << "secNum=" << sequence << " data=";for (auto &byte : data) {ss << "[" << std::hex << (int) byte << "]";}Logger(LogLevel::INFO) << "Received: " << ss.str();});ptr->setCloseListener([]() {Logger(LogLevel::INFO) << "Closed";});}//handle connectwhile (connectionManager_1.hasOpenConnections()) {connectionManager_1.handleConnections(std::chrono::milliseconds(50));// connectionManager_2.handleConnections(std::chrono::milliseconds(50));}connectionManager_1.forwardClose(si_1, io_1);connectionManager_1.forwardClose(si_2, io_2);。。。。return EXIT_SUCCESS;
}
顯示Log如下,能正常維持兩個連接
wireshark報文如下:
此系列的b站視頻見:
基于EIPScanner的Linux Ethernet/IP的多生產者連接及Tag讀寫實現分享(一 引言)_嗶哩嗶哩_bilibili
參考代碼見:
咸魚ID:tb764914262