am335x Qt SocketCAN Demo hacking

/***********************************************************************************
 *                    am335x Qt SocketCAN Demo hacking
 *  说明:
 *      本源代码来自OK335xS,主要是为分析如何在Qt中使用SocketCAN的这种通信方式。
 *
 *                                          2015-9-12 晴 深圳 南山平山村 曾剑锋
 **********************************************************************************/

cat main.c
    #include <QtGui/QApplication>
    #include "mainwindow.h"
    #include "myinputpanelcontext.h"

    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        /**
         * 创建软键盘
         */
        MyInputPanelContext *ic = new MyInputPanelContext;
        /**
         * This function replaces the QInputContext instance used by the application with inputContext.
         * Qt takes ownership of the given inputContext.
         *
         * 设置软键盘
         */
        a.setInputContext(ic); //将输入上下文与应用程序关联

        MainWindow w;
        /**
         * Qt::WindowMaximizeButtonHint:
         *        Adds a maximize button. On some platforms this implies Qt::WindowSystemMenuHint for it to work.
         * Qt::WindowMinimizeButtonHint:
         *     Adds a minimize button. On some platforms this implies Qt::WindowSystemMenuHint for it to work.
         */
        w.setWindowFlags(w.windowFlags()& ~Qt::WindowMaximizeButtonHint& ~Qt::WindowMinimizeButtonHint);
        w.showMaximized();
        w.show();

       return a.exec();
    }

cat  mainwindow.h
    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H

    #include <QMainWindow>
    #include <QProcess>
    #include <sys/ioctl.h>
    #include <net/if.h>
    #include <linux/can.h>
    #include "thread.h"
    #include <QButtonGroup>

    /**
     * 引入界面文件生成的UI类
     */
    namespace Ui {
    class MainWindow;
    }

    class MainWindow : public QMainWindow
    {
        Q_OBJECT

    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    protected:
        void moveEvent(QMoveEvent *);        // 界面移动事件
        void resizeEvent(QResizeEvent *);    // 界面重绘大小事件
        void closeEvent(QCloseEvent *);      // 界面关闭事件
    private slots:
        void on_send_clicked();              // 发送按钮点击槽
        void msg(QString str);               // 信息处理信号槽
        void stopcan(int v);                 // 停止can信号槽
        void startcan(int v);                // 开始can信号槽
        void on_can0_toggled(bool checked);  // can0 被点击翻转信号槽
        void on_can1_toggled(bool checked);  // can1 被点击翻转信号槽

    private:
        Ui::MainWindow *ui;                  // 声明图形界面指针
        int socket;                          // can socket 描述符
        struct sockaddr_can addr;            // can socket 地址结构体
        Thread *t;                           // 线程
        QButtonGroup* btg;                   // 按钮
    };

    #endif // MAINWINDOW_H

cat  mainwindow.c
    #include <sys/ioctl.h>
    #include <fcntl.h>
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include <QMessageBox>
    #include <unistd.h>

    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),            // 构造函数初始化父类构造函数
        ui(new Ui::MainWindow)          // 创建ui实体,并赋值
    {
        ui->setupUi(this);              // 设置将图形界面放置在哪个对象上

        btg = new QButtonGroup;         // 创建分组,多选一
        btg->addButton(ui->can0,0);
        btg->addButton(ui->can1,1);

        startcan(0);
    }

    MainWindow::~MainWindow()
    {
        /**
         * 这里让人怀疑,都已经删除了ui界面,button group又怎么能够获取到ui里面的checkedId呢?
         * 唯一的解释就是button group里面保存了最后一次toggle事件获取的checkedId值,而不是运行
         * checkedId()的时候去获取checkedId
         */
        delete ui;
        stopcan(btg->checkedId());
    }

    void MainWindow::msg(QString str)
    {
        /**
         * 将获取到的信息放到显示文本框的最后去
         */
        ui->label->append(str);
    }

    void MainWindow::on_send_clicked()
    {
        /**
         * struct can_frame - basic CAN frame structure
         * @can_id:  CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition
         * @can_dlc: frame payload length in byte (0 .. 8) aka data length code
         *           N.B. the DLC field from ISO 11898-1 Chapter 8.4.2.3 has a 1:1
         *           mapping of the ‘data length code‘ to the real payload length
         * @data:    CAN frame payload (up to 8 byte)
         *
         * 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    data[CAN_MAX_DLEN] __attribute__((aligned(8)));
         * };
         */
        struct can_frame frame;
        /**
         * 获取将要发送的文本内容
         * Returns a std::string object with the data contained in this QString.
         * The Unicode data is converted into 8-bit characters using the toUtf8() function.
         */
        std::string  str=ui->edit->text().toStdString();

        /**
         * 如果文本的长度大于8,那么将给出提示信息,并直接返回,不发送数据
         */
        if(str.length() > 8)
        {
            QMessageBox::about(this,"error","length of send string must less than 8 bytes");
            return;
        }

        /**
         * 默认发送的can id是0x123
         *
         * 扩展格式识别符由 29 位组成。其格式包含两个部分:11 位基本 ID、18 位扩展 ID。
         * Controller Area Network Identifier structure:
         *
         * bit 0-28     : CAN识别符 (11/29 bit)
         * bit 29       : 错误帧标志 (0 = data frame, 1 = error frame)
         * bit 30       : 远程发送请求标志 (1 = rtr frame)
         * bit 31       : 帧格式标志 (0 = standard 11 bit, 1 = extended 29 bit)
         *
         * typedef __u32 canid_t;
         *
         * struct can_frame {
         *      canid_t can_id;  // 32 bit CAN_ID + EFF/RTR/ERR flags
         *       __u8    can_dlc; // 数据长度: 0 .. 8
         *       __u8    data[8] __attribute__((aligned(8)));
         *  };
         */
        frame.can_id = 0x123;
        /**
         * Returns a pointer to an array that contains a null-terminated sequence of
         * characters (i.e., a C-string) representing the current value of the string object.
         * This array includes the same sequence of characters that make up the value of
         * the string object plus an additional terminating null-character (‘\0‘) at the end.
         */
        strcpy((char*)frame.data, str.c_str());
        /**
         * 目前猜测:dlc --> data length count
         * 于是可以很好的解释:can 发送的数据长度,是按字节算的
         */
        frame.can_dlc = str.length();

        /**
         * Send N bytes of BUF on socket FD to peer at address ADDR (which is
         * ADDR_LEN bytes long).  Returns the number sent, or -1 for errors.
         *
         * This function is a cancellation point and therefore not marked with
         * __THROW.
         *
         * extern ssize_t sendto (int __fd, __const void *__buf, size_t __n,
         *         int __flags, __CONST_SOCKADDR_ARG __addr,
         *         socklen_t __addr_len);
         */
        sendto(socket,&frame,sizeof(struct can_frame),0,(struct sockaddr*)&addr,sizeof(addr));
    }

    void MainWindow::moveEvent(QMoveEvent *)
    {
        /**
         * 让测试窗口不会被移动
         */
        this->move(QPoint(0,0));
    }

    void MainWindow::resizeEvent(QResizeEvent *)
    {
        /**
         * 让窗口最大化显示
         */
        this->showMaximized();
    }

    void MainWindow::closeEvent(QCloseEvent *)
    {
        /**
         * 直接退出,不用关闭can口么?也就是说程序会在真正推出前,先解析掉所有当前生成的类实体?
         */
         exit(0);
    }

    void MainWindow::startcan(int v)
    {
        /**
         * 从提示信息可以看出,使用125000作为默认的波特率
         */
        if(v == 0)
        {
            system("canconfig can0 bitrate 125000 ctrlmode triple-sampling on");
            system("canconfig can0 start");
        }
        else
        {
            system("canconfig can1 bitrate 125000 ctrlmode triple-sampling on");
            system("canconfig can1 start");
        }

        /**
         * Create a new socket of type TYPE in domain DOMAIN, using
         * protocol PROTOCOL.  If PROTOCOL is zero, one is chosen automatically.
         * Returns a file descriptor for the new socket, or -1 for errors.
         *
         * extern int socket (int __domain, int __type, int __protocol) __THROW;
         *
         * #define PF_CAN        29    // Controller Area Network.
         *
         * SOCK_RAW = 3,               // Raw protocol interface.
         * #define SOCK_RAW SOCK_RAW
         *
         * particular protocols of the protocol family PF_CAN
         * #define CAN_RAW        1    // RAW sockets
         *
         */
        socket =  ::socket(PF_CAN, SOCK_RAW, CAN_RAW);

        /**
         * struct ifreq
         * {
         *  # define IFHWADDRLEN    6
         *  # define IFNAMSIZ    IF_NAMESIZE
         *    union
         *    {
         *          char ifrn_name[IFNAMSIZ];    // Interface name, e.g. "en0".
         *    } ifr_ifrn;
         *
         *    union
         *    {
         *          struct sockaddr ifru_addr;
         *          struct sockaddr ifru_dstaddr;
         *          struct sockaddr ifru_broadaddr;
         *          struct sockaddr ifru_netmask;
         *          struct sockaddr ifru_hwaddr;
         *          short int ifru_flags;
         *          int ifru_ivalue;
         *          int ifru_mtu;
         *          struct ifmap ifru_map;
         *          char ifru_slave[IFNAMSIZ];    // Just fits the size
         *          char ifru_newname[IFNAMSIZ];
         *          __caddr_t ifru_data;
         *    } ifr_ifru;
         * };
         * # define ifr_name    ifr_ifrn.ifrn_name            // interface name
         * # define ifr_hwaddr    ifr_ifru.ifru_hwaddr        // MAC address
         * # define ifr_addr    ifr_ifru.ifru_addr            // address
         * # define ifr_dstaddr    ifr_ifru.ifru_dstaddr      // other end of p-p lnk
         * # define ifr_broadaddr    ifr_ifru.ifru_broadaddr  // broadcast address
         * # define ifr_netmask    ifr_ifru.ifru_netmask      // interface net mask
         * # define ifr_flags    ifr_ifru.ifru_flags          // flags
         * # define ifr_metric    ifr_ifru.ifru_ivalue        // metric
         * # define ifr_mtu    ifr_ifru.ifru_mtu              // mtu
         * # define ifr_map    ifr_ifru.ifru_map              // device map
         * # define ifr_slave    ifr_ifru.ifru_slave          // slave device
         * # define ifr_data    ifr_ifru.ifru_data            // for use by interface
         * # define ifr_ifindex    ifr_ifru.ifru_ivalue       // interface index
         * # define ifr_bandwidth    ifr_ifru.ifru_ivalue     // link bandwidth
         * # define ifr_qlen    ifr_ifru.ifru_ivalue          // queue length
         * # define ifr_newname    ifr_ifru.ifru_newname      // New name
         * # define _IOT_ifreq    _IOT(_IOTS(char),IFNAMSIZ,_IOTS(char),16,0,0)
         * # define _IOT_ifreq_short _IOT(_IOTS(char),IFNAMSIZ,_IOTS(short),1,0,0)
         * # define _IOT_ifreq_int    _IOT(_IOTS(char),IFNAMSIZ,_IOTS(int),1,0,0)
         *
         * SIOCGIFINDEX:
         *     Retrieve the interface index of the interface into ifr_ifindex.
         */
        struct ifreq ifr;
        strcpy((char *)(ifr.ifr_name),v == 0 ? "can0" : "can1");
        ioctl(socket,SIOCGIFINDEX,&ifr);

        /**
         * 绑定socket
         */
        addr.can_family = AF_CAN;
        addr.can_ifindex = ifr.ifr_ifindex;
        bind(socket,(struct sockaddr*)&addr,sizeof(addr));

        /**
         * 这里是存在问题,每次线程并没有关闭,而是直接不管,可能导致一些问题
         * 从后续的代码可以看出,每次都已经停止了线程,delete了对象实体。
         */
        t = NULL;

        /**
         * 创建线程,并将socket文件描述符作为参数传入线程,主要作为接受数据线程
         */
        t = new Thread(socket);

        /**
         * 用于处理线程发出的信号
         */
        connect(t,SIGNAL(msg(QString)),this,SLOT(msg(QString)));

        /**
         * 开启线程
         */
        t->start();
    }

    void MainWindow::stopcan(int v)
    {
        /**
         * 关闭对应的can之前,先关闭对应socket接受线程
         */
        if(t)
        {
            t->stop();
            t->deleteLater();
        }

        /**
         * 关闭socket文件描述符
         */
        ::close(socket);

        /**
         * 给出相关的提示信息
         */
        if(v == 0)
            system("canconfig can0 stop");
        else
            system("canconfig can1 stop");
    }

    void MainWindow::on_can0_toggled(bool checked)
    {
        /**
         * 根据对应的情况,打开,或者关闭对应的can设备
         */
        if(checked)
        {
            stopcan(1);
            startcan(0);
        }
    }

    void MainWindow::on_can1_toggled(bool checked)
    {
        /**
         * 根据对应的情况,打开,或者关闭对应的can设备
         */
        if(checked)
        {
            stopcan(0);
            startcan(1);
        }
    }
    
时间: 2024-10-18 04:22:50

am335x Qt SocketCAN Demo hacking的相关文章

Qt QML referenceexamples attached Demo hacking

/********************************************************************************************* * Qt QML referenceexamples attached Demo hacking * 说明: * 1. 本源代码来自Qt自带的Example,而本文也仅仅是代码解读,需要有点基础: * 2. 由于是Qt自带Demo,分为几个文件,文件存在联系,而本人把所有代码放在这个文件里,会照成阅读困难:

Linux SocketCan client server demo hacking

/*********************************************************************** * Linux SocketCan client server demo hacking * 说明: * 本文主要是解读Linux上的SocketCan的基本使用方法,内容和Linux上的 * 网络编程差不多. * * 2016-3-28 深圳 南山平山村 曾剑锋 ********************************************

Cmockery macro demo hacking

/********************************************************************* * Cmockery macro demo hacking * 说明: * 本文记录对Cmockery的宏使用的示例进行测试.跟踪. * * 2016-5-7 深圳 南山平山村 曾剑锋 ********************************************************************/ 一.cat src/exampl

ti processor sdk linux am335x evm setup.sh hacking

#!/bin/sh # # ti processor sdk linux am335x evm setup.sh hacking # 说明: # 本文主要对TI的sdk中的setup.sh脚本进行解读,是为了了解其工作机制. # 该文件中主要时调用bin下的脚本. # # 2016-4-16 深圳 南山平山村 曾剑锋 # This distribution contains contributions or derivatives under copyright # as follows: #

Qt: 时钟Demo

其实是一个很简单的Demo,可以编译了拿NSIS打包.最近在做富文本编辑器和补C++不记得的东西吧,项目遥遥无期. 1 //clock.pro 2 3 #------------------------------------------------- 4 # 5 # Project created by QtCreator 2016-07-26T19:06:54 6 # 7 #------------------------------------------------- 8 9 QT +=

QT委托demo

class SpinBoxDeegate1 :public QStyledItemDelegate{ Q_OBJECTpublic: SpinBoxDeegate1(QObject* parent = 0); QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; void setEditorData(QWidget *editor

QT Demo 之 calqlatr(1) main.cpp

其实从最开始要学习和分析Qt的Demo时选定的就是calqlatr工程,但是打开源码一看,貌似难度高了点,这才有了上面的几篇基本控件的分析.从这一章开始,我要拿下calqlatr这个Demo项目了. main.cpp main.cpp中的代码非常简单: #include "../../shared/shared.h" DECLARATIVE_EXAMPLE_MAIN(demos/calqlatr/calqlatr) DECLARATIVE_EXAMPLE_MAIN(NAME)是一个函数

Qt5官方demo解析集15——Chapter 1: Creating a New Type

本系列所有文章可以在这里查看http://blog.csdn.net/cloud_castle/article/category/2123873 前面我们说到了QML的粒子系统,它可以创造丰富多彩的粒子特效.但是更多的情况下,我们的QML界面是配合C++进行工作的:QML负责界面渲染,C++负责逻辑事务.甚至有时,我们还会利用QML来绘制C++代码中定义的可视化组件,或者使用C++代码来访问QML中对象的属性等.从这篇博文开始,我们介绍了Qt官方Demo中的"Chapter"系列,它介

自定义QT窗口部件外观之QStyle

自定义QT窗口部件外观 重新定义Qt内置窗口部件的外观常用的方法有两种:一是通过子类化QStyle 类或者预定义的一个样式,例如QWindowStyle,来定制应用程序的观感:二是使用Qt样式表. QStyle 类的使用 1.      准备必要的背景图片.在你想添加自定义风格的工程目录下新建一个文件夹“images”,将背景图片等放入文件夹“images”. 2.      点击Qt Creator的“文件”->“新建文件或工程”->模板选择“Qt”,再选择Qt资源文件->点击“选择”