前言

本文主要介绍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. [原][OSG]深入osg函数----SceneView::cull 函数

    参考:最长一帧 先介绍几个类: osgUtil::CullVisitor:“筛选访问器” 当我们使用它遍历场景图形的各个节点时, CullVisitor 将会对每一个遇到的节点执行场景筛选的工作,判断 ...

  2. 【Golang】 可以自动生成测试用例的库--gotests

    简介 gotests是一个Golang命令行工具,它可以使编写Go的测试代码变得容易.它能基于目标源文件的函数和方法生成数据驱动测试用例,并且在此过程会自动导入任何依赖. 下面是gotests在使用S ...

  3. spring事务管理方式大全

    http://blog.csdn.net/baibinboss/article/details/64922472

  4. CSS3 媒体查询@media 查询(响应式布局)

    例:如果文档宽度小于 300 像素则修改背景颜色(background-color): @media screen and (max-width: 300px) { body { background ...

  5. Python 爬虫-BeautifulSoup

    2017-07-26 10:10:11 Beautiful Soup可以解析html 和 xml 格式的文件. Beautiful Soup库是解析.遍历.维护“标签树”的功能库.使用Beautifu ...

  6. 『Os』常用方法记录

    os.rename(name_old, name_new) 『Scrapy』爬取斗鱼主播头像 重命名函数os.rename比win下的重命名强多了,它可以对路径重命名达到修改文件位置的功效. os.p ...

  7. WaitForMultipleObjects用法详解

    本文转载于:http://blog.csdn.net/sac761/article/details/52456385 WaitForMultipleObjects是Windows中的一个功能非常强大的 ...

  8. UVA-1626 Brackets sequence (简单区间DP)

    题目大意:给一个有小括号和中括号组成的序列,满足题中的三个条件时,是合法的.不满足时是不合法的,问将一个不合法的序列最少添加几个括号可以使之变成合法的.输出最短合法序列. 题目分析:这是<入门经 ...

  9. 硬盘分区表知识——详解硬盘MBR (转)

    Ref: http://www.blogjava.net/galaxyp/archive/2010/04/25/319344.html 硬盘是现在计算机上最常用的存储器之一.我们都知道,计算机之所以神 ...

  10. 55. 45. Jump Game II *HARD*

    1. Given an array of non-negative integers, you are initially positioned at the first index of the a ...