该程序是一个基于 UDPDK 的 UDP 数据包接收程序。
程序首先通过cpu_init(),直接将该程序的优先级设置为最高优先级99,保证当前程序会优先获得 CPU 资源,确保对 UDP 数据接收、模拟输出触发等时间敏感的操作能快速响应,避免因资源竞争导致的处理延迟。
之后调用udpdk_api.h中函数udpdk_init(argc, argv),初始化 UDPDK 的运行环境,包括:
实际运行该程序时,输入指令./dpdk_short -c config.ini,其中相关参数已经在config.ini文件中写入,修改其中参数,可以调整接收端mac地址和ip地址,或者控制只接收哪个mac地址的发送端数据。
该函数返回值>=0时,UDPDK环境初始化成功。之后再调用程序中编写的函数parse_app_args(argc, argv),解析命令行指令。该函数只处理-d的延时命令,根据-d后的数选择延时多少微秒。在我们的指令中没有延时需求,因此实际直接返回0即可。
之后调用函数dd_recv,通过 UDP 协议接收数据,并根据接收状态控制模拟输出(AO)设备的电压输出。
static void dd_recv(void)
{
int sock, n;
struct sockaddr_in servaddr, cliaddr;
char buf[1936];
// Create a socket
if ((sock = udpdk_socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
fprintf(stderr, "Pong: socket creation failed\n");
return;
}
// Bind it
memset(&servaddr, 0, sizeof(servaddr));
memset(&cliaddr, 0, sizeof(cliaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(PORT_PONG);
if (udpdk_bind(sock, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
fprintf(stderr, "Pong: bind failed\n");
return;
}
while (app_alive) {
if(g_ao_triggered) {
trigger_ao_0v_once();
}
int len = sizeof(cliaddr);
n = udpdk_recvfrom(sock, (void *)buf, sizeof(buf), 0, (struct sockaddr *)&cliaddr, &len);
if (n > 0) {
trigger_ao_3v_once();
}
}
}
程序首先使用 udpdk_socke,创建一个 UDP 套接字,之后将套接字绑定到指定端口 PORT_PONG(8010)和所有网络接口(INADDR_ANY),用于监听来自该端口的 UDP 数据。再将程序丢进app_alive控制的循环中,当程序需要终止时跳出循环;循环中,通过 udpdk_recvfrom 阻塞等待接收 UDP 数据,接收到的数据将会写入共享内存dd.shm.5里面,共享内存的数据会由dd_count.c程序解析。
循环终止后,调用udpdk_interrupt(0)和udpdk_cleanup()函数关闭释放udpdk。
另外,程序中还有函数trigger_ao_3v_once、trigger_ao_0v_once、ao_cleanup,这些函数通过调用comedi_data_write函数,改变PCI板卡输出通道的电平。
trigger_ao_3v_once、trigger_ao_0v_once,分别将输出通道的输出电平调整为3V/0V,用于根据设定规则输出高低电平;ao_cleanup则将所有通道输出变为低电平后,还关闭comedi停止输出,在程序终止时释放输出通道。
该程序是基于共享内存的数据消费者程序,用于从共享内存中获取blob数据。
程序首先通过parse_opts解析命令行。执行程序时输入指令./dd_count -c config.yml会需要调用read_config_from_file,读取config.yml文件内的信息,该文件内存储了共享内存的标识 ID(job_id),启用的通道数量(channels_enabled),每个数据块的大小(blob_size)等内容。
之后,程序通过dd_init(MODE_CONSUMER, 0, job_id),轮询等待生产者创建共享内存,当未找到对应id号的共享内存时,输出未找到共享内存信息,并在1秒延时后继续循环。
找到共享内存后,pthread_create(&threads[0], NULL, cons_proc, NULL)创建消费者进程,启动消费线程cons_proc。该消费者程序,在共享内存里面存在blob时,通过dd_get_blob_pop读取blob,并通过计数器packet_count对blob计数,之后输出该blob相关信息,例如blob id,blob里面包含的采样数据数量,总共收到的包的数量。
调用该程序时,需要dpdk_short.c程序先接收到udp包,并将udp包内容写入到共享内存dd.shm.5里面,之后该程序检测到共享内存,读取共享内存里面数据,并输出共享内存里面相关的信息。通过观察输出的blob总共有多少个,即可判断出来上一次udp发送里面,上位机接收到了多少udp包,根据该数据即可计算得出udp发送的丢包率。
本文章使用limfx的vscode插件快速发布