对Socket CAN的理解(3)——【Socket CAN发送数据流程】

2023-05-16

转载请注明出处:http://blog.csdn.net/Righthek 谢谢!

    对于本文,我们将从用户层使用Socket CAN进行数据发送时,数据从用户空间到底层驱动的整个通信流程,用户层使用Socket CAN可参考上一篇文章《对Socket CAN的理解(2)——【Socket的原理及使用】》。

    当我们在用户层通过socket进行CAN数据的发送时,需要进行以下操作:

    (1) 创建一个套接字socket,采用AF_CAN协议;

    (2)将创建的套接字返回描述符sockfd,绑定到本地的地址;

    (3)通过sendto系统调用函数进行发送;

sendto的函数声明如下:

int sendto(int sockfd, const void *msg, intlen,unsigned intflags, const struct sockaddr *to, int tolen);

         主要参数说明如下:

         sockfd:通过socket函数生成的套接字描述符;

         msg:该指针指向需要发送数据的缓冲区;

         len:是发送数据的长度;

         to:目标主机的IP地址及端口号信息;

 

    sendto的系统调用会发送一帧数据报到指定的地址,在CAN协议调用之前把该地址移到内核空间和检查用户空间数据域是否可读。

在net/socket.c源文件中,sendto函数的系统调用如下代码:

SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len, unsigned, flags, structsockaddr __user *, addr, int, addr_len)

{

         structsocket *sock;

         structsockaddr_storage address;

         interr;

         structmsghdr msg;

         structiovec iov;

         intfput_needed;

         if(len > INT_MAX)

                   len= INT_MAX;

         sock= sockfd_lookup_light(fd, &err, &fput_needed);

         if(!sock)

                   gotoout;

         iov.iov_base= buff;

         iov.iov_len= len;

         msg.msg_name= NULL;

         msg.msg_iov= &iov;

         msg.msg_iovlen= 1;

         msg.msg_control= NULL;

         msg.msg_controllen= 0;

         msg.msg_namelen= 0;

         /*把用户空间的地址移动到内核空间中*/

         if(addr) {

                   err= move_addr_to_kernel(addr, addr_len,(struct sockaddr *)&address);

                   if(err < 0)

                            gotoout_put;

                   msg.msg_name= (struct sockaddr *)&address;

                   msg.msg_namelen= addr_len;

         }

         if(sock->file->f_flags & O_NONBLOCK)

                   flags|= MSG_DONTWAIT;

         msg.msg_flags= flags;

         err= sock_sendmsg(sock, &msg, len);

}

 

在sendto的系统调用(sys_sendto)里,会调用到sock_sendmsg()函数,该函数代码如下:

int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)

{

         structkiocb iocb;

         structsock_iocb siocb;

         intret;

         init_sync_kiocb(&iocb,NULL);

         iocb.private= &siocb;

         ret= __sock_sendmsg(&iocb, sock, msg, size);

         if(-EIOCBQUEUED == ret)

                   ret= wait_on_sync_kiocb(&iocb);

         returnret;

}

接下来调用__sock_sendmsg()函数。

static inline int __sock_sendmsg(struct kiocb *iocb,struct socket *sock, struct msghdr *msg, size_t size)

{

         interr = security_socket_sendmsg(sock, msg, size);

         returnerr ?: __sock_sendmsg_nosec(iocb, sock, msg, size);

}

再往下一步就是__sock_sendmsg_nosec函数。在__sock_sendmsg_nosec()函数中会返回一个sendmsg函数指针。

static inline int __sock_sendmsg_nosec(struct kiocb*iocb, struct socket *sock, struct msghdr *msg, size_t size)

{

         structsock_iocb *si = kiocb_to_siocb(iocb);

         sock_update_classid(sock->sk);

         si->sock= sock;

         si->scm= NULL;

         si->msg= msg;

         si->size= size;

         returnsock->ops->sendmsg(iocb, sock,msg, size);

}

在/net/can/raw.c源文件中,将raw_sendmsg函数地址赋给sendmsg函数指针,即在函数__sock_sendmsg_nosec()中return sock->ops->sendmsg(iocb,sock, msg, size),返回的函数指针将指向raw_sendmsg()函数。

static const struct proto_ops raw_ops = {

         .family        = PF_CAN,

         .release       = raw_release,

         .bind          = raw_bind,

         .connect       = sock_no_connect,

         .socketpair    = sock_no_socketpair,

         .accept        = sock_no_accept,

         .getname       = raw_getname,

         .poll          = datagram_poll,

         .ioctl         = can_ioctl,    /* use can_ioctl() from af_can.c */

         .listen        = sock_no_listen,

         .shutdown      = sock_no_shutdown,

         .setsockopt    = raw_setsockopt,

         .getsockopt    = raw_getsockopt,

         .sendmsg       = raw_sendmsg,

         .recvmsg       = raw_recvmsg,

         .mmap          = sock_no_mmap,

         .sendpage      = sock_no_sendpage,

};

 

static int raw_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_tsize)

{

         structsock *sk = sock->sk;

         structraw_sock *ro = raw_sk(sk);

         structsk_buff *skb;

         structnet_device *dev;

         intifindex;

         interr;

         if(msg->msg_name) {

                   structsockaddr_can *addr =

                            (structsockaddr_can *)msg->msg_name;

                   if(msg->msg_namelen < sizeof(*addr))

                            return-EINVAL;

                   if(addr->can_family != AF_CAN)

                            return-EINVAL;

                   ifindex= addr->can_ifindex;

         }else

                   ifindex= ro->ifindex;

         if(size != sizeof(struct can_frame))

                   return-EINVAL;

         dev= dev_get_by_index(&init_net, ifindex);

         if(!dev)

                   return-ENXIO;

         skb= sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT,

                                       &err);

         if(!skb)

                   gotoput_dev;

         err= memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);

         if(err < 0)

                   gotofree_skb;

         err= sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags);

         if(err < 0)

                   gotofree_skb;

         /*to be able to check the received tx sock reference in raw_rcv() */

         skb_shinfo(skb)->tx_flags|= SKBTX_DRV_NEEDS_SK_REF;

         skb->dev= dev;

         skb->sk  = sk;

         err= can_send(skb,ro->loopback);

         dev_put(dev);

         if(err)

                   gotosend_failed;

         returnsize;

}

         在net/can/af_can.c源文件中,can_send函数负责CAN协议层的数据传输,即传输一帧CAN报文(可选本地回环)。参数skb指针指向套接字缓冲区和在数据段的CAN帧。loop参数是在本地CAN套接字上为监听者提供回环。

int can_send(struct sk_buff *skb, int loop)

{

         structsk_buff *newskb = NULL;

         structcan_frame *cf = (struct can_frame *)skb->data;

         interr;

         if(skb->len != sizeof(struct can_frame) || cf->can_dlc > 8) {

                   kfree_skb(skb);

                   return-EINVAL;

         }

         if(skb->dev->type != ARPHRD_CAN) {

                   kfree_skb(skb);

                   return-EPERM;

         }

         if(!(skb->dev->flags & IFF_UP)) {

                   kfree_skb(skb);

                   return-ENETDOWN;

         }

         skb->protocol= htons(ETH_P_CAN);

         skb_reset_network_header(skb);

         skb_reset_transport_header(skb);

         if(loop) {

                   /*local loopback of sent CAN frames */

                   /*indication for the CAN driver: do loopback */

                   skb->pkt_type= PACKET_LOOPBACK;

                   if(!(skb->dev->flags & IFF_ECHO)) {

                            /*

                             * If the interface is not capable to doloopback

                             * itself, we do it here.

                             */

                            newskb= skb_clone(skb, GFP_ATOMIC);

                            if(!newskb) {

                                     kfree_skb(skb);

                                     return-ENOMEM;

                            }

                            newskb->sk= skb->sk;

                            newskb->ip_summed= CHECKSUM_UNNECESSARY;

                            newskb->pkt_type= PACKET_BROADCAST;

                   }

         }else {

                   /*indication for the CAN driver: no loopback required */

                   skb->pkt_type= PACKET_HOST;

         }

         /*send to netdevice */

         err= dev_queue_xmit(skb);

         if(err > 0)

                   err= net_xmit_errno(err);

         if(err) {

                   kfree_skb(newskb);

                   returnerr;

         }

         if(newskb)

                   netif_rx_ni(newskb);

         /*update statistics */

         can_stats.tx_frames++;

         can_stats.tx_frames_delta++;

         return0;

}

int dev_queue_xmit(struct sk_buff *skb)

{

         structnet_device *dev = skb->dev;

         structnetdev_queue *txq;

         structQdisc *q;

         intrc = -ENOMEM;

 

         /*Disable soft irqs for various locks below. Also

          * stops preemption for RCU.

          */

         rcu_read_lock_bh();

 

         txq= dev_pick_tx(dev, skb);

         q= rcu_dereference_bh(txq->qdisc);

 

#ifdef CONFIG_NET_CLS_ACT

         skb->tc_verd= SET_TC_AT(skb->tc_verd, AT_EGRESS);

#endif

         trace_net_dev_queue(skb);

         if(q->enqueue) {

                   rc= __dev_xmit_skb(skb, q, dev, txq);

                   gotoout;

         }

         if(dev->flags & IFF_UP) {

                   intcpu = smp_processor_id(); /* ok because BHs are off */

 

                   if(txq->xmit_lock_owner != cpu) {

 

                            if(__this_cpu_read(xmit_recursion) > RECURSION_LIMIT)

                                     gotorecursion_alert;

 

                            HARD_TX_LOCK(dev,txq, cpu);

 

                            if(!netif_tx_queue_stopped(txq)) {

                                     __this_cpu_inc(xmit_recursion);

                                     rc= dev_hard_start_xmit(skb, dev, txq);

                                     __this_cpu_dec(xmit_recursion);

                                     if(dev_xmit_complete(rc)) {

                                               HARD_TX_UNLOCK(dev,txq);

                                               gotoout;

                                     }

                            }

                            HARD_TX_UNLOCK(dev,txq);

                            if(net_ratelimit())

                                     printk(KERN_CRIT"Virtual device %s asks to "

                                            "queue packet!\n", dev->name);

                   }else {

                            /*Recursion is detected! It is possible,

                             * unfortunately

                             */

recursion_alert:

                            if(net_ratelimit())

                                     printk(KERN_CRIT"Dead loop on virtual device "

                                            "%s, fix it urgently!\n",dev->name);

                   }

         }

 

         rc= -ENETDOWN;

         rcu_read_unlock_bh();

 

         kfree_skb(skb);

         returnrc;

out:

         rcu_read_unlock_bh();

         returnrc;

}

int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, structnetdev_queue *txq)

{

         conststruct net_device_ops *ops = dev->netdev_ops;

         intrc = NETDEV_TX_OK;

         unsignedint skb_len;

         if(likely(!skb->next)) {

                   u32features;

                   /*

                    * If device doesn't need skb->dst, releaseit right now while

                    * its hot in this cpu cache

                    */

                   if(dev->priv_flags & IFF_XMIT_DST_RELEASE)

                            skb_dst_drop(skb);

                   if(!list_empty(&ptype_all))

                            dev_queue_xmit_nit(skb,dev);

                   skb_orphan_try(skb);

                   features= netif_skb_features(skb);

 

                   if(vlan_tx_tag_present(skb) &&

                       !(features & NETIF_F_HW_VLAN_TX)) {

                            skb = __vlan_put_tag(skb,vlan_tx_tag_get(skb));

                            if(unlikely(!skb))

                                     gotoout;

                            skb->vlan_tci= 0;

                   }

                   if(netif_needs_gso(skb, features)) {

                            if(unlikely(dev_gso_segment(skb, features)))

                                     gotoout_kfree_skb;

                            if(skb->next)

                                     gotogso;

                   }else {

                            if(skb_needs_linearize(skb, features) &&

                                __skb_linearize(skb))

                                     gotoout_kfree_skb;

                            /*If packet is not checksummed and device does not

                             * support checksumming for this protocol,complete

                             * checksumming here.

                             */

                            if(skb->ip_summed == CHECKSUM_PARTIAL) {

                                     skb_set_transport_header(skb,

                                               skb_checksum_start_offset(skb));

                                     if(!(features & NETIF_F_ALL_CSUM) &&

                                          skb_checksum_help(skb))

                                               gotoout_kfree_skb;

                            }

                   }

                   skb_len= skb->len;

                   rc= ops->ndo_start_xmit(skb, dev);

                   trace_net_dev_xmit(skb,rc, dev, skb_len);

                   if(rc == NETDEV_TX_OK)

                            txq_trans_update(txq);

                   returnrc;

         }

}

         以下开始进行到CAN的底层驱动代码了,由于CAN驱动是编译进内核中,所以在系统启动时会注册CAN驱动,注册CAN驱动过程中会初始化d_can_netdev_ops结构体变量。在这个过程中,d_can_netdev_ops结构体变量定义了3个函数指针,其中(*ndo_start_xmit)函数指针指向d_can_start_xmit函数的入口地址。

static const struct net_device_ops d_can_netdev_ops = {

         .ndo_open= d_can_open,

         .ndo_stop= d_can_close,

         .ndo_start_xmit =d_can_start_xmit,

};

 

static netdev_tx_t d_can_start_xmit(struct sk_buff*skb, structnet_device *dev)

{

         u32msg_obj_no;

         structd_can_priv *priv = netdev_priv(dev);

         structcan_frame *frame = (struct can_frame *)skb->data;

         if(can_dropped_invalid_skb(dev, skb))

                   returnNETDEV_TX_OK;

         msg_obj_no= get_tx_next_msg_obj(priv);

         /*prepare message object for transmission */

         d_can_write_msg_object(dev,D_CAN_IF_TX_NUM, frame, msg_obj_no);

         can_put_echo_skb(skb,dev, msg_obj_no - D_CAN_MSG_OBJ_TX_FIRST);

         /*

          * we have to stop the queue in case of a wraparound or

          * if the next TX message object is still inuse

          */

         priv->tx_next++;

         if(d_can_is_next_tx_obj_busy(priv, get_tx_next_msg_obj(priv)) ||

                   ((priv->tx_next& D_CAN_NEXT_MSG_OBJ_MASK) == 0))

                   netif_stop_queue(dev);

         returnNETDEV_TX_OK;

}

         在d_can_start_xmit()函数中,会调用d_can_write_msg_object()函数准备消息报文进行传输。

static void d_can_write_msg_object(struct net_device *dev, intiface, struct can_frame *frame, int objno)

{

         inti;

         unsignedint id;

         u32dataA = 0;

         u32dataB = 0;

         u32flags = 0;

         structd_can_priv *priv = netdev_priv(dev);

 

         if(!(frame->can_id & CAN_RTR_FLAG))

                   flags|= D_CAN_IF_ARB_DIR_XMIT;

 

         if(frame->can_id & CAN_EFF_FLAG) {

                   id= frame->can_id & CAN_EFF_MASK;

                   flags|= D_CAN_IF_ARB_MSGXTD;

         }else

                   id= ((frame->can_id & CAN_SFF_MASK) << 18);

 

         flags|= D_CAN_IF_ARB_MSGVAL;

         d_can_write(priv,D_CAN_IFARB(iface), IFX_WRITE_IDR(id) | flags);

 

         for(i = 0; i < frame->can_dlc; i++) {

                   if(frame->can_dlc <= 4)

                            dataA|= (frame->data[i] << (8 * i));

                   else{

                            if(i < 4)

                                     dataA|= (frame->data[i] << (8 * i));

                            else

                                     dataB|= (frame->data[i] << (8 * (i - 4)));

                   }

         }

 

         /*DATA write to Message object registers DATAA and DATAB */

         if(frame->can_dlc <= 4)

                   d_can_write(priv,D_CAN_IFDATA(iface), dataA);

         else{

                   d_can_write(priv,D_CAN_IFDATB(iface), dataB);

                   d_can_write(priv,D_CAN_IFDATA(iface), dataA);

         }

 

         /*enable TX interrupt for this message object */

         d_can_write(priv,D_CAN_IFMCTL(iface),

                            D_CAN_IF_MCTL_TXIE| D_CAN_IF_MCTL_EOB |

                            D_CAN_IF_MCTL_TXRQST| D_CAN_IF_MCTL_NEWDAT |

                            frame->can_dlc);

 

         /*Put message data into message RAM */

         d_can_object_put(dev,iface, objno, D_CAN_IF_CMD_ALL);

}

    以上即是作者对Socket CAN进行数据发送的理解。接下来,我们将分析Socket CAN的数据接收!

转载请注明出处:http://blog.csdn.net/Righthek 谢谢!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

对Socket CAN的理解(3)——【Socket CAN发送数据流程】 的相关文章

  • EGO-PLANNER安装问题记录以及如何在Ubuntu22.04LTS上安装ROS noetic

    一 Ubuntu系统版本及ROS版本 笔者误操作升级系统版本到了Ubuntu22 04LTS xff0c 在这个版本中系统不支持ROS1的安装 xff0c 笔者尝试用ROS2运行ego planner xff0c 并未运行成功 xff0c
  • 算法竞赛中常用的STL

    C 43 43 标准模板库 xff08 STL xff09 封装了大量十分有用的数据结构和算法 xff0c 熟练使用STL将会使我们的程序编写如虎添翼 接下来会介绍几种在程序竞赛中常用到的STL类 如果想了解更多 xff0c 推荐直接访问官
  • Lwip从入门到放弃之(一)---基础网络知识扫盲

    Lwip从入门到放弃之 基础网络知识扫盲 一 由于工作中用到了有关Lwip的有关知识 xff0c 本人作为一个网络通信协议的门外汉 xff0c 打算系统的学习一下以太网通讯的有关知识 而Lwip作为一款开源的轻量级TCP IP协议栈 xff
  • nginx电信合规100分配置

    在日常线上部署中 xff0c 总会遇到nginx配置基线漏洞 xff0c 整理了一份nginx100分配置分享下 可以通过基线扫描 nginx conf user nobody worker processes 1 error log lo
  • gitee码云webhook,代码提交后同步到服务器。

    1 创建脚本 xff0c 写入以下内容 脚本放入www根目录下 span class token delimiter important lt php span span class token variable json span spa
  • Socket接口编程

    简介 1 Socket 英文原意是 孔 或者 插座 的意思 在网络编程中 通常将其称之为 套接字 当前网络中的主流程序设计都是使用 Socket 进行编程的 因为它简单易用 更是一个标准 能在不同平台很方便移植 2 socket是统一的编程
  • Linux基础命令-chattr更改文件隐藏属性

    目录 前言 一 chattr命令介绍 二 语法及常用参数和模式 2 1 一样用help或man查看语法 2 2 常用参数 2 3 命令的模式 三 参考实例 3 1 给文件添加无法修改的权限 3 2 从指定文件移除隐藏属性 3 3 给目录添加
  • 四轴飞行器的串级PID参数整定经验

    串级PID即将两个PID控制器按照串联的方式连接起来 xff0c 前一个的输出作为后一个的输入两者共同控制控制对象 对于四旋翼来讲最普通的就是外环角度环 xff0c 内环角速度环 xff0c 两者怎么联系呢 xff0c 有的说法是 xff1
  • 嵌入式C语言复习——Day4

    嵌入式C语言复习 Day4 C语言函数的使用 1 函数概述 xff1a 一堆代码的集合 xff0c 用一个标签去描述它 xff0c 复用化 xff1b 函数三要素 xff1a 1 函数名 xff08 地址 xff09 2 输入参数 3 返回
  • C++基础复习——Day2

    类和对象 封装对象的初始化和清理构造函数和析构函数构造函数的分类及调用拷贝构造函数调用时机深拷贝与浅拷贝 C 43 43 对象模型和this指针友元运算符重载加号运算符重载左移运算符重载递增运算符重载赋值运算符重载 继承继承的基本用法继承方
  • 【模电基础复习】

    模拟电子技术 概念向 1 二极管杂质半导体的形成载流子是什么线性元件与非线性元件PN结形成原理及特性PN结的击穿二极管特性和主要参数二极管应用其他二极管类型 1 思考题为什么称空穴是载流子 xff1f 如何从PN结的电压电流特性方程来理解其
  • 【数电基础复习】

    数字电子技术 概念向 数制和码制数字量与模拟量位权十 二进制运算反码 补码奇偶校验 逻辑函数逻辑代数运算最小项和最大项逻辑函数化简方法 门电路CMOS门电路CMOS反相器CMOS电压传输特性和电流传输特性CMOS反相器静态输入特性和输出特性
  • 数据结构与算法——队列

    数据结构与算法 队列队列的链式存储结构创建一个队列入队列操作 出队列操作销毁一个队列 队列 队列 xff08 queue xff09 是只允许在一端进行插入操作 xff0c 而在另一端进行删除操作的线性表 与栈相反 xff0c 队列是一种先
  • 数据结构与算法——递归和分治

    数据结构与算法 递归斐波那契数列的递归实现 分治 递归 在现实当中 xff0c 我们只有在迫不得已的情况下才使用递归 xff0c 因为递归本身的效率并不理想 xff0c 但他的思想却值得我们留存在记忆之中 斐波那契数列的递归实现 使用递归实
  • 数据结构与算法——字符串

    数据结构与算法 字符串字符串的比较字符串的存储结构BF算法KMP算法 字符串 定义 xff1a 串 String 是由零个或多个字符组成的有限序列 xff0c 又名叫字符串 一般记为 s 61 a1a2a3 an n gt 61 0 串可以
  • 数据结构对齐规则(C语言)

    概念 xff1a 一些概念是为了容易理解 xff0c 自己定义的 1 基本对齐系数 xff1a 默认情况 xff1a 由编译器和操作系统决定 xff0c 一般来说32位系统对齐系数为4 xff08 字节 xff09 xff1b 64位系统对
  • ubuntu grace/xmgrace安装和使用

    grace是什么 xff1f Grace是 GRaphing Advanced Computation and Exploration of data 的缩写 它是在X Window系统和Motif下的所见即所得 xff08 所见及所得 x
  • OFDM多径传输时域和频域模型,以及循环前缀的作用

    1 多径信道传输模型 从信号传输的基本模型入手 考虑如下式所示的线性时不变系统 xff0c y t 61 h
  • 对单片机堆栈的理解

    看关于单片机方面的书籍的时候 xff0c 总是能看到别人说的一些堆栈啊什么的操作 xff0c 之前看到这个术语就直接跳过 xff0c 没想到去探究单片机内部的原理 但是最近课程学习微机原理这门课 xff0c 需要我们写汇编程序 xff0c
  • ROS 中package.xml文件详解01

    package xml文件时每一个ros包都要有的一个文件 xff0c 也是必须要包含的一个文件 1 最简单的xml文件 span class token operator lt span package format span class

随机推荐

  • 常用车载总线CAN、CAN FD、LIN、FlexRay、Ethernet介绍

    文章目录 前言 关于这些总线的详细介绍可分别参考如下 xff1a 一 为什么要这些总线二 车载总线的种类1 CAN1 1 CAN协议简介1 2 CAN协议特点 2 CAN FD2 1 CAN FD协议简介2 2 CAN FD协议特点 3 L
  • Leetcode刷题【8. 字符串转换整数】

    力扣第8题 xff0c 字符串转换整数 atoi 题目描述 xff1a 请你来实现一个 myAtoi string s 函数 xff0c 使其能将字符串转换成一个 32 位有符号整数 xff08 类似 C C 43 43 中的 atoi 函
  • Leetcode刷题【10. 正则表达式匹配】

    力扣第10题 xff0c 正则表达式匹配 题目描述 xff1a 给你一个字符串 s 和一个字符规律 p xff0c 请你来实现一个支持 和 的正则表达式匹配 匹配任意单个字符 匹配零个或多个前面的那一个元素 所谓匹配 xff0c 是要涵盖
  • Jetseon TX2 & IntelRealsense D435i & Python

    Jetseon TX2 amp IntelRealsense D435i amp Python amp Socket 一 IntelRealsense Python Wrapper GitHub 1 Installation pip ins
  • Unix 环境高级编程(一):开发环境

    Unix 环境高级编程 xff08 一 xff09 xff1a 开发环境 一 Unix操作系统二 Linux操作系统三 GNU编译工具 xff08 GCC xff09 1 简介2 基本用法3 文件后缀4 构建过程5 预处理指令6 预定义宏7
  • pyqt判断鼠标点击事件——左键按下、中键按下、右键按下、左右键同时按下等等

    我用自定义的myLabel类继承pyqt中的QLabel类 xff0c 然后在myLabel类中重载了鼠标按下事件函数 xff0c 在这一函数中实现了判断左右中键按下的代码 from PyQt5 import QtCore QtGui Qt
  • 无人驾驶学习笔记--路径规划(一)【Path Finding -- Hybrid A* 】

    无人驾驶学习笔记 路径规划 xff08 一 xff09 Path Finding Hybrid A 混合A算法 xff08 Hybrid A xff09 It uses continuous search space 连续空间It alwa
  • rosbag remp 以及/velodyne_packets和/velodyne_points的相互转换

    在采集velodyne雷达数据的时候 xff0c 本来想要采集的是 velodyne points topic xff0c 却不小心复制成了 velodyne packets topic 采完数据才发现不对 xff0c 一脸懵逼 赶紧查一下
  • 串口调试助手vc源程序及其详细编写过程

    目次 xff1a 1 建立项目 2 在项目中插入MSComm控件 3 利用ClassWizard定义CMSComm类控制变量 4 在对话框中添加控件 5 添加串口事件消息处理函数OnComm 6 打开和设置串口参数 7 发送数据 8 发送十
  • 18张含金量最高的大数据证书

    这年头从事数据行业很不赖 用人需求量之大达到创记录的水平 xff0c 薪资也水涨船高 几乎任何数据认证都会让你的薪资涨一涨 本文介绍了哪几大数据认证可以让你稳赚丰厚薪水 顶级数据技能拿顶薪 你是不是在想 xff1a 为获得那下一份数据认证付
  • XML解析——Java中XML的四种解析方式

    XML是一种通用的数据交换格式 它的平台无关性 语言无关性 系统无关性 给数据集成与交互带来了极大的方便 XML在不同的语言环境中解析方式都是一样的 只不过实现的语法不同而已 XML的解析方式分为四种 xff1a 1 DOM解析 xff1b
  • JVM调优总结 -Xms -Xmx -Xmn -Xss

    Xms 是指设定程序启动时占用内存大小 一般来讲 xff0c 大点 xff0c 程序会启动的快一点 xff0c 但是也可能会导致机器暂时间变慢 Xmx 是指设定程序运行期间最大可占用的内存大小 如果程序运行需要占用更多的内存 xff0c 超
  • Spring Boot 传参方式

    最近在搞Spring Boot的项目 xff0c 把传参方式总结一下 网上也参考一些文章 xff0c 总结的很不错 xff0c 这里借鉴一下 注解 64 RequestParam 这个注解用来绑定单个请求数据 xff0c 既可以是url中的
  • Java BigDecimal开方

    前言 一般开平方使用的是Math中的静态方法Math sqrt double a xff0c 涉及到金融计算的时候 xff0c Math sqrt double a 精度就不够了 金融领域的计算 xff0c 用的都是BigDecimal类型
  • Spring Boot 集成RabbitMQ

    RabbitMQ is an open source multi protocol messaging broker 前言 参照官方Messaging with RabbitMQ xff0c 记录在实战中的一些坑 搭建RabbitMQ服务
  • Java 获取接口所有实现类

    利用Spring的Bean工厂 xff0c 获取接口所有实现类 前言 在学习Spring Boot 集成RabbitMQ时 xff0c 发现定义了好几个bean xff0c 这些bean在什么地方用到呢 xff1f 查看RabbitAdmi
  • Intellij IDEA-SSH executable-Native

    Connecting to gitlab using PuTTY generated SSH key in IDEA 背景 项目开发中 xff0c 使用Gitlab搭建git服务 xff0c 做代码的版本管理 xff0c 一开始是使用htt
  • 匿名四轴PID参数调试讲解

    过程详解 1 要在飞机的起飞油门基础上进行PID参数的调整 xff0c 否则 烤四轴 的时候调试稳定了 xff0c 飞起来很可能又会晃荡 2 内环的参数最为关键 xff01 理想的内环参数能够很好地跟随打舵 xff08 角速度控制模式下的打
  • 使用cv2eigen或eigen2cv时注意头文件包含顺序

  • 对Socket CAN的理解(3)——【Socket CAN发送数据流程】

    转载请注明出处 xff1a http blog csdn net Righthek 谢谢 xff01 对于本文 xff0c 我们将从用户层使用Socket CAN进行数据发送时 xff0c 数据从用户空间到底层驱动的整个通信流程 xff0c