Synthesijerで作ったモジュールをMessagePack-RPCで制御する(MessagePack-Ruby編)

##はじめに

Synthesijerで作ったモジュールをMessagePack-RPCで制御する話もいよいよ最終コーナーです。
今回は、Synthesijerで作った MessagePack-RPC サーバーを、ZYNQ+Linux 上のクライアントから呼び出す例を示します。
クライアントには MessagePack-Ruby を使います。他の言語でも出来るかもしれません。

ただ、現在、私の環境(ZYNQ+Debian8(jessie))では、MessagePack-RPC-Ruby のインストールが上手くいかなかったので、今回はMessagePack-RPC-Rubyは使っていません。

##準備

次の ruby パッケージが必要です。

- msgpack-ruby
- serialport

これらをインストールします。Debian8(jessie)ではこれらのインストールはgem では失敗するので apt-get を使います。

```
shell# apt-get install ruby-msgpack
shell# apt-get install ruby-serialport
```

##クライアントのコード例

````ruby:accumulator_server.rb
require 'msgpack'
require 'serialport'

class AccumulatorServer

  def initialize
    @port     = SerialPort.new("/dev/zptty0", 38400)
    @port.read_timeout = 1000
    @port.flow_control = SerialPort::HARD
    @unpacker = MessagePack::Unpacker.new(@port)
    @msgid    = 0
  end

  def call(method, args)
    @msgid = (@msgid+1) % 256
    req = [0, @msgid, method, args].to_msgpack
    @port.write(req)
    @unpacker.each do |obj|
      type, resid, error, result = obj
      if (error == nil) then
        return result
      else
        puts error
        return nil
      end
      break
    end 
  end

  def get_regs
    result = call('$GET', [{"reg" => nil}])
    if result != nil
      return result[0]["reg"]
    else
      return nil
    end 
  end

  def set_regs(arg)
    result = call('$SET', [{"reg" => arg}])
  end

  def add(arg)
    return call('add', [arg])
  end
end
```
##テスト用スクリプト

```ruby:test.rb
require_relative 'accumulator_server'

acc = AccumulatorServer.new

rnd = Random.new
acc_reg=1
acc.set_regs(acc_reg)
(0..1000).to_a.each do |n|
  num      = rnd.rand(0..10000)
  curr_reg = acc.get_regs
  add_reg  = acc.add(num)
  next_reg = acc.get_regs
  acc_reg  = acc_reg + num
  status   = ((acc_reg == next_reg) && (acc_reg == add_reg)) ? "OK" : "NG"
  puts "#{status} : reg = #{curr_reg}; add(#{num}) => #{add_reg}; reg = #{next_reg}"
end

acc_reg=1
acc.set_regs(acc_reg)
(0..1000).to_a.each do |n|
  num      = rnd.rand(-10000..0)
  curr_reg = acc.get_regs
  add_reg  = acc.add(num)
  next_reg = acc.get_regs
  acc_reg  = acc_reg + num
  status   = ((acc_reg == next_reg) && (acc_reg == add_reg)) ? "OK" : "NG"
  puts "#{status} : reg = #{curr_reg}; add(#{num}) => #{add_reg}; reg = #{next_reg}"
end

acc.call("sub", [1])
acc.call("add", 1)
acc.call("add", "a")
```

test.rb を ruby で実行します。

```
shell% ruby test.rb
    :
  (中略)
    :
OK : reg = -4898220; add(-3407) => -4901627; reg = -4901627
OK : reg = -4901627; add(-6936) => -4908563; reg = -4908563
NoMethodError
ArgumentError
ArgumentError

```

##参照

[MessagePack for VHDL (https://github.com/ikwzm/msgpack-vhdl)](https://github.com/ikwzm/msgpack-vhdl)
[MessagePack for VHDL Examples (https://github.com/ikwzm/msgpack-vhdl-examples)](https://github.com/ikwzm/msgpack-vhdl-examples)
[MessagePack-RPCを使ってFPGAを制御](http://qiita.com/ikwzm/items/2644c6e50a7049c75d49)
[Synthesijerで作ったモジュールをMessagePack-RPCで制御する(アーキテクチャ編)](http://qiita.com/ikwzm/items/6cb623b057a687ff4a8e)
[Synthesijerで作ったモジュールをMessagePack-RPCで制御する(IP-Package編)](http://qiita.com/ikwzm/items/924fc3fd59bdf7da55a2)
[Synthesijerで作ったモジュールをMessagePack-RPCで制御する(ZYNQ論理合成編)](http://qiita.com/ikwzm/items/0254f1d49602095b5cde)
[Synthesijerで作ったモジュールをMessagePack-RPCで制御する(TTYドライバ編)](http://qiita.com/drafts/533b905f7d1eb2e6c4d5)