注意:学习资料可在ElfBoard官方网站“资料”专区获取。
本节用到的源码路径:ELF 1开发板资料包3-例程源码3-1 命令行例程源码6_elf1_cmd_can
can.c
#include <errno.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <termios.h> /*PPSIX 终端控制定义*/
#include "mycan.h"
/*
* @description : 字符串按格式输出
* @param - *destpoint : 字符串格式缓冲区
* @param - *fmt : 多个参数
* @return : 按格式输出字符串缓冲区首指针
*/
char func_dprintf(char *destpoint, char *fmt, ...)
{
va_list arg_ptr;
char ulen, *tmpBuf;
tmpBuf = destpoint;
va_start(arg_ptr, fmt);
ulen = vsprintf(tmpBuf, fmt, arg_ptr);
va_end(arg_ptr);
return ulen;
}
/*
* @description : 打开can外设,设置波特率,创建文件描述符
* @param - *device : 设备名称
* @param - para : can应用参数
* @return : 打开设备执成功返回文件描述符,失败返回-1
*/
int func_open_can(char *device, struct_can_param para)
{
FILE *fstream = NULL;
char buff[300] = {0}, command[50] = {0};
int fd = -1;
struct sockaddr_can addr;
struct ifreq ifr;
/*关闭can设备 ifconfig can0 down*/
memset(buff, 0, sizeof(buff));
memset(command, 0, sizeof(command));
func_dprintf(command, "ifconfig %s down", device);
printf("%s n", command);
if (NULL == (fstream = popen(command, "w")))
{
fprintf(stderr, "execute command failed: %s", strerror(errno));
}
while (NULL != fgets(buff, sizeof(buff), fstream))
{
printf("%sn", buff);
if (strstr(buff, "No such device") || strstr(buff, "Cannot find device"))
return -1;
}
pclose(fstream);
sleep(1);
/*设置can波特率 ip link set can0 up type can bitrate 250000 triple-sampling on*/
memset(buff, 0, sizeof(buff));
memset(command, 0, sizeof(command));
if (para.loopback_mode == 1)
{
func_dprintf(command, "ip link set %s up type can bitrate %d triple-sampling on loopback on", device, para.baudrate);
}
else
{
func_dprintf(command, "ip link set %s up type can bitrate %d triple-sampling on loopback off", device, para.baudrate);
}
printf("%s n", command);
if (NULL == (fstream = popen(command, "w")))
{
fprintf(stderr, "execute command failed: %s", strerror(errno));
}
while (NULL != fgets(buff, sizeof(buff), fstream))
{
printf("%sn", buff);
if (strstr(buff, "No such device") || strstr(buff, "Cannot find device"))
return -1;
}
pclose(fstream);
sleep(1);
/*打开can设备 ifconfig can0 up*/
memset(buff, 0, sizeof(buff));
memset(command, 0, sizeof(command));
func_dprintf(command, "ifconfig %s up", device);
printf("%s n", command);
if (NULL == (fstream = popen(command, "w")))
{
fprintf(stderr, "execute command failed: %s", strerror(errno));
}
while (NULL != fgets(buff, sizeof(buff), fstream))
{
printf("%sn", buff);
if (strstr(buff, "No such device") || strstr(buff, "Cannot find device"))
return -1;
}
pclose(fstream);
sleep(3);
/* 创建 socket */
fd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (fd < 0)
{
printf("socket:%s", strerror(errno));
return -1;
}
/* 设置接口设备名称 */
strcpy(ifr.ifr_name, device);
/* 确定接口 index */
if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0)
{
printf("SIOCGIFINDEX:%sn", strerror(errno));
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
/* 绑定 socket到 CAN 接口 */
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
printf("bind:%sn", strerror(errno));
return -1;
}
return fd;
}
/*
* @description : 设置can回环模式和过滤规则
* @param - fd : 文件描述符
* @param - para: can应用参数
* @return : 设置成功返回1,失败返回-1
*/
int func_set_can(int fd, struct_can_param para)
{
int loopback = 1;
int reciveown = 1;
if (para.loopback_mode == 1)
{
// 回环设置 0 关闭回环 1 打开回环
// setsockopt(fd, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &loopback, sizeof(loopback));
// 接收自己的帧 0 不接收自己帧 1 接收自己帧
// setsockopt(fd, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, &reciveown, sizeof(reciveown));
}
/* 设置过滤规则 */
if (setsockopt(fd, SOL_CAN_RAW, CAN_RAW_FILTER, ¶.filter, sizeof(para.filter)) < 0)
{
printf("error when set filtern");
return -1;
}
return 1;
}
/*
* @description : can接收一个can帧
* @param - fd : 文件描述符
* @param - *pframe: 一个can帧结构体指针
* @return : 接收数据长度
*/
int func_receive_can_frame(int fd, struct can_frame *pframe)
{
int rx_count = 0;
rx_count = recv(fd, pframe, sizeof(*pframe), 0);
if (rx_count <= 0)
{
return rx_count;
}
else
{
if (pframe->can_id & CAN_EFF_FLAG) /*如果是扩展帧,清除扩展帧标识*/
{
pframe->can_id &= (~CAN_EFF_FLAG);
}
else
{
pframe->can_id &= (~CAN_SFF_MASK);
}
}
return pframe->can_dlc;
}
/*
* @description : can接收一组数据包
* @param - fd : 文件描述符
* @param - *buff: 要接收can一组数据的缓冲区首指针
* @param - len : 接收到一组数据的长度
* @return : 接收数据长度
*/
int func_receive_can_buff(int fd, unsigned char *buff, int len)
{
int receive_len = 0, total_receive_len = 0;
struct can_frame frame;
int i = 0;
while (1)
{
receive_len = func_receive_can_frame(fd, &frame);
for (i = 0; i < receive_len; i++)
{
*(buff + total_receive_len) = frame.data[i];
total_receive_len++;
}
if ((receive_len < 8) || (total_receive_len > (len - 8)))
{
return total_receive_len;
}
}
return total_receive_len;
}
/*
* @description : can发送一个can帧
* @param - fd : 文件描述符
* @param - *pframe: 一个can帧结构体指针
* @param - param : can应用参数
* @return : 发送数据长度,发送失败返回-1
*/
int func_send_can_frame(int fd, struct can_frame *pframe, struct_can_param param)
{
int result = 0;
if (param.extend == 1) /*扩展帧增加扩展帧标志*/
{
pframe->can_id &= CAN_EFF_MASK;
pframe->can_id |= CAN_EFF_FLAG;
}
else
{
pframe->can_id &= CAN_SFF_MASK;
}
result = send(fd, pframe, sizeof(struct can_frame), 0);
if (result == -1)
{
printf("send:%sn", strerror(errno));
return -1;
}
return result;
}
/*
* @description : can发送一组数据包
* @param - fd : 文件描述符
* @param - *buff: 要发送can一组数据的缓冲区首指针
* @param - len : 发送数据的长度
* @param - param: can应用参数
* @return : 实际发送数据长度
*/
int func_send_can_buff(int fd, unsigned char *buff, int len, struct_can_param param)
{
int remain_frame_len = 0, frame_numb = 0;
struct can_frame frame;
int i = 0;
remain_frame_len = len;
while (1)
{
if (remain_frame_len >= 8)
{
frame.can_dlc = 8; /*填充发送长度*/
remain_frame_len -= 8; /*剩余数据长度*/
}
else
{
frame.can_dlc = remain_frame_len; /*填充发送长度*/
remain_frame_len = 0; //
}
frame.can_id = param.id; /*填充发送id*/
for (i = 0; i < frame.can_dlc; i++)
{
frame.data[i] = buff[frame_numb * 8 + i]; /*填充发送数据*/
}
func_send_can_frame(fd, &frame, param);
frame_numb++;
if (remain_frame_len == 0)
{
return len;
}
}
return len;
}
main.c
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h> /*PPSIX 终端控制定义*/
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include "mycan.h"
char ver[20] = {"ver01.001"};
int sock_fd;
struct_can_param can_param = {250000, 0x103, {
0x100,
0x00,
},
0,
0,
0,
2000000};
unsigned char send_buff[1024], receive_buff[1024];
unsigned int send_num = 0, receive_num = 0;
//数据收发应用
char active_send_buff[500] = "test can";
int active_send_mode = 0, active_send_num = 8, active_send_time = 1000, active_send_time_count = 0;
int real_send_num = 0;
int loopback_send_mode = 0;
char dev[20];
/*
* @description : 自定义打印函数
* @param - buff: 打印数据缓冲区
* @param - lens: 打印数据长度
* @param - mode: 打印格式
* @return : 无
*/
void func_my_print(unsigned char *buff, unsigned int lens, unsigned char mode)
{
int i = 0;
switch (mode)
{
case 'H': //按照16进制打印数据
for (i = 0; i < lens; i++)
{
printf("0X%02X ", buff[i]);
}
break;
case 'h': //按照16进制打印数据
for (i = 0; i < lens; i++)
{
printf("0x%02x ", buff[i]);
}
break;
case 'd': //按照10进制打印数据
for (i = 0; i < lens; i++)
{
printf("%02d ", buff[i]);
}
break;
case 'c': //按照字符打印数据
for (i = 0; i < lens; i++)
{
printf("%c", buff[i]);
}
break;
default:
break;
}
printf("n");
}
/*
* @description : 打印参数设置格式
* @param - pname: 函数名
* @return : 无
*/
static void print_usage(const char *pname)
{
printf("Usage: %s device [-b baudrate] [-id id_numb] [-filt id mask] [-e] [-fd dbaudrate] [-t data time] [-l] [-L] [-v]"
"nt'-b baudrate' for different baudrate, range 5k to 5M,unit is Kbps"
"nt'-id id_numb' for nonzero can send id"
"nt'-filt id mask' for receive can_id and can_mask"
"nt'-e' for extend id frame"
"nt'-fd dbaudrate' for can fd mode , dbaudrate range 250k to 5M,unit is Kbps"
"nt'-t data time' for interval set time actively sends the data, unit is s"
"nt'-l' for can loopback mode"
"nt'-L' for app loopback receive data"
"nt'-rf path' save the data received by the serial port into the file, path for file to save"
"nt'-v' show version"
"ntexample : can0 baudrate 250k id 123 filt_id 105 filt_mask 1f0 extend id string data was send every 2s--> ./can_demo can0 -b 250 -id 123 -filt 105 1f0 -e -t abcdef 2"
"ntexample : can1 baudrate 250k id 105 filt_id 123 filt_mask 120 extend id --> ./can_demo can1 -b 250 -id 105 -filt 123 1f0"
"ntexample : can0 canfd mode baudrate 250k id 123 filt_id 105 filt_mask 1f0 extend id string data was send every 2s--> ./can_demo can0 -b 250 -id 123 -filt 105 1f0 -e -t 12345678 2 -fd 4000"
"ntexample : can1 canfd mode baudrate 250k id 105 filt_id 123 filt_mask 120 extend id --> ./can_demo can1 -b 250 -id 105 -filt 123 1f0 -e -fd 4000"
"ntexample : can0 canfd mode baudrate 500k extend id dbaudrate 4000k loopback mode 19 data was send every 1s --> ./can_demo can0 -b 500 -filt 0 0 -fd 4000 -t abcdefg 1 -e -ln ",
pname);
}
/*
* @description : 解析函数带入参数
* @param - numb: 参数个数
* @param - *param: 带入参数数组指针
* @param - *canparam: can应用参数
* @return : 无
*/
void get_param(int numb, char *param[], struct_can_param *canparam)
{
int i = 0, len = 0;
unsigned int baudrate = 0, id = 0, mask = 0, active_param = 0;
if (numb <= 2)
return;
for (i = 2; i < numb; i++)
{
if (!strcmp(param[i], "-b"))
{
i++;
baudrate = atoi(param[i]);
switch (baudrate)
{
case 5:
case 10:
case 20:
case 40:
case 50:
case 80:
case 100:
case 125:
case 200:
case 250:
case 400:
case 500:
case 666:
case 800:
case 1000:
case 2000:
case 4000:
case 5000:
canparam->baudrate = baudrate * 1000;
break;
}
continue;
}
if (!strcmp(param[i], "-id"))
{
i++;
id = strtoul(param[i], NULL, 16);
if (id)
{
canparam->id = (unsigned int)id;
}
continue;
}
if (!strcmp(param[i], "-filt"))
{
i++;
id = 0;
id = strtoul(param[i], NULL, 16);
canparam->filter.can_id = (canid_t)id;
i++;
mask = strtoul(param[i], NULL, 16);
canparam->filter.can_mask = (canid_t)mask;
continue;
}
if (!strcmp(param[i], "-e"))
{
canparam->extend = 1;
continue;
}
if (!strcmp(param[i], "-fd"))
{
canparam->canfd_mode = CAN_FD_MODE;
i++;
baudrate = atoi(param[i]);
switch (baudrate)
{
case 250:
case 500:
case 1000:
case 2000:
case 4000:
case 5000:
canparam->data_baudrate = baudrate * 1000;
break;
}
continue;
}
if (!strcmp(param[i], "-t"))
{
active_send_mode = 1;
i++;
len = strlen(param[i]);
if (len > 0)
{
active_send_num = len;
memcpy(active_send_buff, param[i], len); //要发送的字符串
i++;
len = atoi(param[i]); //发送间隔
if (len > 0)
{
active_send_time = len * 1000; //转换为ms单位
active_send_time_count = active_send_time;
}
}
continue;
}
if (!strcmp(param[i], "-l"))
{
canparam->loopback_mode = 1;
continue;
}
if (!strcmp(param[i], "-L"))
{
loopback_send_mode = 1;
continue;
}
if (!strcmp(param[i], "-v"))
{
printf("can_demo ver: %sn", ver);
continue;
}
}
}
/*
* @description : 主函数
* @param - argc : 参数个数
* @param - *argv: 带入参数数组指针
* @return : 执行结果
*/
int main(int argc, char *argv[])
{
int i = 0, result = 0;
//检测是否有参数
if (argc < 2 || strncmp(argv[1], "can", 3))
{
print_usage(argv[0]);
exit(1);
}
//检测是否有--h或--help
if ((!strcmp(argv[1], "--h")) || (!strcmp(argv[1], "--help")))
{
print_usage(argv[0]);
exit(1);
}
strcpy(dev, argv[1]);
//从main函数带来的参数解析为CAN口参数
get_param(argc, argv, &can_param);
//当知道设备名称时可以直接赋值dev,例strcpy(dev, "can0");
//打开CAN口 创建socket 绑定socket
sock_fd = func_open_can(dev, can_param);
if (sock_fd < 0)
{
printf("Can't Open deveice %s n", dev);
exit(0);
}
else
{
printf("baudrate = %ldK,can_id = 0x%x,can_filter_id = 0x%x,can_filter_mask = 0x%x,extend id = %d,loopback mode = %d,canfd mode = %d,dbaudrate = %ldKn",
can_param.baudrate / 1000, can_param.id, can_param.filter.can_id, can_param.filter.can_mask,
can_param.extend, can_param.loopback_mode, can_param.canfd_mode, can_param.data_baudrate / 1000);
//设置CAN口过滤
result = func_set_can(sock_fd, can_param);
if (result < 0)
{
perror("set_opt error");
exit(0);
}
//设置CAN口为非阻塞方式
fcntl(sock_fd, F_SETFL, O_NONBLOCK); //非阻塞
}
while (1)
{
//接收数据
receive_num = func_receive_can_buff(sock_fd, receive_buff, sizeof(receive_buff));
if (receive_num > 0)
{
printf("[%s nread=%d] ", dev, receive_num);
func_my_print(receive_buff, receive_num, 'c'); //将收到的数据打印出来
}
//组织发送数据
if ((1 == loopback_send_mode) && (receive_num > 0)) //数据回环处理
{
send_num = receive_num;
memcpy(send_buff, receive_buff, receive_num);
}
else if (1 == active_send_mode)
{
if (active_send_time_count >= active_send_time)
{
active_send_time_count = 0;
send_num = active_send_num;
memcpy(send_buff, active_send_buff, active_send_num);
}
else
{
active_send_time_count++;
}
}
//发送数据
if (send_num > 0)
{
real_send_num = func_send_can_buff(sock_fd, send_buff, send_num, can_param);
if (real_send_num > 0)
{
printf("[%s nwrite=%d] ", dev, real_send_num);
func_my_print(send_buff, real_send_num, 'c');
}
memset(send_buff, 0, send_num);
send_num = 0;
}
usleep(1000); // 1ms
}
close(sock_fd);
exit(0);
}
进程名:elf1_cmd_can
使用方法:./elf1_cmd_can 设备名 [参数选项]… …