#!/usr/bin/ruby $KCODE = 'e' require 'tk' #------------------------------------------------------------------------------- # # TkSignalCanvas # class TkSignalCanvas < TkCanvas attr_reader :vx attr_reader :vy attr_reader :vy2 attr_reader :ymax def initialize @shadowLines = Hash.new @vx = 5; @vy = 2 super end #----------------------------------------------------------- # # スコープ画面の初期化 # def initScope(vx, vy) self.width( 127 * (@vx = vx) + 1 + 16) # 描画サイズ決定 self.height(126 * (@vy = vy) + 1 + 16) @ymax = 63 * (@vy2 = @vy * 2) + 8 self.find_all.each {|item| item.delete} # 全ての描画要素を削除 bg = TkcRectangle.new(self, 0, 0, self.width, self.height) { fill('#004000') } [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 127].each {|x| TkcLine.new(self, x * @vx + 8, 8, x * @vx + 8, @ymax) { width(1) fill('red') } } [0, 63, 126].each {|y| TkcLine.new(self, 8, @ymax - (y * @vy), 127 * @vx + 8, @ymax - (y * @vy)) { width(1) fill('red') } } @hisLines = TkcLines.new(self) @hisLines.style('yellow', 1) ['u', 'y', 't', 'r', 'e', 'w', 'q'].each {|key| @shadowLines[key] = TkcLines.new(self) @shadowLines[key].style('white', 1) } # 最終的には u が hisLines, white @lines = TkcLines.new(self) @lines.style('green', 2) # 米印が回る end #----------------------------------------------------------- # # スナップ内の波形表示 # def historyScope(signalData) @hisLines.form(signalData) end #----------------------------------------------------------- # # 比較参照用の波形表示 # def shadowScope(key, signalData) @shadowLines[key].form(signalData) end #----------------------------------------------------------- # # スコープ画面の更新 # def updateScope(signalData) @lines.form(signalData) end end #------------------------------------------------------------------------------- # # TkcLines - 多節点の線分 # class TkcLines #----------------------------------------------------------- # # 波形の部品を定義する # def initialize(canvas) @canvas = canvas @lines = Array.new (0..126).each {|i| x = TkcLine.new(@canvas) { width(1) fill('green') } @lines.push(x) } end #----------------------------------------------------------- # # 波形を形成する # def form(sample) (0..126).each {|i| j = i + 1 @lines[i].coords(i * @canvas.vx + 8, @canvas.ymax - (sample[i] * @canvas.vy2), j * @canvas.vx + 8, @canvas.ymax - (sample[j] * @canvas.vy2)) # @lines[i].fill(sprintf('#00%02x00', 255 - (sample[i] - sample[j]).abs)) # @lines[i].width(2) } end #----------------------------------------------------------- # # スタイルを設定する # def style(color, width) (0..126).each {|i| j = i + 1 @lines[i].fill(color) @lines[i].width(width) } end end #------------------------------------------------------------------------------- # # 波形の履歴キュークラス # class FormHistory @size) end end #------------------------------------------------------------------------------- # # 序数を返すメソッドを追加 # class Integer def to_s_th unit = ['th', 'st', 'nd', 'rd', 'th', 'th', 'th', 'th', 'th', 'th'][self % 10] unit = 'th' if(self / 10 % 10 == 1) self.to_s + unit end end #------------------------------------------------------------------------------- # # 比較参照用の波形クラス # class FormShadow 0 ? @cursor -= 1 : @cursor) : nil end def cursorNext() # スナップ後なら移動後のカーソル位置を返す @cursor ? (@cursor < (self.length - 1) ? @cursor += 1 : @cursor) : nil end def cursorOn() # スナップ後なら移動後のカーソル位置を返す @cursor ? @cursor : nil end #----------------------------------------------------------- # # スナップエリアをファイルに保存 # def writeFile(name) File.open(name, 'w') {|file| file.write(sprintf("==AnotherPenScopeSnapshotData==\n")) self.each {|samples| file.write(samples.join(',') + "\n") } } end #----------------------------------------------------------- # # スナップ領域に読み込む # # def readFile(name) # text = '' # File.open(name) {|file| # unless file.readline =~ /^==MasterZapperData=/ # # Ruby/Tk 内では raise が予約語になるので同義の fail を使う # fail "Signal file format error - #{name}" # end # text = file.read # } # text.tr!(" \r\n", '') # @signalData = text.split(',') # self.draw # end end #=============================================================================== # # Main # system "stty 19200 raw -crtscts cs7 -echo < /dev/com1" rs232c = open("/dev/com1", "r") root = TkRoot.new { title('Another PenScope') } #------------------------------------------------------------------------------- # # Define Canvas for Signal # signalCanvas = TkSignalCanvas.new history = FormHistory.new(100) snap = FormSnap.new shadow = FormShadow.new #------------------------------------------------------------------------------- # # Define StatusBar # statusBar = TkLabel.new { # TkFont.new # puts *TkFont.names # puts *TkFont.families text('Status') font TkFont.new(['osaka', 10, ['bold']]) relief('sunken') borderwidth(1) anchor('w') } #------------------------------------------------------------------------------- # # Define AboutBox # def aboutBox Tk.messageBox( 'icon'=>'info', 'type'=>'ok', 'title'=>'About Another PenScope', 'message'=><'Open Another PenScope snapshot file', 'filetypes'=>fileTypes, 'initialfile'=>'*.aps', 'defaultextension'=>'.aps' ) begin signalCanvas.readFile(fileName) statusBar.text(fileName) rescue statusBar.text($!) end unless fileName == '' }], '---', # separator ['Save', proc{ fileName = Tk.getSaveFile( 'title'=>'Save Another PenScope snapshot file', 'filetypes'=>fileTypes, 'initialfile'=>'Untitled.aps', # insert current filename 'defaultextension'=>'.aps' ) begin snap.writeFile(fileName) statusBar.text(fileName) rescue statusBar.text($!) end unless fileName == '' }], '---', ['Exit', proc{exit}] ], [['View', 0], # add with radio ], [['I/O', 0], # add with check ], [['Help', 0], ['About', proc{aboutBox}] ] ] mainMenu = TkMenubar.new(nil, menu_spec, 'tearoff'=>false) vx = TkVariable.new(signalCanvas.vx) [1, 2, 3, 4, 5, 6].each {|v| mainMenu[1][1].add('radio', 'label' =>['', 'x1','x2','x3','x4','x5','x6'][v], 'command' =>proc{ signalCanvas.initScope(vx.to_i, (vx.to_i) / 2 + 1) }, 'variable'=>vx, 'value' =>v) } isAutoZap = TkVariable.new(1) isAutoSave = TkVariable.new(1) mainMenu[2][1].add('command', {'label'=>'Zap', 'command'=>proc{aboutBox}}) mainMenu[2][1].add('check', {'label'=>'AutoZap', 'variable'=>isAutoZap}) mainMenu[2][1].add('separator') mainMenu[2][1].add('command', {'label'=>'Master', 'command'=>proc{aboutBox}}) mainMenu[2][1].add('check', {'label'=>'AutoSave', 'variable'=>isAutoSave}) root.bind('F1', proc{ aboutBox }) # aboutダイアログ root.bind('s', proc{ # 過去xxx波形をスナップ snap.shot(history) statusBar.text('Snapped last ' + snap.length.to_s + ' waves.') }) root.bind('k', proc{ # スナップを遡る if(snapCursor = snap.cursorPrev()) signalCanvas.historyScope(snap[snapCursor]) statusBar.text('Snapped ' + snapCursor.to_s_th + ' waves.') end }) root.bind('j', proc{ # スナップを進む if(snapCursor = snap.cursorNext()) signalCanvas.historyScope(snap[snapCursor]) statusBar.text('Snapped ' + snapCursor.to_s_th + ' waves.') end }) root.bind('q', proc{ if(snapCursor = snap.cursorOn()) shadow.store('q', snap[snapCursor]) signalCanvas.shadowScope('q', shadow['q']) end }) root.bind('w', proc{ if(snapCursor = snap.cursorOn()) shadow.store('w', snap[snapCursor]) signalCanvas.shadowScope('w', shadow['w']) end }) root.bind('e', proc{ if(snapCursor = snap.cursorOn()) shadow.store('e', snap[snapCursor]) signalCanvas.shadowScope('e', shadow['e']) end }) root.bind('Q', proc{ }) #------------------------------------------------------------------------------- # # Build Window # statusBar.pack('side'=>'bottom', 'fill'=>'x') mainMenu.pack('side'=>'top', 'fill'=>'x') signalCanvas.pack('fill'=>'both') if ARGV[0] begin signalCanvas.readFile(ARGV[0]) statusBar.text(ARGV[0]) rescue statusBar.text($!) end else signalCanvas.initScope(5, 2) end #------------------------------------------------------------------------------- # # 割り込み処理 # TkAfter.new(1, -1, proc { samples = Array.new loop { # パケット切り出し if(IO.select([rs232c], nil, nil, 5)) c = rs232c.getc break if(c > 0x6f) # セパレータ発見 samples.push(c) else print "Timeout occurred.\n" break end } # sleep 1 # (0..132).each {|c| # samples.push(c % 2 + 31) # } if(samples.length == 0) # ダミーパケット # dummy elsif(samples.length == 4) # hoge(samples[0, 4]) elsif(samples.length == 133) history.store(samples[0, 128]) signalCanvas.updateScope(samples[0, 128]) elsif(samples.length == 137) # hoge(samples[0, 4]) history.store(samples[4, 128]) signalCanvas.updateScope(samples[4, 128]) else print "====protocol error====\n" # パケット長異常 end # statusBar.text(Time.now.asctime) }).start Tk.mainloop