2018年9月23日日曜日

mbed OS 5でCallbackを使う。

mbed OS 5ではコールバック関数にFunctionPointer(参考「mbedのコールバック FunctionPointerを使うテスト」)ではなくCallbackクラスが推奨されています。以下の記事を参考にして少し調べました。

Callbackについて
https://os.mbed.com/docs/v5.8/reference/platform.html#callbacks

状態(State)の重要性
https://os.mbed.com/docs/v5.8/reference/platform.html#the-importance-of-state

APIドキュメント
https://os.mbed.com/docs/v5.8/reference/callback.html

「[em] bed ded」さんの「mbed OS5 の Callback

Tickerのコールバック


NucleoF446REでTickerのサンプルプログラムを動作させました。

参考「https://os.mbed.com/docs/latest/reference/ticker.html

ブレッドボード配線図

drivers/Ticker.hでコールバック関数の登録は以下のように定義されています。

void attach (Callback< void()> func, float t)

サンプルプログラム

#include "mbed.h"
 
Ticker flipper;

DigitalOut led1(D2);
DigitalOut led2(D3);
 
void flip() {
    led2 = !led2;
}
 
int main() {
    led2 = 1;
    flipper.attach(&flip, 2.0);
 
    while(1) {
        led1 = !led1;
        wait(0.2);
    }
}

普通の関数の場合、見た目はCallbackクラスを使わないmbed 2のときと変わりありません。

クラスの中でコールバック関数を登録する場合は以下のように定義されています。

template<typename T , typename M >
void attach (T *obj, M method, float t)

サンプルプログラム

#include "mbed.h"
 
// LEDチカチカクラス
class Flipper {
public:
    Flipper(PinName pin) : _pin(pin) {
        _pin = 0;
    }
    void flip() {
        _pin = !_pin;
    }
private:
    DigitalOut _pin;
};
 
DigitalOut led1(D2);
Flipper f(D3);
Ticker t;
 
int main() {
    // mbed 2のときは
    // t.attach(&f, &Flipper::flip, 1.0);
    t.attach(callback(&f, &Flipper::flip), 1.0); 
 
    while(1) {
        led1 = !led1;
        wait(0.1);
    }
}

RotaryEncoder LibraryをCallbackに対応させる


以上を踏まえて、Callbackを使うように警告が出ていたRotaryEncoderクラスを修正しました。

RotaryEncoder Library
https://os.mbed.com/users/ryood/code/RotaryEncoder/#cfc8f362bce6

テストプログラム
https://os.mbed.com/users/ryood/code/RotaryEncoder_Test/

RotaryEncoderクラスで内部的に使っている、Ticker::attach_us()の書き方が

ticker.attach_us(this, &RotaryEncoder::func_ticker, t);

のとき、以下のような警告が出ていましたが、


Warning: Function "mbed::Ticker::attach_us(T *, M, us_timestamp_t) [with T=RotaryEncoder, M=void (RotaryEncoder::*)()]" (declared at line 144 of "/extras/mbed-os.lib/drivers/Ticker.h") was declared "deprecated" in "RotaryEncoder/RotaryEncoder.h", Line: 98, Col: 17

Callbackを使い、

ticker.attach_us(callback(this, &RotaryEncoder::func_ticker), t);

とすればワーニングは出なくなりました。

C++のテンプレートは難解でよくわかっていませんが、かいつまんで言えば、普通のコールバック関数の登録は特に変わらず、クラス内でコールバック関数を使う場合は、

attach(オブジェクトへのポインタ, オブジェクトのメンバ関数へのポインタ, 引数)

と書いていていたところを、callback()関数を使って

attach(callback(オブジェクトへのポインタ, オブジェクトのメンバ関数へのポインタ), 引数)

と書けば良いようです。

callback()関数はplatform/Callback.hで定義されています。

/** Create a callback class with type infered from the arguments
 *
 *  @param func     Static function to attach
 *  @return         Callback with infered type
 */
template <typename R>
Callback<R()> callback(R(*func)() = 0)
{
    return Callback<R()>(func);
}

/** Create a callback class with type infered from the arguments
 *
 *  @param obj      Optional pointer to object to bind to function
 *  @param method   Member function to attach
 *  @return         Callback with infered type
 */
template<typename T, typename U, typename R>
Callback<R()> callback(U *obj, R(T::*method)())
{
    return Callback<R()>(obj, method);
}


/** Create a callback class with type infered from the arguments
 *
 *  @param func     Static function to attach
 *  @param arg      Pointer argument to function
 *  @return         Callback with infered type
 */
template <typename T, typename U, typename R>
Callback<R()> callback(R(*func)(T *), U *arg)
{
    return Callback<R()>(func, arg);
}

など。

0 件のコメント:

コメントを投稿