目录
一、背景
二、可行性验证
三、开发调试
一、背景
在一般场景下,只需一路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