读取C中的can总线显示29位can ID的can ID不正确

读取C中的can总线显示29位can ID的can ID不正确,c,linux,can-bus,C,Linux,Can Bus,我用c写了一些代码来读取CAN总线数据 当我读取11位CAN ID时,一切正常 当我试图读取29位ID时,它显示的ID不正确 示例: 接收29位id的消息: 0x01F0A020 并用 printf(“%X\n”,frame.can\u id) 它打印 81F0A020 11位ID消息 0x7DF 并用 printf(“%X\n”,frame.can\u id) 打印正确 7DF 有人能告诉我为什么会这样吗 #include <stdio.h> #include <stdlib

我用c写了一些代码来读取CAN总线数据 当我读取11位CAN ID时,一切正常 当我试图读取29位ID时,它显示的ID不正确

示例:
接收29位id的消息:
0x01F0A020
并用
printf(“%X\n”,frame.can\u id)
它打印
81F0A020

11位ID消息
0x7DF
并用
printf(“%X\n”,frame.can\u id)
打印正确
7DF

有人能告诉我为什么会这样吗

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <net/if.h>
#include <fcntl.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/can.h>
#include <linux/can/raw.h>

#define MAX_DATA_LEN 8
#define MAX_FIELDS 23
#define MAX_FIELD_LEN 64
#include <limits.h>


char data_str[MAX_FIELDS][MAX_FIELD_LEN];
int i;


int
main(void)
{
    int s;
    int nbytes;
    struct sockaddr_can addr;
    struct can_frame frame;
    unsigned short data[MAX_FIELDS];
    int sockfd=0;
    int bcast=1;
    struct sockaddr_in src_addr;
    struct sockaddr_in dst_addr;
    int numbytes;

    int fa;
    struct ifreq ifr;

    fa = socket(AF_INET, SOCK_DGRAM, 0);

    ifr.ifr_addr.sa_family = AF_INET;
    strncpy(ifr.ifr_name, "eth0", IFNAMSIZ-1);

    ioctl(fa, SIOCGIFHWADDR, &ifr);
    close(fa);



    //
    if((sockfd = socket(PF_INET,SOCK_DGRAM,0)) == -1)
    {
        perror("Udp sockfd create failed");
        exit(1);
    }
    //Enabled broadcast mode for udp
    if((setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,
                &bcast,sizeof bcast)) == -1)
    {
        perror("setsockopt failed for broadcast mode ");
        exit(1);
    }
    src_addr.sin_family = AF_INET;
    src_addr.sin_port = htons(8888);
    src_addr.sin_addr.s_addr = INADDR_ANY;
    memset(src_addr.sin_zero,'\0',sizeof src_addr.sin_zero);

    if(bind(sockfd, (struct sockaddr*) &src_addr, sizeof src_addr) == -1)
    {
        perror("bind");
        exit(1);
    }

    dst_addr.sin_family = AF_INET;
    dst_addr.sin_port = htons(45454);
    dst_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    memset(dst_addr.sin_zero,'\0',sizeof dst_addr.sin_zero);

    if((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
        perror("Error while opening socket");
        return -1;
    }

    addr.can_family  = AF_CAN;
    addr.can_ifindex = 0;

    if(bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
        perror("Error in socket bind");
        return -2;
    }

    //struct can_frame frame;
    while(1)
    {
        nbytes = read(s, &frame, sizeof(struct can_frame));

        if (nbytes < 0) {
                perror("can raw socket read");
                return 1;
        }

        /* paranoid check ... */
        if (nbytes < sizeof(struct can_frame)) {
                fprintf(stderr, "read: incomplete CAN frame\n");
                return 1;
        }   

        //Print the received CAN ID 
        printf("%X\n",frame.can_id);


    }
    return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义最大数据长度8
#定义最大值字段23
#定义最大字段长度64
#包括
char data_str[MAX_FIELDS][MAX_FIELD_LEN];
int i;
int
主(空)
{
int-s;
整数字节;
结构sockaddr\u can addr;
结构can_框架;
无符号短数据[最大字段];
int-sockfd=0;
int-bcast=1;
src_addr中的结构sockaddr_;
dst_addr中的结构sockaddr_;
整数单位;
int-fa;
结构ifreq-ifr;
fa=插座(AF_INET,SOCK_DGRAM,0);
ifr.ifr\u addr.sa\u family=AF\u INET;
strncpy(ifr.ifr_名称,“eth0”,IFNAMSIZ-1);
ioctl(fa、SIOCGIFHWADDR和ifr);
关闭(fa);
//
if((sockfd=socket(PF_INET,SOCK_DGRAM,0))=-1)
{
perror(“Udp sockfd创建失败”);
出口(1);
}
//已启用udp的广播模式
如果((设置锁定选择)(sockfd、SOL_插座、SO_广播、,
&bcast,sizeof bcast))=-1)
{
perror(“广播模式设置锁定失败”);
出口(1);
}
src_addr.sin_family=AF_INET;
src_addr.sin_port=htons(8888);
src_addr.sin_addr.s_addr=INADDR_ANY;
memset(src_addr.sin_zero、\0',src_addr.sin_zero的大小);
if(绑定(sockfd,(结构sockaddr*)&src_addr,src_addr的大小)=-1)
{
佩罗(“绑定”);
出口(1);
}
dst_addr.sin_family=AF_INET;
dst地址sin端口=htons(45454);
dst_addr.sin_addr.s_addr=inet_addr(“127.0.0.1”);
memset(dst地址单零、\0',dst地址单零的大小);
如果((s=插座(PF_CAN、SOCK_RAW、CAN_RAW))<0){
perror(“打开插座时出错”);
返回-1;
}
addr.can_family=AF_can;
地址can\U ifindex=0;
if(绑定(结构sockaddr*)&addr,sizeof(addr))<0{
perror(“套接字绑定错误”);
返回-2;
}
//结构can_框架;
而(1)
{
nbytes=读取(s,&frame,sizeof(struct can_frame));
如果(n字节<0){
perror(“可读取原始套接字”);
返回1;
}
/*偏执狂检查*/
if(n字节
结构can框架的
can id
字段包含can id和EFF/RTR/ERR标志。扩展ID有29位,因此有3个空闲位用于表示3个标志

示例ID
0x01F0A020
必须是扩展帧,但ID
0x7DF
可以作为基本帧或扩展帧发送。这些是不同的信息。要区分具有相同ID的基本帧或扩展帧,需要EFF标志

在您的示例中,您可以看到值
0x81F0A020
,它是ID
0x01F0A020
CAN\u EFF\u标志的组合(
0x80000000U

从中提取

要仅获取不带标志的ID,应根据
CAN\U EFF\U标志
位的值应用
CAN\U SFF\U掩码
CAN\U EFF\U掩码

示例代码:

        //Print the received CAN ID 
        printf("%X\n", 
               (frame.can_id & CAN_EFF_FLAG) ? (frame.can_id & CAN_EFF_MASK)
                                             : (frame.can_id & CAN_SFF_MASK));

struct can_frame
can_id
字段包含can idEFF/RTR/ERR标志。扩展ID有29位,因此有3个空闲位用于表示3个标志

示例ID
0x01F0A020
必须是扩展帧,但ID
0x7DF
可以作为基本帧或扩展帧发送。这些是不同的信息。要区分具有相同ID的基本帧或扩展帧,需要EFF标志

在您的示例中,您可以看到值
0x81F0A020
,它是ID
0x01F0A020
CAN\u EFF\u标志的组合(
0x80000000U

从中提取

要仅获取不带标志的ID,应根据
CAN\U EFF\U标志
位的值应用
CAN\U SFF\U掩码
CAN\U EFF\U掩码

示例代码:

        //Print the received CAN ID 
        printf("%X\n", 
               (frame.can_id & CAN_EFF_FLAG) ? (frame.can_id & CAN_EFF_MASK)
                                             : (frame.can_id & CAN_SFF_MASK));

为什么fishy
(struct sockaddr*)
会强制转换?@Bodo在不同结构类型之间强制转换会调用未定义的行为,很可能是一个bug。它们是真正兼容的类型吗?如果是,为什么要使用两种不同的类型。它要么是代码气味,要么是库气味struct sockaddr
struct sockaddr\u can
完全不兼容,因此它似乎是一个库错误。它们是不兼容的类型,这也是一种严格的别名冲突。@Bodo唯一重要的是,如果结构被反引用为
struct sockaddr
anywhere,那么它就是一个bug。否则这只是一个混乱的API设计。@问题是,他们不能检查初始元素,除非它与整个
struct sockaddr\u can
具有相同的左值类型,而事实并非如此。在最坏的情况下,您会得到未对齐的访问。充其量,你会收到一个公开邀请,让gcc优化器发疯。为什么可疑的
(struct sockaddr*)
强制转换?@Bodo在不同的结构类型之间强制转换调用未定义的
        //Print the received CAN ID 
        printf("%X\n", 
               (frame.can_id & CAN_EFF_FLAG) ? (frame.can_id & CAN_EFF_MASK)
                                             : (frame.can_id & CAN_SFF_MASK));