2016-09-07 11 views
0

CANバスで動作するにはC++ APIにアクセスする必要があります。最高のソリューションは、私が必要とするすべての機能を公開するためのQMLラッパーを書くことです。ここでモジュール[]がインストールされていません - QMLのカスタムC++ラッパーの登録

は、これまでのところ、私のcanservice.cpp次のとおりです。

私が持っている canservice.h
#include "canservice.h" 
#include <QCanBus> 
#include <QDebug> 
#include <QCanBusFrame> 
#include <QTimer> 

#include <QtCore/qbytearray.h> 
#include <QtCore/qvariant.h> 
#include <QtCore/qdebug.h> 

CANService::CANService(QObject *parent) : 
    QObject(parent), 
    m_canDevice(nullptr) 
{ 
    QString status = ""; 

    initializeSettings(); 


    // TODO" disable sending messages until connection is stablished 
} 

CANService::~CANService() 
{ 
    delete m_canDevice; 
} 

void CANService::receiveError(QCanBusDevice::CanBusError error) const 
{ 
    switch (error) { 
     case QCanBusDevice::ReadError: 
     case QCanBusDevice::WriteError: 
     case QCanBusDevice::ConnectionError: 
     case QCanBusDevice::ConfigurationError: 
     case QCanBusDevice::UnknownError: 
      qWarning() << m_canDevice->errorString(); 
    default: 
     break; 
    } 
} 

void CANService::initializeSettings() 
{ 
    foreach (const QByteArray &backend, QCanBus::instance()->plugins()) { 
     qInfo() << "found: " + backend; 
     if (backend == "socketcan") { 
      // found socketcan 
      m_currentSettings.backendName = "socketcan"; 
      break; 
     } 
    } 

    if(m_currentSettings.backendName.length() < 1) { 
     qWarning() << "did not find a backend"; 
    } 

    m_currentSettings.backendName = "socketcan"; 
    m_currentSettings.deviceInterfaceName = QStringLiteral("vcan0"); 
} 

void CANService::connectDevice() 
{ 
    m_canDevice = QCanBus::instance()->createDevice(m_currentSettings.backendName.toLocal8Bit(), m_currentSettings.deviceInterfaceName); 
    if (!m_canDevice) { 
     showStatusMessage(tr("Connection error")); 
     return; 
    } 
    connect(m_canDevice, &QCanBusDevice::errorOccurred, 
      this, &MainWindow::receiveError); 
    connect(m_canDevice, &QCanBusDevice::framesReceived, 
      this, &MainWindow::checkMessages); 
    connect(m_canDevice, &QCanBusDevice::framesWritten, 
      this, &MainWindow::framesWritten); 

    if (p.useConfigurationEnabled) { 
     foreach (const ConnectDialog::ConfigurationItem &item, p.configurations) 
      m_canDevice->setConfigurationParameter(item.first, item.second); 
    } 

    if (!m_canDevice->connectDevice()) { 
     delete m_canDevice; 
     m_canDevice = nullptr; 
     qInfo() << "Connection error"; 
    } else { 
     qInfo() << m_currentSettings.backendName << "is connected"; 
    } 
} 

void CANService::sendMessage() const 
{ 
    if (!m_canDevice) 
     return; 

    // TODO: replace test message with input 
    QByteArray writings = dataFromHex("1122334455667788"); 

    QCanBusFrame frame; 
    const int maxPayload = 8; // 64 : 8; 
    int size = writings.size(); 
    if (size > maxPayload) 
     size = maxPayload; 
    writings = writings.left(size); 
    frame.setPayload(writings); 

    //TODO: get from UI 
    qint32 id = 100; 
    if (id > 2047) { 
     //11 bits 
     id = 2047; 
    } 

    frame.setFrameId(id); 
    frame.setExtendedFrameFormat(true); 

    // frame.setFrameType(QCanBusFrame::RemoteRequestFrame); 
    // frame.setFrameType(QCanBusFrame::ErrorFrame); 
    frame.setFrameType(QCanBusFrame::DataFrame); 

    m_canDevice->writeFrame(frame); 
} 

void CANService::checkMessages() 
{ 
    if (!m_canDevice) 
     return; 

    const QCanBusFrame frame = m_canDevice->readFrame(); 

    const qint8 dataLength = frame.payload().size(); 

    const qint32 id = frame.frameId(); 

    QString view; 
    if (frame.frameType() == QCanBusFrame::ErrorFrame) { 
     interpretError(view, frame); 
    } else { 
     view += QLatin1String("Id: "); 
     view += QString::number(id, 16).toUpper(); 
     view += QLatin1String(" bytes: "); 
     view += QString::number(dataLength, 10); 
     view += QLatin1String(" data: "); 
     view += dataToHex(frame.payload()); 
    } 

    if (frame.frameType() == QCanBusFrame::RemoteRequestFrame) { 
     qInfo() << "got remote request message" << view; 
    } else if (frame.frameType() == QCanBusFrame::ErrorFrame) { 
     qWarning() << "got can error frame: " << view; 
    } else { 
     qInfo() << "got can frame: " << view; 
    } 
} 

void CANService::interpretError(QString &view, const QCanBusFrame &frame) 
{ 
    if (!m_canDevice) 
     return; 

    view = m_canDevice->interpretErrorFrame(frame); 
} 

static QByteArray dataToHex(const QByteArray &data) 
{ 
    QByteArray result = data.toHex().toUpper(); 

    for (int i = 0; i < result.size(); i += 3) 
     result.insert(i, ' '); 

    return result; 
} 

static QByteArray dataFromHex(const QString &hex) 
{ 
    QByteArray line = hex.toLatin1(); 
    line.replace(' ', QByteArray()); 
    return QByteArray::fromHex(line); 
} 

私のQMLファイルで
#ifndef CANSERVICE_H 
#define CANSERVICE_H 

#include <QObject> 
#include <QQuickItem> 
#include <QCanBusDevice> 


class CANService : public QObject 
{ 
    Q_OBJECT 
public: 
    explicit CANService(QObject *parent = 0); 
    typedef QPair<QCanBusDevice::ConfigurationKey, QVariant> ConfigurationItem; 

    struct Settings { 
     QString backendName; 
     QString deviceInterfaceName; 
     QList<ConfigurationItem> configurations; 
     bool useConfigurationEnabled; 
    }; 


    void connectDevice(); 

    Q_INVOKABLE void connect(const QString &query) { 
     qDebug() << "invoking connect with " << query; 


    } 

    explicit ConnectDialog(QWidget *parent = nullptr); 
    ~ConnectDialog(); 

    Settings settings() const; 

private: 
    Settings m_currentSettings; 
    void initializeSettings(); 


signals: 

public slots: 

}; 

qmlRegisterType<MyObject>("can.myapp", 1, 0, "CANService"); 

#endif // CANSERVICE_H 

私が最初に、新たに定義されたサービスインポートしよう:import can.myapp 1.0をして、私は宣言するそのインスタンス:

CANService { 
    id: "myCanService" 
} 

このアプリケーションを実行し、CANServiceへの呼び出しを行うQMLファイルをロードするRY、それがロードされないと私はアプリケーションのコンソールで次のエラーを取得する:

component not ready: 
"file:///home/aras/Projects/myapp/apps/com.myapp.diagnostics/Diagnostics.qml:5 module \"can.myapp\" is not installed\n" 

EDIT: 問題はどこで最も可能性が高いです電話はqmlRegisterTypeです。私はappmanを使用していますので、私のアプリケーションにはmainという機能がありません。実行する適切な場所はどこですかqmlRegisterType

+0

お問い合わせありがとうございますhttp://gitlab.unique-conception.org/groups/qt-can-2.0 – GrecKo

答えて

2

古い投稿に同様のタグを付けたので、私は応答しています。ここで

はカップルの質問です: 1)私の理解では、あなたが QtQuickApplicationViewer(あなたがそのようにロードしている場合)

をインスタンス化する前に、これはmain方法で呼び出される必要があるということであるどこにqmlRegisterType<MyObject>("can.myapp", 1, 0, "CANService");を呼んでいます。 2)これは単純な例で機能しますか(単純なQStringの値を関数に渡します)?

私は積極的に適切なタイミングでのQtでのコーディングではないんだけど、うまくいけば、これは正しい方向にあなたを指すことができます:

は簡単なのカスタムコンポーネントを使用して、私のアプリケーションの一つ(から「メイン」方法ですコマンドライン経由のJava接続)。

#include <QtGui/QGuiApplication> 
#include <QtCore> 
#include <QtQml> 
#include "qtquick2applicationviewer.h" 
#include "globals.h" 
#include "lightassistant.h" 
#include "reporting.h" 

int main(int argc, char *argv[]) 
{ 
    QGuiApplication app(argc, argv); 

    //C++ Types 
    qmlRegisterType<LightAssistant>("com.lightassistant", 1, 0, "LightAssistant"); 
    qmlRegisterType<Reporting>("com.lightassistant", 1, 0, "Reporting"); 
    //Singletons 
    //qmlRegisterSingletonType(QUrl("file:///qml/LightAssistant/Styles.qml"), "com.lightassistant", 1, 0, "Styles"); 

    QtQuick2ApplicationViewer viewer; 
    viewer.setMainQmlFile(QStringLiteral("qml/LightAssistant/main.qml")); 
    viewer.showExpanded(); 
    qDebug() << "offline path is " << viewer.engine()->offlineStoragePath(); 
    LA::OFFLINE_STORAGE_PATH = viewer.engine()->offlineStoragePath(); 
    return app.exec(); 
} 

ここでは単純化されたクラス(これらのクラスは〜600行です)

#ifndefLIGHTASSISTANT_H 
#define LIGHTASSISTANT_H 

#include <QtSql> 
#include <QtCore> 
#include <QtXml> 
#include <QtXmlPatterns> 
#include "globals.h" 



class LightAssistant : public QObject 
    { 
     Q_OBJECT 
    public: 
     explicit LightAssistant(QObject *parent = 0); 

     /** 
     * Is this running on Android? 
     */ 
     Q_INVOKABLE 
     int isAndroid() 
     { 
      #ifdef Q_OS_ANDROID 
      return 1; 
      #else 
      return 0; 
      #endif 
     } 

     /** 
     * Is this running on Android? 
     */ 
     Q_INVOKABLE 
     int isIOS() 
     { 
      #ifdef Q_OS_IOS 
      return 1; 
      #else 
      return 0; 
      #endif 
     } 

     /** 
     * @brief isMobile is this on a mobile device? 
     * @return 
     */ 
     Q_INVOKABLE 
     int isMobile() 
     { 
      return isIOS() + isAndroid(); 
     } 
     .... 
     } 
#endif // LIGHTASSISTANT_H 

理論的にはあなたが今のようなQMLでこれを呼び出すことができます:

import com.lightassistant 1.0 
Item { 
    LightAssistant { 
    id: la 
    } 

    function isIos(){ 
    return la.isIOS(); 
    } 

} 

は、私は本当に何かを示唆しています配管に問題がないことを確認するためにこのような簡単なことですし、それが機能するならば、方法でメソッドを行って、何かをブロックしている別の呼び出しがあるかどうかを確認してください。完全な情報源がなくても、おそらくあなたがコンポーネントを登録している場所であると私が推測します。

+0

ありがとうございます。私はあなたが正しいと思う、私は 'qmlRegisterType ...'を間違っていると思われるヘッダファイルに入れました。しかし、 'appman'を使っているので、私のアプリケーションは' main'メソッドを持っていません。私が登録を行うことができるどんなアイデア? – Aras

+1

@Aras私は決してそれを使用していないのでappmanのために迷っています。QMLビューアが起動する前に読み込むことができるかどうかを確認するために 'initialize'メソッドを試しますが、開発者に直接手を差し伸べて、それを結びつけるフックを与えることができないかどうか確認してください。 –

+1

私は通常、 '* .cpp'ファイルで登録を行います:' const int registration = qmlRegisterType <...> '。これらの変数は 'main()'が実行される前に作成されます。少し危険ですが、まだ問題はありませんでした。 – Velkan

関連する問題