1

私は現在、ビーグルボーンの小さなプロジェクトに取り組んでいます。基本的な目標は、ビーグルボーンのストックjavaScriptフレームワークとは対照的に、c ++のフルパワーを提供するフレームワークを作成することですが、arduinoフレームワークと同じように開発者にとっても使いやすいものです。

私が構築したものの1つは、ボタンやロータリーエンコーダーなどのさまざまなタイプの単純なGPIO割り込み用の事前に作成されたクラスです。したがって、開発者はボタンを定義し、接続されているビーグルボーンのどのGPIOピンも指定する必要があります。

今のところ、割り込みオブジェクトのpollInterupt()関数をメインループに手動で追加して、プログラムが突然発生したGPIOピンの状態を繰り返しチェックできるようにする必要があります。

問題は次のとおりです。ボタンのクラスコンストラクター関数にコードを追加します。このコードを定義すると、バックグラウンドで割り込みハンドラーに自動的に渡され、新しいオブジェクトのpollInterupt()関数が繰り返し実行されるため、開発者はこれを行う必要がありません。ボタンを定義するよりも複雑なもの。

でもレンガの壁にぶつかっているようです。エンドユーザーにとってフレームワークをシンプルにしようとすることは、舞台裏のコードがばかげて複雑になっていることを意味します。定義された割り込みオブジェクトを自動的に処理することを考えることができる最良の方法は、リンクリストです。これは、現在のプロトタイプコードの外観です。

#include <iostream>

class interuptButton;
class interuptHandler;

class interuptHandler{
    public:
        class node{
            public:
                node *next;
                node *prev;
            public:
                void *interupt;
        };

        node *first;
        node *last;
        node *current;
        node *temp;

public:
    interuptHandler(){
        first = new node;
        last  = new node;
        first -> prev = NULL;
        first -> next = last;
        last  -> prev = first;
        last  -> next = NULL;
    }
    void add(void *_interupt){
        temp = new node;

        current = last -> prev;
        current -> next = temp;
        temp    -> prev = current;
        temp    -> next = last;
        last    -> prev = temp;

        temp    -> interupt = _interupt;
    }
    void run(){
        current = first -> next;
        while(current -> next != NULL){
            std::cout << current -> interupt << std::endl;
//              std::cout << current -> interupt -> pin << std::endl;
//              current->interupt->pollInterupt();
//              std::cout << reinterpret_cast < interuptButton* > (current->interupt)->pin << std::endl;
            current = current -> next;
        }
    }
}handler;



class interuptButton{
public:
    int  pin;
    bool value;
public:
    interuptButton(int _pin){
        pin = _pin;
        handler.add(this);
    }
    void pollInterupt(){
        std::cout << "check pin " << pin << " to see if the GPIO has changed" << std::endl;
    }
};



int main(int argc, char **argv){

interuptButton buttonA(41);
interuptButton buttonB(45);
interuptButton buttonC(43);

handler.run();

return 0;
}

システムは機能しているようで、interuptButtonコンストラクターは新しく作成されたオブジェクトをinteruptHandlerのリンクリストに正常に渡します。このリンクリストは、run()関数のメモリアドレスを出力とともに出力できます。

bin/./test
0x7fff5fbff9e0
0x7fff5fbff9d0
0x7fff5fbff9c0

問題は、run()の他の行のコメントを外すと、ポインタオブジェクトの変数または関数にアクセスしようとすると、g++がエラーをスローし始めることです。

最初の2行は次のようになります。

src/main.cpp: In member function ‘void interuptHandler::run()’:
src/main.cpp:47: error: ‘void*’ is not a pointer-to-object type
make: *** [all] Error 1

3行目は次のようになります。

src/main.cpp:49: error: invalid use of incomplete type ‘struct interuptButton’
src/main.cpp:4: error: forward declaration of ‘struct interuptButton’
make: *** [all] Error 1

それらのオブジェクトの変数と関数にそれらのポインターを介してアクセスする方法についてのアドバイスをいただければ幸いです。

さらに良いことに、舞台裏のイベントハンドラーにオブジェクトを自動的に送信するためのより良い方法があれば、私はすべての耳です。

4

2 に答える 2

0

関数の定義を .cpp ファイルに移動する必要がありますか? 定義される前に、interuptbutton の内部にアクセスしているようです。

または、これは 1 つの大きな .cpp ファイルであるため、 main の直前に関数を定義してrun、2 番目のエラー セットを修正できます。

最初のエラーは一目瞭然です。おそらく、Interrupt インターフェイスを作成し、それへのポインターを保持する必要がありvoid*ます。reinterpret_castingはすべてをとても醜くします。

class IInterupt{
 // other stuff common to all interupt classes
    void pollInterupt() = 0; // pure virtual force all inheriting classes to implement.   
}

class interuptButton : public IInterupt{ //bla bla }

 class node{
        public:
            node *next;
            node *prev;
        public:
            IInterupt*interupt;
    };
于 2013-01-21T09:24:40.057 に答える
0

node構造体では、interruptポインターはポインターであり、任意voidの型を指すことができることを意味します。ただし、コンパイラはそれが何を指しているのかわからないため、型キャストを使用して、実際にどの型を指しているかをコンパイラに伝える必要があります。

reinterpret_cast<interuptButton*>(current->interrupt)->pollInterrupt();

他の問題については、循環依存関係があります。クラスはクラスinterruptHandlerに依存し、interruptButtonその逆もあります。これは、1 つまたは両方のクラスの定義と実装を分離することによって解決する必要があります。最も簡単な方法は、クラス定義をinterruptButton定義の上にinterruptHandler配置し、実装、つまり実際のコードをクラス定義のinterruptButton後に配置することです。interruptHandler


クラスだけでなく、複数の割り込み可能なクラスを使用する場合interruptButtonは、継承と仮想関数を持つ抽象基底クラスを使用する必要があります。void次に、ポインターまたは型キャストは必要ありません。

struct baseIntertuptable
{
    virtual void pollInterrupt() = 0;
};

struct interruptHandler
{
private:
    struct node
    {
        // ...
        baseInterruptable* interrupt;
    };

public:
    void run()
    {
        // ...
        current->interrupt->pollInterrupt();
        // ...
    }
};

class interruptButton : public baseInterruptable
{
public:
    void pollInterrupt()
    {
        // ...
    }
};

baseInterruptable抽象基本クラスは使用前に完全に定義され、interruptHandlerクラスはそのクラスのみを使用するため、これにより、クラス定義の循環依存の問題も解決するはずです。

于 2013-01-21T09:27:09.737 に答える