RPC - リモートプロシージャコール

RPC - リモートプロシージャコール

mbed とパソコンやサーバを繋いで使う機会はよくあります。
そのたびごとにパソコン=mbed間のプロトコルを決めてプログラムを作っていては面倒です。
そんなときUNIXなどでメジャーな RPC を使い、簡単に mbed のハードウェアにアクセスすることができます。

mbed は RPCコマンドを受信し解釈することが可能です。
RPCコマンドはいろいろなプロトコルを通じて送ることができます。

ここでは RPC を使うための mbed のプログラムコードを紹介します。
PCやサーバ側のプログラム向けのライブラリはさまざまなものが開発されています。 MATLAB, LabVIEW, Python, Java, JavaScript, .NET

※ RPC (Remote Procedure Call)とは、プログラムから別のアドレス空間(別のCPUだったり、ネットワーク越しのPCだったり)にあるプログラムを実行する技術。 (Wikipedia参照

Information

mbedのRPCコマンドの形式は次のとおりです。
/<Object Name>/<Method Name>

"/" だけ送ると、使用できるObject Nameを返します。

"/<Object Name>" だけ送ると、使用できるMethod Nameを返します。

Warning

最近、RPCは BASEクラス から分離されました。
最近のmbedライブラリを使用する場合は、mbed-rpcライブラリをインポートし、
#include "mbed_rpc.h"
を追記し、 このページの例は "Base::" を "RPC::" へ書き換えてください。
rpc()関数も RPC::call() へ書き換えてください。

AnalogInがエラーになる問題は、va009039さんが修正されています。
http://va009039.blogspot.jp/2013/02/mbed-rpc_16.html

・・・と、思っていたら、元のライブラリのリビジョンがだいぶ変わってしまったので、Revision 5 をベースに独自に修正しました。

Import librarymbed-rpc

mbed rpc

例:main.cpp

#include "mbed.h"
#include "mbed_rpc.h"

int main () {

    RPC::add_rpc_class<RpcDigitalIn>();
    RPC::add_rpc_class<RpcDigitalOut>();
    RPC::add_rpc_class<RpcDigitalInOut>();
    RPC::add_rpc_class<RpcAnalogIn>();
    RPC::add_rpc_class<RpcAnalogOut>();
    RPC::add_rpc_class<RpcPwmOut>();
    RPC::add_rpc_class<RpcSPI>();
    RPC::add_rpc_class<RpcSerial>();
    RPC::add_rpc_class<RpcTimer>();

    :

    char inbuf[40], outbuf[40];

    strcpy(inbuf, "/DigitalOut/new LED1 myled");
    RPC::call(inbuf, outbuf);
    printf("%s\r\n", outbuf);

    strcpy(inbuf, "/myled/write 1");
    RPC::call(inbuf, outbuf);
    printf("%s\r\n", outbuf);

以下、少し古い情報

RPCコマンドの例

/DigitalOut/new LED1 myled
/myled/write 1

mbed 側の定義例

char buf[256], outbuf[256];
strcpy(buf, "/DigitalOut/new LED1 myled");
rpc(buf, outbuf); 

I2Cはライブラリにないが、SPIなんかもRPC経由でアクセスできる。

Base::add_rpc_class<SPI>();
と定義しておけば
/SPI/new spi p5 p6 p7

RPC Over Serial

シリアル経由で RPCコマンド を受け付けるサンプルです。

Import programRPC_Serial

Program to interface with mbed using RPC over Serial

#include "mbed.h"
#include "rpc.h"
Serial pc(USBTX, USBRX);
int main() {
    // setup the classes that can be created dynamically
    Base::add_rpc_class<AnalogIn>();
    Base::add_rpc_class<AnalogOut>();
    Base::add_rpc_class<DigitalIn>();
    Base::add_rpc_class<DigitalOut>();
    Base::add_rpc_class<DigitalInOut>();
    Base::add_rpc_class<PwmOut>();
    Base::add_rpc_class<Timer>();
    Base::add_rpc_class<SPI>();
    Base::add_rpc_class<BusOut>();
    Base::add_rpc_class<BusIn>();
    Base::add_rpc_class<BusInOut>();
    Base::add_rpc_class<Serial>();
    // receive commands, and send back the responses
    char buf[256], outbuf[256];
    while(1) {
        pc.gets(buf, 256);
        rpc(buf, outbuf); 
        pc.printf("%s\n", outbuf);
    }
}

上のプログラムを mbed 上で実行し、PCシリアルより次のように操作します。

sample

/DigitalOut/new LED1 myled
	これはmbedのプログラムで
	DigitalOut myled(LED1);
	を実行したのと同じです。
	成功すると myled と返ってきます。

/myled/write 1
	これはmbedのプログラムで
	myled.write(1);
	を実行したのと同じです。

RPC Over HTTP

ウェブブラウザからも RPC を使用して、 mbed のハードウェアをコントロールすることができます。
グローバルIPアドレス(WAN)で使う場合はセキュリティ機能(認証など)を載せたほうがいいでしょう。

Information

HTTP経由のRPCコマンドの形式は http://<url of mbed>/rpc/<Object name>/<Method name> <Arguments separated by spaces>

svr.addHandler<RPCHandler>("/rpc"); 

Import programRPC_HTTP

A slight Alteration to Donatien's HTTP Server Example so that it registers all the classes with RPC support to demonstrate RPC over HTTP

上のプログラムを mbed 上で実行し、ブラウザより次のURLへアクセスして操作します。

sample

http://192.168.0.123/rpc/DigitalIn/new p5 myport
	これはmbedのプログラムで
	DigitalIn myport(p5);
	を実行したのと同じです。
	成功すると myport と返ってきます。

http://192.168.0.123/rpc/myport/read
	これはmbedのプログラムで
	myport.read();
	を実行したのと同じです。
	ポートの状態 0 または 1 が返ってきます。

※ 192.168.0.123 はユーザーの環境に合わせてください。

また、上のプログラムは mbed のUSBストレージ(USBメモリ)にもアクセスできますので RPCを使ったhtmlファイルを入れておくといいでしょう。

sample

http://192.168.0.123/files/mbed.htm

RPC 実装

ユーザーが独自に作成した関数(クラス)をRPCに対応させるサンプル。

Import programMyRPC_Serial

http://mbed.org/users/okini3939/notebook/RPC_jp/

クラス内に get_rpc_methods(), get_rpc_class() を用意する。

MyRPC::MyRPC(PinName pin, const char *name) : Base(name), _pin(pin) {}

void MyRPC::blink(int n) {
      :
}

int MyRPC::number() {
      :
    return r;
}

const rpc_method *MyRPC::get_rpc_methods() {
  static const rpc_method rpc_methods[] = {
    { "blink", rpc_method_caller<MyRPC, int, &MyRPC::blink>},
    { "number", rpc_method_caller<int, MyRPC, &MyRPC::number> },
    RPC_METHOD_SUPER(Base)
  };
  return rpc_methods;
}       

rpc_class *MyRPC::get_rpc_class() {
    static const rpc_function funcs[] = {
        "new", rpc_function_caller<const char*, PinName, const char*, &Base::construct<MyRPC,PinName,const char*> >,
        RPC_METHOD_END
    };
    static rpc_class c = { "MyRPC", funcs, NULL };
    return &c;
}

このサンプルは、PCシリアルより次のように操作します。

sample

/MyRPC/new LED2 myled

/myled/blink 10

/myled/number

詳細 戻る


Please log in to post comments.