GoとVISAで計測器通信ができるようになったら、今度は表示をなんとかしたくなってきた。
温度計測にしたところで、画面的には単純に時間と温度をprintするだけだと、ひたすらスクロールしていくだけのものしか作れないのが寂しい。
チャートやグラフとはいわないまでも、同じ位置でデジタル表示できるとか、ボタンやテキストボックスでなにか設定変更できたりするとよいなと思っていた。
あまり凝ったものでなくてもいいので、1行程度のデータ表示と、数点の入力項目やボタンのある画面が作れればより実用的になるはず。
探してみると、Go言語用のTUIアプリケーションを作るためのtviewというライブラリがあった。
tviewのサンプルを見よう見まねで、VISA(232C)経由で温度・湿度表示させるサンプルを作成してみた。
usbrh2とUSB-232C経由で通信、1秒ごとに温度と湿度を取得して表示するだけのもの。
スクロールすることなく、画面の定位置でデータが1秒間隔ごとに更新される。
Control+Qキーで終了する。
これなら、SSH接続したターミナルで動くので、GUIの無いLinuxサーバやRasPiに計測器を接続してリモート操作するのに使えそう。
画面

ソース
[example_visa_tview.go]
package main
import (
"fmt"
"strings"
"time"
"github.com/gdamore/tcell/v2"
vi "github.com/jpoirier/visa"
"github.com/rivo/tview"
)
func currentTimeString() string {
t := time.Now()
return t.Format("15:04:05")
}
func updateTextView(app *tview.Application, textView *tview.TextView, instr vi.Object) {
var tmpr, rhmd float64
var tmp_msg, msg string
for {
time.Sleep(1 * time.Second)
b := []byte("getrh\r\n")
_, status := instr.Write(b, uint32(len(b)))
if status < vi.SUCCESS {
// fmt.Println("Error writing to the device, exiting...")
msg = "Error writing to the device!"
// return
} else {
buffer, _, status := instr.Read(100)
if status < vi.SUCCESS {
// fmt.Println("Error reading a response from the device")
msg = "Error reading a response from the device!"
// return
} else {
tmp_msg = string(buffer)
tmp_msg = strings.TrimSpace(tmp_msg)
fmt.Sscanf(tmp_msg, ":%f,%f,", &tmpr, &rhmd)
msg = fmt.Sprintf("Temperature: %.2f `C, RHumidity: %.2f %%\n", tmpr, rhmd)
// fmt.Printf("Count: %d Data: %s\n", retCount, buffer)
}
}
app.QueueUpdateDraw(func() {
textView.SetText(fmt.Sprintf("%s: %s", currentTimeString(), msg))
})
}
}
func main() {
rm, status := vi.OpenDefaultRM()
if status < vi.SUCCESS {
fmt.Println("Could not open a session to the VISA Resource Manager!")
return
}
defer rm.Close()
instr, status := rm.Open("ASRL33::INSTR", vi.NULL, vi.NULL)
// instr, status := rm.Open("USB0::0xCAFE::0x4000::E661410403177E38::INSTR", vi.NULL, vi.NULL)
if status < vi.SUCCESS {
fmt.Println("An error occurred opening the session to ASRL33::INSTR")
return
}
defer instr.Close()
instr.SetAttribute(vi.ATTR_TMO_VALUE, 5000)
instr.SetAttribute(vi.ATTR_TERMCHAR_EN, 1)
instr.SetAttribute(vi.ATTR_TERMCHAR, 0x0A)
app := tview.NewApplication()
app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
switch event.Key() {
// case tcell.KeyEnter: // Press EnterKey
case tcell.KeyCtrlQ: // Press Ctrl+Q
app.Stop() // Stop this app.
return nil
}
return event
})
textView := tview.NewTextView()
flex := tview.NewFlex().
AddItem(textView, 0, 1, true)
// AddItem(textView2, 0, 1, true)
flex.SetBorder(true).SetTitle(" usbrh data monitor - Press Ctrl+Q to exit this app.")
go updateTextView(app, textView, instr)
if err := app.SetRoot(flex, true).Run(); err != nil {
panic(err)
}
rm.Close()
instr.Close()
}
COMポートを"ASRL33::INSTR"としているので、接続したポートに合わせて修正が必要。
具体的には"rm.Open("ASRL33::INSTR", vi.NULL, vi.NULL)"の"ASRL33:INSTR"の部分を書き換える
実行するには、モジュールの初期化とライブラリの取得後に go run で実行する
$ go mod init main $ go mod tidy $ go run example_visa_tview.go