#!/usr/bin/ruby $KCODE = 'e' require 'tk' #-------------------------------------------------------------------------------------- # # TkScrollCanvas # class TkScrollCanvas < TkCanvas def initialize(*args) @frame = TkFrame.new { relief('sunken') borderwidth(1) } TkGrid.columnconfigure(@frame, 0, 'weight'=>1) TkGrid.rowconfigure( @frame, 0, 'weight'=>1) super(@frame, *args) end def scrollbar(direction) if direction =~ /v/ @yScrollBar = TkScrollbar.new(@frame) { orient('vertical') } self.yscrollbar(@yScrollBar) end if direction =~ /h/ @xScrollBar = TkScrollbar.new(@frame) { orient('horizontal') } self.xscrollbar(@xScrollBar) end end def pack(*args) self.grid( 'column'=>0, 'row'=>0, 'sticky'=>'news') @yScrollBar.grid('column'=>1, 'row'=>0, 'sticky'=>'ns') if @yScrollBar @xScrollBar.grid('column'=>0, 'row'=>1, 'sticky'=>'we') if @xScrollBar @frame.pack(*args) end end #-------------------------------------------------------------------------------------- # # TkSignalCanvas # class TkSignalCanvas < TkScrollCanvas attr_reader :viewRatio attr_reader :vx attr_reader :vy attr_reader :vy2 attr_reader :ymax #----------------------------------------------------------- # # キャンバスの初期化 # def initialize @signalData = Array.new @viewRatio = 1 super end #----------------------------------------------------------- # # スコープ画面の初期化 # def initScope(vx, vy) self.width( 127 * (@vx = vx) - 110) # 描画サイズ決定 self.height(126 * (@vy = vy) + 17) @vy2 = @vy * 2 @ymax = 126 * (@vy = vy) + 8 self.find_all.each {|item| item.delete} # 全ての描画要素を削除 bg = TkcRectangle.new(self, 0, 0, 0, 0) { width(0) 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, 'arrow'=>'none') { width(1) fill('red') } } [0, 63, 126].each {|y| TkcLine.new(self, 8, @ymax - (y * @vy), 127 * @vx + 8, @ymax - (y * @vy), 'arrow'=>'none') { width(1) fill('red') } } self.coords(bg, 0, 0, 127 * @vx - 110, 126 * @vy + 17) # scrollregion([0, 0, 127 * @vx - 110, 126 * @vy+ 17]) @lines = TkcLines.new(self) 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(3) 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)) } end end #-------------------------------------------------------------------------------------- # # スナップエリアクラス # # @size = 100 #----------------------------------------------------------- # # 波形の履歴をスナップ領域に移す # #----------------------------------------------------------- # # スナップ領域から1波形得る # #----------------------------------------------------------- # # スナップ領域に読み込む # # 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 #----------------------------------------------------------- # # スナップ領域を書き込む # # def writeFile(name) # File.open(name, 'w') {|file| # file.write(sprintf("==MasterZapperData= c =\n")) # i = 0 # @signalData.each {|x| # file.write(sprintf(" %4d,%s", x, i % 16 == 15 ? "\n" : "")) # i += 1 # } # } # 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 { # scrollbar('h') # scrollregion([0, 0, 800, height()]) } #-------------------------------------------------------------------------------------- # # Define StatusBar # statusBar = TkLabel.new { # TkFont.new # puts *TkFont.names # puts *TkFont.families text('abd') font TkFont.new(['osaka', 10, ['bold']]) relief('sunken') borderwidth(1) anchor('w') } #-------------------------------------------------------------------------------------- # # Define AboutBox # def aboutBox Tk.messageBox( 'icon'=>'info', 'type'=>'ok', 'title'=>'About YiYeCon Signal iewer', 'message'=><'Open signal file', 'filetypes'=>fileTypes, 'initialfile'=>'*.sig', 'defaultextension'=>'.sig' ) begin signalCanvas.readFile(fileName) statusBar.text(fileName) rescue statusBar.text($!) end unless fileName == '' }], '---', # separator ['Save', proc{ fileName = Tk.getSaveFile( 'title'=>'Save signal file', 'filetypes'=>fileTypes, 'initialfile'=>'Untitled.sig', # insert current filename 'defaultextension'=>'.sig' ) begin signalCanvas.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) viewRatio = TkVariable.new(signalCanvas.viewRatio) [3, 2, 1, 0].each {|v| mainMenu[1][1].add('radio', 'label' =>['Real','1/2','1/4','1/8'][v], 'command' =>proc{signalCanvas.initScope(viewRatio.to_i)}, 'variable'=>viewRatio, '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}) #-------------------------------------------------------------------------------------- # # 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 } if(samples.length == 0) # ダミーパケット # dummy elsif(samples.length == 4) # hoge(samples[0, 4]) elsif(samples.length == 133) signalCanvas.updateScope(samples[0, 128]) elsif(samples.length == 137) # hoge(samples[0, 4]) signalCanvas.updateScope(samples[4, 128]) else print "====protocol error====\n" # パケット長異常 end statusBar.text(Time.now.asctime) }).start Tk.mainloop