前言

本文主要介绍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. Nginx 多重条件判断

    server{ listen 80; server_name xxx.com; index index.html index.htm index.php admin.php; root /home/w ...

  2. Python day15装饰器基本理论,以及结合全局变量模拟session

    装饰器(decorator):为其他函数添加附加功能 原则:1.不修改被修饰函数源代码 2.不修改被修饰函数的调用方式 装饰器=高阶函数+函数嵌套+闭包 import time def timmer( ...

  3. IIS中发布后出现Could not load file or assembly'System.Data.SQLite.dll' or one of its depedencies

    [问题]在我本机的开发环境c#连接sqlite3没有问题,可是release版本移植到其他的机器就提示Could not load file or assembly'System.Data.SQLit ...

  4. Redis分布式锁实现简单秒杀功能

    这版秒杀只是解决瞬间访问过高服务器压力过大,请求速度变慢,大大消耗服务器性能的问题. 主要就是在高并发秒杀的场景下,很多人访问时并没有拿到锁,所以直接跳过了.这样就处理了多线程并发问题的同时也保证了服 ...

  5. YII第三步,日志开启

    YII第三步,日志开启 index.php入口文件配置: defined('YII_DEBUG') or define('YII_DEBUG',true); cofig/main.php 'prelo ...

  6. 使用Jenkins实现maven项目一键部署

    下面的博客请详细的,值得一看:jenkins+maven+svn实现简单的一键发布 http://blog.csdn.net/pein_zero/article/details/52597615#co ...

  7. 20170706wdVBA保存图片到本地API

    Private Type GUID Data1 As Long Data2 As Integer Data3 As Integer Data4(0 To 7) As Byte End Type Pri ...

  8. Java基础-String和StringBuilder类型(11)

    String类概述 字符串是由多个字符组成的一串数据字符串可以看成是字符数组 构造方法 public String(String original)public String(char[] value ...

  9. SourceTree

    MAC上最好的GIT免费GUI工具是SourceTree(没有之一).此外,最好的GIT代码开源网站是GitHub,最好的GIT代码私有库是BitBucket https://www.sourcetr ...

  10. Generate PDF in Sourcing through concurrent request,在EBS java并发中调用指定am的方法

    package oracle.apps.pon.printing.cp; import java.io.InputStream; import java.io.FileOutputStream; im ...