前言

本文主要介绍socketCan中的发送函数cansend的源码解析.

代码

/*
* cansend.c - simple command line tool to send CAN-frames via CAN_RAW sockets
*
* Copyright (c) 2002-2007 Volkswagen Group Electronic Research
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Volkswagen nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* Alternatively, provided that this notice is retained in full, this
* software may be distributed under the terms of the GNU General
* Public License ("GPL") version 2, in which case the provisions of the
* GPL apply INSTEAD OF those given above.
*
* The provided data structures and external interfaces from this code
* are not restricted to be used by modules with a GPL compatible license.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* Send feedback to <linux-can@vger.kernel.org>
*
*/ #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> #include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h> #include <linux/can.h>
#include <linux/can/raw.h> #include "lib.h" int main( )
{
int s; /* can raw socket */
int required_mtu;
int mtu;
int enable_canfd = ;
struct sockaddr_can addr;
struct canfd_frame frame;
struct ifreq ifr; char* input = "008#abcd1234cdef567830";
/* parse CAN frame */
required_mtu = parse_canframe(input, &frame);
printf("required_mtu is %d\n", required_mtu);
printf("CAN_MTU is %d\n", (long unsigned int)CAN_MTU);
//printf("CANID_DELIM is %d\n", CANID_DELIM);//#-35-0x23.
printf("IFNAMSIZ is %d\n", IFNAMSIZ);
if (!required_mtu){
fprintf(stderr, "\nWrong CAN-frame format! Try:\n\n");
fprintf(stderr, " <can_id>#{R|data} for CAN 2.0 frames\n");
fprintf(stderr, " <can_id>##<flags>{data} for CAN FD frames\n\n");
fprintf(stderr, "<can_id> can have 3 (SFF) or 8 (EFF) hex chars\n");
fprintf(stderr, "{data} has 0..8 (0..64 CAN FD) ASCII hex-values (optionally");
fprintf(stderr, " separated by '.')\n");
fprintf(stderr, "<flags> a single ASCII Hex value (0 .. F) which defines");
fprintf(stderr, " canfd_frame.flags\n\n");
fprintf(stderr, "e.g. 5A1#11.2233.44556677.88 / 123#DEADBEEF / 5AA# / ");
fprintf(stderr, "123##1 / 213##311\n 1F334455#1122334455667788 / 123#R ");
fprintf(stderr, "for remote transmission request.\n\n");
return ;
} /* open socket */
if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < ) {
perror("socket");
return ;
} const char* ifrname = "can1";
strcpy(ifr.ifr_name, ifrname);
ifr.ifr_ifindex = if_nametoindex(ifr.ifr_name);
if (!ifr.ifr_ifindex) {
perror("if_nametoindex");
return ;
} memset(&addr, , sizeof(addr));
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
/*
if (required_mtu > CAN_MTU) { //* check if the frame fits into the CAN netdevice
if (ioctl(s, SIOCGIFMTU, &ifr) < 0) {
perror("SIOCGIFMTU");
return 1;
}
mtu = ifr.ifr_mtu; if (mtu != CANFD_MTU) {
printf("CAN interface is not CAN FD capable - sorry.\n");
return 1;
} //* interface is ok - try to switch the socket into CAN FD mode
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES,
&enable_canfd, sizeof(enable_canfd))){
printf("error when enabling CAN FD support\n");
return 1;
} //* ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64
frame.len = can_dlc2len(can_len2dlc(frame.len));
}
*/ /* disable default receive filter on this RAW socket */
/* This is obsolete as we do not read from the socket at all, but for */
/* this reason we can remove the receive list in the Kernel to save a */
/* little (really a very little!) CPU usage. */
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, ); if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < ) {
perror("bind");
return ;
} /* send frame */
printf("frame.len is %d\n", frame.len);
printf("frame.can_id is %x\n", frame.can_id);
if (write(s, &frame, required_mtu) != required_mtu) {
perror("write");
return ;
} close(s); return ;
}

解析

1.message的格式;

    char* input = "008#abcd1234cdef567830";

其中‘008表示can_id,必须是三位十六进制数据,可以表示标准帧或者扩展帧;符号#“是can_id和can数据的分界符,最后的数据是报文的数据,标准帧一次最多只能发送8bits的数据,多余的数据自动丢弃;

2.parse_canframe函数,具体内容可参考lib.h和lib.c文件;

int parse_canframe(char *cs, struct canfd_frame *cf);
 /* parse CAN frame */
 required_mtu = parse_canframe(input, &frame);

function -- Transfers a valid ASCII string decribing a CAN frame into struct canfd_frame.

3.创建socket;

s = socket(PF_CAN, SOCK_RAW, CAN_RAW)

创建socket套接字

PF_CAN 为域位,同网络编程中的AF_INET,即ipv4协议;

SOCK_RAW使用的协议类型,SOCK_RAW表示原始套接字,报文头由自己创建;

CAN_RAW为使用的具体协议,为can总线协议;

4. 指定can口名称;

const char* ifrname = "can1";

5.发送数据则禁止过滤;

setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, ); //Disable filter.

6.绑定socketCan;

bind(s, (struct sockaddr *)&addr, sizeof(addr)

bind函数用于绑定套接字,即将套接字和canbus外设进行绑定;

7.发送数据;

  /* send frame */
if (write(s, &frame, required_mtu) != required_mtu) { //发送数据!
perror("write");
return ;
}

8.数据格式的定义;

struct can_frame {
canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
__u8 can_dlc; /* frame payload length in byte (0 .. CAN_MAX_DLEN) */
__u8 __pad; /* padding */
__u8 __res0; /* reserved / padding */
__u8 __res1; /* reserved / padding */
__u8 data[CAN_MAX_DLEN] __attribute__((aligned()));
};
struct canfd_frame {
canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
__u8 len; /* frame payload length in byte */
__u8 flags; /* additional flags for CAN FD */
__u8 __res0; /* reserved / padding */
__u8 __res1; /* reserved / padding */
__u8 data[CANFD_MAX_DLEN] __attribute__((aligned()));
}; #define CAN_MTU (sizeof(struct can_frame))
#define CANFD_MTU (sizeof(struct canfd_frame))

struct can_frame - basic CAN frame structure;

struct canfd_frame - CAN flexible data rate frame structure;

参考

1.linux平台can总线编程模型

2.can-utils-git

can-utils源码解析cansend的更多相关文章

  1. 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新

    [原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...

  2. 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新

    上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...

  3. Retrofit2 源码解析

    原文链接:http://bxbxbai.github.io/2015/12/13/retrofit2-analysis/ 公司里最近做的项目中网络框架用的就是Retrofit,用的多了以后觉得这个框架 ...

  4. Retrofit2.0源码解析

    欢迎访问我的个人博客 ,原文链接:http://wensibo.net/2017/09/05/retrofit/ ,未经允许不得转载! 今天是九月的第四天了,学校也正式开学,趁着大学最后一年的这大好时 ...

  5. iview源码解析(1)

    概述 公司技术栈开始用vue主导开发,但因为公司前端会vue的不多所以在项目中用到vue的技术不是很深,之前出去面试被接连打击,而且本来打算开始为公司vue的项目构建自己的组件库所以去下载了iview ...

  6. elementUi源码解析(1)--项目结构篇

    因为在忙其他事情好久没有更新iview的源码,也是因为后面的一些组件有点复杂在考虑用什么方式把复杂的功能逻辑简单的展示出来,还没想到方法,突然想到element的组件基本也差不多,内部功能的逻辑也差不 ...

  7. element-ui 源码解析 二

    Carousel 走马灯源码解析 1. 基本原理:页面切换 页面切换使用的是 transform 2D 转换和 transition 过渡 可以看出是采用内联样式来实现的 举个栗子 <div : ...

  8. 第三十六节,目标检测之yolo源码解析

    在一个月前,我就已经介绍了yolo目标检测的原理,后来也把tensorflow实现代码仔细看了一遍.但是由于这个暑假事情比较大,就一直搁浅了下来,趁今天有时间,就把源码解析一下.关于yolo目标检测的 ...

  9. t-io 集群解决方案以及源码解析

    t-io 集群解决方案以及源码解析 0x01 概要说明 本博客是基于老谭t-io showcase中的tio-websocket-showcase 示例来实现集群.看showcase 入门还是挺容易的 ...

随机推荐

  1. Python day20正则表达式和re方法

    元字符6个函数以及几个元字符1.'.'通配符2.'^'以什么开头3.'$'以什么结尾4.'*'紧挨着的字符0~∞次5.'+'紧挨着的字符1~∞次6.'?'紧挨的字符0次或1次7.'{}' {0,}== ...

  2. 棋盘覆盖问题(算法分析)(Java版)

    1.问题描述: 在一个2k×2k个方格组成的棋盘中,若有一个方格与其他方格不同,则称该方格为一特殊方格,且称该棋盘为一个特殊棋盘.显然特殊方格在棋盘上出现的位置有种情形.因而对任何 k≥0,有4k种不 ...

  3. 阿里官方Java代码规范标准

    阿里官方Java代码规范标准<阿里巴巴Java开发手册 终极版 v1.3.0>下载 https://www.cnblogs.com/han-1034683568/p/7680354.htm ...

  4. Mac百度云盘不限速操作步骤

    第一步:下载所需工具:(①②步我放在同一个文件夹,可一起下载,链接失效请留言) 工具地址:链接: https://pan.baidu.com/s/1raicYzM 密码: ve3n ①下载Aria2G ...

  5. Oracle 声明常量 (转)

    原文地址 Oracle 声明常量 常量在声明时赋予初值,并且在运行时不允许重新赋值.使用CONSTANT关键字声明常量. 声明常量 DECLARE pi CONSTANT number :=3.14; ...

  6. zk客户端的ClientCnxn类

    ClientCnxn是客户端的类:该类管理zk客户端的socket io,维持一个可用服务器的列表. //ClientCnxn类 private final LinkedList<Packet& ...

  7. 实现自己的ls命令

    一步步实现,先看最简单的ls的指令: ls不带参数,直接打印文件名 dst.txt main10.c main11.c main12.c main13.c main14.c~ main15.c~ ma ...

  8. Wifi Troughput Test using iperf

    learning wifi throughput test using iperf [Purpose]        Learning how to do wifi throughput test u ...

  9. ajax post提交空字符串(string.Empty) MVC接收为null的问题

    ajax post提交空字符串(string.Empty) MVC接收为null的问题 这个问题查了好多资料才知道原因: if (bindingContext.ModelMetadata.Conver ...

  10. Spring学习笔记之Testing

    测试嘛,一般也就两种,一种就是单元测试,另外一个就是集成测试.都是废话 一.单元测试 以前也就是搞个模拟,main函数一写搞定. 现在呢,有了个spring,也有了个推荐规范?这个是个什么东西?什么叫 ...