PCと電子コンパスとの通信は、完璧に成功したと報告しましたが、実はいま一つ問題
があります。

スクリプトまで持ち出すと容量が増え迷惑でないかと心配し、簡易なスクリプトで内
容がわかる程度に留めてきました。
しかし、PC間の通信問題を越えて、電子コンパスとの通信問題に発展しております。
このために、スクリプトが複雑になりました。また、将来、RS232Cを利用される方
に、このやり取りが参考にもなることもあると思います。また、なかむらさんのご指
摘のように「小出しするつもり」では全くありせんので、言葉に甘えて、スクリプト
を添付します。(電子コンパスとの通信は可能ですが、計測値3種
(roll,pitch,azimuth)を表示するだけに留めています。)

1 現状
 スクリプトをrunさせて、port=.open(com4,"r+").binmodeで、電子コンパスに指
令を送り、計測を一回だけで終了し、port.closeする場合には、そのPCからの計測命
令の発出直後に計測データを表示し、スクリプトを終了します。毎回、runさせるな
らば、これでも計測に利用可能です。
2 問題点
 ところが、run後に任意の時間に、計測を繰り返し、計測値を表示記録させる目的
で、while〜endを利用して、繰り返し計測をしようとすると、問題が発生します。
chr = STDIN.getcによって、キー入力文字をchrで判定して、(例えばenterキーを押
したときのみ) 計測を行うようにしたところ、enterキーを押したときに、計測内
容は、古い計測値を示します。すなわち、数10回も以前に取得した計測値が、読み
込まれているらしく、これを表示するので、enterキーを押した直後の計測値を表示
しません。
 これでは、使い物になりません。この原因は、bufferにデータが貯まるためと思わ
れます。このとき、sysread(1)やport.flush等を入れても、効果がありません。
3 疑問点
1) port.flushの入れるスクリプト内の位置はどこが正しいでしょうか。
2) この現象は、Rubyのバッファーだけでなく、OS側もバッファーリングしている
ために起こるのではないかと思いますが、如何でしょうか。
3) OSのバッファーリングを、ios.flushのように、system命令でWindows側をfl
ushする命令はないのでしょうか。

面倒な内容ですが、よろしくご指導をお願いします。
矢幡 久

================================
# 電子コンパス計測システム TruePoint 矢幡 2006年4月30日
#電子コンパスへのメッセージパケットID 
# Start/Stop Messages 開始/終了
reset=0x42   # request data:none, Reply data: Not applicable
vrsn=0xC3    # Reply data: 12bytes Major 0-1, Minor 2-3, Options 4-5, Serial
             # number 6-9 Up Orentation 10, Forward orientation 11
power=0x44   # request data:none , Reply data: DPOWER Wakeup Message
baud=0x47

# Diagnostic Messages  診断
test=0x48     # Request data none, Reply data 2bytes  Results 0-1
stat=0x49     # Status Reply data: 6 bytes 温度0-1、Heading Kang 2-3,
Reserved 4-5

# Initaialization Messages    初期化
inical=0x50    # Request data 9 bytes,  Azimth offset 3-4,Roll offest
5-6,Pitch offset 7-8
imvar=0x54     # Initialize Magnetic Declination 3bytes
wmm=0x55       # World Magnetic Model  15bytes, Day0 Month 1, Year 2,Lat3-6,
Lon 7-10, Alt 11-14
               # Reply data 23bytes, Status 0, Magnetic declination
1-2,Source, 3-22
orient=0x70    # Output data 18bytes:  Roll 0-1, Pitch 2-3, Azimuth
4-5,rightwar acceleration 6-7
               # forwar acc. 8-9, upward acc. 10-11, rightward magnetometer
               # 12-13, forward mag. 14-15, upward mag. 16-17

# Compensation Message     補償
mcal=0x72      # Request data 1 byte 0=No request, 1=Start compass
               # compensation 2=request 3=abort, 4=revert to default
compensation values
               # Reply data 13 bytes: state 0, status code 1, bin 0 dat
count 2, 〜 bin 7 data
               # computation competion count 10, quality 11-12

# Other Messages    その他
sdflt =0x66    # Set start-up defaults SDFLT/DSDFLT 12bytes Req 0-1,
MagDecl2-3,
               # Azimuth offset 4-5, Pitch offset 6-7, Roll 8-9, DORIENT Int
10-11

orrate=0x7F    # dorient massage rate  Request data 2 bytes DORIENT interval
0-1
               # Reply 2 bytes,

system "MODE COM4 BAUD=9600 PARITY=N DATA=8 STOP=1"
port = open("com4", "r+b")#.binmode
msgidd=[orient] # , inical, imvar]
hel=0
msgidd.each {|msgid|
  aa=[]
  sop=[0x0D,0x0A,0x7E]  #
  sbuffer=sop

  checksum=0
  # msgid=orient   # example
  msglength = 0
  sbuffer[3]=msgid # メッセージID
  sbuffer[4]=msglength   # dataの長さ
  (0..4+msglength).each {|i|
  dd=sbuffer[i]
  d3=sprintf("%2X", dd)
  p [i,sbuffer[i],dd,d3]
  aa << d3
  checksum+=dd
  }

  p checksum    # チェックサム
  p dd=checksum%256
  d3=sprintf("%2X", dd)
  i=msglength+5
  p [i,sbuffer[i],dd,d3]
  aa << d3
  p aa

p "============== 1 =============="
i=0
# status = timeout(1) {          # Time Limit
 aa.each {|hel|
 # hel.each {|hel2|
   port.syswrite  hel #hel #,"\r\n"    # RS232C OUT
   print hel  # => "0xa"
 }
print "\n"
}
p "============== 2 ============"
p chrt = "r"
countnum=0
while (1) #(chrt != "s")    # <=== whileの前に#をおき、これを潰すと、うまく
動作する。
print "key = "
chr = STDIN.getc
if chr!= "s" then          # キー入力がs以外のときは計測する。
#   port.syswrite  hel #hel #,"\r\n"    # RS232C OUT
        data=[]
        while c = port.sysread(1)    # RS232C IN
          b=c[0]
          break if b==0x0D
         end
          while c = port.sysread(1)    # RS232C IN
            b=c[0]
            break if b==0x0A
          end
          while c = port.sysread(1)    # RS232C IN
            b=c[0]
            break if b==0x7E
          end

          c=port.sysread(1)
          msgid= sprintf("%02X",c[0])   # messageID
          #print  "命令ID=",msgid,"\t"
          c=port.sysread(1)
          msglength = c[0].to_i   # messageのデータ長
          #print "データバイト数=",msglength ,"\n"

          data=[]
          msglength.times {
            c = port.sysread(1)
            data << c
          }
         # p data
         d=data.pack("a1a1a1a1a1a1") # data(バイナリー)をパックした文字列
を返す。
         #p d
         dd=d.unpack("sss")  # 2byteを符号付きshortとみなし、配列で返す。
         # p dd
         dd.each {|ee|
           print sprintf("%3.1f\t",ee*360.0/65535) # 65536/360×角度として送
信されるので、角度に戻す
         }
         print "\n"
        port.flush       # <=== flushの入れる位置はこれでよいか?
        $stdout.flush   # <=== flushの入れる位置はこれでよいか?
        end
end    # <==== while に合わせて潰すend
port.close