Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Opensurce Qt6.2 vectorcan can not receive and send CAN-FD message



  • Use vectorcan APIs (Qt 6.2.2 , Qt SerialBus part) to connect Can bus ,but fail to receive can-fd message.
    The bus status is always "Unknown" when invoking busStatus() but the hasBusStatus() always return "true", as a result , it make me so confused.

    Besides, I try to run can example in Qt6.2 , it show the same warning as above.
    So , I wonder whether vectorcan APIs is not good or get some bugs.
    I will appreciate it if anyone can give me a hand.

    Best Regards



  • @Shadow_3102 said in Opensurce Qt6.2 vectorcan can not receive and send CAN-FD message:

    The bus status is always "Unknown"

    Is it possible for you to use another non-Qt application/tool to check that your CAN setup is working properly in that machine/PC/device?



  • @Pablo-J-Rogina Thank you for your reply , Pablo. I use TSMaster to connect vectorcan plugin , it works well , which can receive and transmit can-fd mseesage as expected.
    So it does make me confused. I am trying to read "XL Driver Library" and run the example provided to find out a solution.



  • What OS are you using?

    If you are on linux and their hardware supports socketcan I would highly recommend using that.

    I found this http://martchus.no-ip.biz/doc/qt5/qtserialbus/qtserialbus-vectorcan-overview.html
    maybe it can shed some light for you?



  • @MrShawn Thanks for your reply, MrShawn. I use QT6.2 on windows. I have seen the guides before ,but it does not give any help.

    And I have found the root cause after several days hard work. Pls see my next comments.



  • After test and reading source code in QT , I have found the root cause .

    The answer in in vectorcanbackend.cpp (...\Qt6.2\6.2.2\Src\qtserialbus\src\plugins\canbus\vectorcan),and we can see function named startRead(), source code as follows:

    void VectorCanBackendPrivate::startRead()
    {
        Q_Q(VectorCanBackend);
    
        QList<QCanBusFrame> newFrames;
    
        for (;;) {
            quint32 eventCount = 1;
            if (usesCanFd) {
                XLcanRxEvent event = {};
    
                const XLstatus status = ::xlCanReceive(portHandle, &event);
                if (Q_UNLIKELY(status != XL_SUCCESS)) {
                    if (status != XL_ERR_QUEUE_IS_EMPTY) {
                        q->setError(systemErrorString(status), QCanBusDevice::ReadError);
                    }
                    break;
                }
                if (event.tag != XL_CAN_EV_TAG_RX_OK)
                    continue;
    
                const XL_CAN_EV_RX_MSG &msg = event.tagData.canRxOkMsg;
    
                QCanBusFrame frame(msg.id & ~XL_CAN_EXT_MSG_ID,
                    QByteArray(reinterpret_cast<const char *>(msg.data), int(msg.dlc)));
                frame.setTimeStamp(QCanBusFrame::TimeStamp::fromMicroSeconds(event.timeStamp / 1000));
                frame.setExtendedFrameFormat(msg.id & XL_CAN_RXMSG_FLAG_EDL);
                frame.setFrameType((msg.flags & XL_CAN_RXMSG_FLAG_RTR)
                                    ? QCanBusFrame::RemoteRequestFrame
                                    : (msg.flags & XL_CAN_RXMSG_FLAG_EF)
                                        ? QCanBusFrame::ErrorFrame
                                        : QCanBusFrame::DataFrame);
    
                newFrames.append(std::move(frame));
            } else {
                XLevent event = {};
    
                const XLstatus status = ::xlReceive(portHandle, &eventCount, &event);
                if (Q_UNLIKELY(status != XL_SUCCESS)) {
                    if (status != XL_ERR_QUEUE_IS_EMPTY) {
                        q->setError(systemErrorString(status),
                            QCanBusDevice::ReadError);
                    }
                    break;
                }
                if (event.tag != XL_RECEIVE_MSG)
                    continue;
    
                const s_xl_can_msg &msg = event.tagData.msg;
    
                if ((msg.flags & XL_CAN_MSG_FLAG_TX_COMPLETED) && !transmitEcho)
                    continue;
    
                QCanBusFrame frame(msg.id & ~XL_CAN_EXT_MSG_ID,
                    QByteArray(reinterpret_cast<const char *>(msg.data), int(msg.dlc)));
                frame.setTimeStamp(QCanBusFrame::TimeStamp::fromMicroSeconds(event.timeStamp / 1000));
                frame.setExtendedFrameFormat(msg.id & XL_CAN_EXT_MSG_ID);
                frame.setLocalEcho(msg.flags & XL_CAN_MSG_FLAG_TX_COMPLETED);
                frame.setFrameType((msg.flags & XL_CAN_MSG_FLAG_REMOTE_FRAME)
                                    ? QCanBusFrame::RemoteRequestFrame
                                    : (msg.flags & XL_CAN_MSG_FLAG_ERROR_FRAME)
                                       ? QCanBusFrame::ErrorFrame
                                       : QCanBusFrame::DataFrame);
    
                newFrames.append(std::move(frame));
            }
        }
    
        q->enqueueReceivedFrames(newFrames);
    }
    

    when usesCanFd is true , the data structure "canRxOkMsg" was used to get several fields. However some wrong API was used, for example :

    Wrong usages:

    QCanBusFrame frame(**msg.id** & ~XL_CAN_EXT_MSG_ID,
            frame.setTimeStamp(QCanBusFrame::TimeStamp::fromMicroSeconds(event.timeStamp / 1000));
            frame.setExtendedFrameFormat(**msg.id** & XL_CAN_RXMSG_FLAG_EDL);
            frame.setFrameType((**msg.flags** & XL_CAN_RXMSG_FLAG_RTR)
                                ? QCanBusFrame::RemoteRequestFrame
                                : (**msg.flags** & XL_CAN_RXMSG_FLAG_EF)
                                    ? QCanBusFrame::ErrorFrame
                                    : QCanBusFrame::DataFrame);
    

    Correct usages:

    QCanBusFrame frame(**msg.canId** & ~XL_CAN_EXT_MSG_ID,
            frame.setTimeStamp(QCanBusFrame::TimeStamp::fromMicroSeconds(event.timeStampSync / 1000));
            frame.setExtendedFrameFormat(**msg.canId** & XL_CAN_RXMSG_FLAG_EDL);
            frame.setFrameType((**msg.msgFlags** & XL_CAN_RXMSG_FLAG_RTR)
                                ? QCanBusFrame::RemoteRequestFrame
                                : (**msg.msgFlags** & XL_CAN_RXMSG_FLAG_EF)
                                    ? QCanBusFrame::ErrorFrame
                                    : QCanBusFrame::DataFrame);
    

    All latest data structures and APIs are included in vxlapi.h, which is provided by vectorcan and you can get this file by installed "XL Driver Library 20.30.14". The version I use is ”XL Driver Library 20.30.14”.

    Snippet code(key point) in vxlapi.h :

    // General RX Event
    typedef struct {
      unsigned int         size;             // 4 - overall size of the complete event
      unsigned short       tag;              // 2 - type of the event
      unsigned short       channelIndex;     // 2        
      unsigned int         userHandle;       // 4 (lower 12 bit available for CAN)
      unsigned short       flagsChip;        // 2 queue overflow (upper 8bit)
      unsigned short       reserved0;        // 2
      XLuint64             reserved1;        // 8 
      XLuint64             timeStampSync;    // 8 - timestamp which is synchronized by the driver
    
      union {
        unsigned char             raw[XL_CANFD_MAX_EVENT_SIZE - XL_CANFD_RX_EVENT_HEADER_SIZE];
        XL_CAN_EV_RX_MSG          canRxOkMsg;
        XL_CAN_EV_RX_MSG          canTxOkMsg;
        XL_CAN_EV_TX_REQUEST      canTxRequest;
    
        XL_CAN_EV_ERROR           canError;
        XL_CAN_EV_CHIP_STATE      canChipState;
        XL_CAN_EV_SYNC_PULSE      canSyncPulse;
      } tagData;
    } XLcanRxEvent;
    
    
    // used with XL_CAN_EV_TAG_RX_OK
    typedef struct {
      unsigned int    canId;
      unsigned int    msgFlags;
      unsigned int    crc;
      unsigned char   reserved1[12];
      unsigned short  totalBitCnt;
      unsigned char   dlc;        
      unsigned char   reserved[5];
      unsigned char   data[XL_CAN_MAX_DATA_LEN];
    } XL_CAN_EV_RX_MSG;
    

    In addition , the same issues exist in startWrite() .

    And I think it is a big bug , needing to fix , so I want to post this issue to Qt but dont know how to do it .
    I will appreciate it if you can help me . Or you can contact me directly.

    BRs//Hengtai
    Email:19047119059@qq.com


  • Lifetime Qt Champion



  • I have known the root cause and report the bug to QT Jira:https://bugreports.qt.io/browse/QTBUG-99259

    I plan to fix it later but some issus happens in my local develpoment environment . As a result , it may still needs some time to finish it .



  • @Shadow_3102 thank you for sharing your findings and for reporting the issue.


Log in to reply