/*********************************************************************************
|
* Copyright: (C) 2024 LingYun IoT System Studio
|
* All rights reserved.
|
*
|
* Filename: can_test.c
|
* Description: This file is socket CAN loop test program
|
*
|
* Version: 1.0.0(05/26/2024)
|
* Author: Guo Wenxue <guowenxue@gmail.com>
|
* ChangeLog: 1, Release initial version on "05/26/2024 05:42:49 PM"
|
*
|
********************************************************************************/
|
|
#include <stdio.h>
|
#include <stdlib.h>
|
#include <string.h>
|
#include <unistd.h>
|
#include <sys/ioctl.h>
|
#include <net/if.h>
|
#include <sys/socket.h>
|
#include <linux/can.h>
|
#include <linux/can/raw.h>
|
#include <getopt.h>
|
|
// 打印使用帮助信息
|
void print_usage(const char *progname)
|
{
|
printf("Usage: %s -i <can_interface> -m <mode>\n", progname);
|
printf("Options:\n");
|
printf(" -i, --interface CAN interface (e.g., can0)\n");
|
printf(" -m, --mode Mode: send or receive\n");
|
printf(" -h, --help Display this help message\n");
|
}
|
|
void send_can_message(const char *ifname)
|
{
|
int fd;
|
struct sockaddr_can addr;
|
struct ifreq ifr;
|
struct can_frame frame;
|
|
// 创建socket
|
fd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
|
if (fd < 0)
|
{
|
perror("socket");
|
exit(1);
|
}
|
|
// 指定CAN接口
|
strcpy(ifr.ifr_name, ifname);
|
ioctl(fd, SIOCGIFINDEX, &ifr);
|
addr.can_family = AF_CAN;
|
addr.can_ifindex = ifr.ifr_ifindex;
|
|
// 绑定socket到CAN接口
|
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
|
{
|
perror("bind");
|
exit(1);
|
}
|
|
// 构造CAN帧
|
frame.can_id = 0x123; // 设置CAN ID
|
frame.can_dlc = 2; // 数据长度
|
frame.data[0] = 0x11; // 数据
|
frame.data[1] = 0x22; // 数据
|
|
// 发送CAN帧
|
if (write(fd, &frame, sizeof(struct can_frame)) != sizeof(struct can_frame))
|
{
|
perror("write");
|
exit(1);
|
}
|
|
// 关闭socket
|
close(fd);
|
}
|
|
void receive_can_message(const char *ifname)
|
{
|
int fd;
|
struct sockaddr_can addr;
|
struct ifreq ifr;
|
struct can_frame frame;
|
|
// 创建socket
|
fd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
|
if (fd < 0) {
|
perror("socket");
|
exit(1);
|
}
|
|
// 指定CAN接口
|
strcpy(ifr.ifr_name, ifname);
|
ioctl(fd, SIOCGIFINDEX, &ifr);
|
addr.can_family = AF_CAN;
|
addr.can_ifindex = ifr.ifr_ifindex;
|
|
// 绑定socket到CAN接口
|
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
|
{
|
perror("bind");
|
exit(1);
|
}
|
|
// 接收CAN帧
|
while (1)
|
{
|
int nbytes = read(fd, &frame, sizeof(struct can_frame));
|
if (nbytes < 0)
|
{
|
perror("read");
|
exit(1);
|
}
|
|
if (nbytes < sizeof(struct can_frame))
|
{
|
fprintf(stderr, "read: incomplete CAN frame\n");
|
exit(1);
|
}
|
|
// 打印接收到的CAN帧
|
printf("Received CAN frame: ID=0x%X DLC=%d data=", frame.can_id, frame.can_dlc);
|
for (int i = 0; i < frame.can_dlc; i++)
|
printf("%02X ", frame.data[i]);
|
|
printf("\n");
|
}
|
|
// 关闭socket
|
close(fd);
|
}
|
|
int main(int argc, char **argv)
|
{
|
int opt, index = 0;
|
const char *ifname = NULL;
|
const char *mode = NULL;
|
|
// 定义长选项
|
static struct option long_options[] =
|
{
|
{"interface", required_argument, 0, 'i'},
|
{"mode", required_argument, 0, 'm'},
|
{"help", no_argument, 0, 'h'},
|
{0, 0, 0, 0}
|
};
|
|
while ((opt = getopt_long(argc, argv, "i:m:h", long_options, &index)) != -1)
|
{
|
switch (opt) {
|
case 'i':
|
ifname = optarg;
|
break;
|
case 'm':
|
mode = optarg;
|
break;
|
case 'h':
|
print_usage(argv[0]);
|
return 0;
|
default:
|
print_usage(argv[0]);
|
return 1;
|
}
|
}
|
|
if (ifname == NULL || mode == NULL)
|
{
|
print_usage(argv[0]);
|
return 1;
|
}
|
|
if (strcmp(mode, "send") == 0)
|
{
|
send_can_message(ifname);
|
}
|
else if (strcmp(mode, "receive") == 0)
|
{
|
receive_can_message(ifname);
|
}
|
else
|
{
|
fprintf(stderr, "Invalid mode: %s\n", mode);
|
print_usage(argv[0]);
|
return 1;
|
}
|
|
return 0;
|
}
|