よくある シリアル通信 <=> TCP Socket する物を作った。
しばらく使ってて特に問題なかったので、使い方とか書いておく。
Mac OSX LeopardとUbuntu 9.04,と10.04とWindows XPで動作した。

普通のsocketなので大抵のプログラム言語から使えるし、少なくとも10個ぐらいのプログラムを下にぶらさげてマイコンと通信させられる。
最近はコレでsocket化したシリアルデバイスにJRubyで作ったGUIをつないで色々やってる。


■ソースコード
githubにある
http://github.com/shokai/serial-socket-gateway


■インストール

git clone git://github.com/shokai/serial-socket-gateway.git

中のserial-socket-gatewayがそれ。Rubyで書かれている。
単体のファイルで動くので、そのまま /usr/local/bin/ とか適当なパスの通っているディレクトリに cp すればいいと思います


■必要なgemのインストール
ruby-serialportとeventmachineを使っているのでそれぞれインストールする。

gem install eventmachine ArgsParser


ruby-serialportは0.7が動かなかったので、俺は0.6を使っている。MacやUbuntuはソースからビルドしてインストーrうする
wget http://rubyforge.org/frs/download.php/72/ruby-serialport-0.6.tar.gz
tar -zxvf ruby-serialport-0.6.tar.gz
cd ruby-serialport-0.6
ruby extconf.rb
make
sudo make install


Windowsは、http://rubyforge.org/tracker/download.php/61/321/9924/1800/ruby-serialport-0.6.0-mswin32-gem.zipからwindows用のバイナリ(gem)を持ってきて、解凍してインストール。
gem install serialport-0.6.0-mswin32.gem


■起動
Arduino等をMacに接続すると /dev/ の下に、tty.usbなんとかというデバイスができているはず。
serial-socket-gateway /dev/tty.usbserial-A7006Rqn
デバイス名を引数に渡して起動。


接続してみる。telnetでok
telnet localhost 8782
デフォルトで8782番portで起動している。port番号はソースの上の方をいじれば変えられる。


■通信の仕様
改行(¥n)区切りで、1行毎に通信している。改行が来るまで送受信しない。


■サンプルプログラム Arduinoから送信
こんなかんじでADコンバータで電圧測って、Serial.println()を使って末尾に改行を付けて9600bpsパリティなしストップビット1で送信。
int ad_pin = 0;

void setup(){
Serial.begin(9600);
}

void loop(){
int ad = analogRead(ad_pin);
Serial.println(ad);
}


■サンプルプログラム Rubyで受信
間にserial-socket-gatewayを挟んでシリアルデバイスと通信する。

require 'socket'
s = TCPSocket.open("192.168.1.100", 8782)

loop do
res = s.gets
if res.to_s.size > 0
puts res
end
end
serial-socket-gatewayはclientとの接続が切れていないか確認する為に、たまに空文字列を送ってくる。
受信した文字列の長さを見て無視してください

送信は
s.puts "abc abc"
rubyのputsは末尾に改行(¥n)が付く。



■サンプルプログラム Rubyで送受信を同時に
標準入力をserial-socket-gatewayにそのまま送る。こういうのeventmachineでやると楽だね
#!/usr/bin/env ruby
require 'rubygems'
require 'socket'
require 'eventmachine'

HOST = 'localhost'
PORT = 8782

begin
s = TCPSocket.open(HOST, PORT)
rescue => e
STDERR.puts e
exit 1
end

EventMachine::run do
EventMachine::defer do
loop do
res = s.gets
exit unless res
if res.to_s.size > 0
puts res
end
end
end

EventMachine::defer do
loop do
s.puts gets
end
end
end


eventmachineが便利!!