注意:学习资料可在ElfBoard官方网站“资料”专区获取。
本节用到的源码路径:ELF 1开发板资料包\03-例程源码\03-1 命令行例程源码\06_elf1_cmd_can
can.c
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include /*PPSIX 终端控制定义*/
- #include "mycan.h"
- /*
- * @description : 字符串按格式输出
- * [url=home.php?mod=space&uid=3142012]@param[/url] - *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("%s\n", 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("%s\n", 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("%s\n", 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:%s\n", 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:%s\n", 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 filter\n");
- 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:%s\n", 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
- #include
- #include
- #include
- #include
- #include
- #include /*PPSIX 终端控制定义*/
- #include
- #include
- #include
- #include
- #include
- #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]"
- "\n\t'-b baudrate' for different baudrate, range 5k to 5M,unit is Kbps"
- "\n\t'-id id_numb' for nonzero can send id"
- "\n\t'-filt id mask' for receive can_id and can_mask"
- "\n\t'-e' for extend id frame"
- "\n\t'-fd dbaudrate' for can fd mode , dbaudrate range 250k to 5M,unit is Kbps"
- "\n\t'-t data time' for interval set time actively sends the data, unit is s"
- "\n\t'-l' for can loopback mode"
- "\n\t'-L' for app loopback receive data"
- "\n\t'-rf path' save the data received by the serial port into the file, path for file to save"
- "\n\t'-v' show version"
- "\n\texample : 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"
- "\n\texample : can1 baudrate 250k id 105 filt_id 123 filt_mask 120 extend id --> ./can_demo can1 -b 250 -id 105 -filt 123 1f0"
- "\n\texample : 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"
- "\n\texample : 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"
- "\n\texample : 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 -l\n ",
- 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: %s\n", 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 = %ldK\n",
- 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 设备名 [参数选项]… …
|