-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrigol.go
191 lines (157 loc) · 5.16 KB
/
rigol.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
package main
import (
"bufio"
"flag"
"fmt"
"net"
"os"
"strconv"
"strings"
"time"
)
var chancount = flag.Int("channels", 4, "number of channels to collect")
var host = flag.String("host", "rigol", "hostname or IP address")
var port = flag.Int("port", 5555, "tcp port to use")
var interval = flag.Int("interval", 1, "number of seconds between readings")
var count = flag.Int("count", -1, "number of measurements to take. -1 = no limit")
var fVavg = flag.Bool("vavg", true, "include Vavg")
var fVmin = flag.Bool("vmin", false, "include Vmin")
var fVmax = flag.Bool("vmax", false, "include Vmax")
var fVpp = flag.Bool("vpp", false, "include Vpp")
var fVrms = flag.Bool("vrms", false, "include Vrms")
var fFreq = flag.Bool("freq", false, "include frequency")
var fScreen = flag.Bool("screen", false, "collect screenshots in PNG format")
var fClear = flag.Bool("clear", false, "clear stats after collection")
func main() {
flag.Parse()
connstr := fmt.Sprintf("%s:%d", *host, *port)
conn, err := net.Dial("tcp", connstr)
if err != nil {
fmt.Printf("Unable to connect to %s\n", connstr)
fmt.Println(err)
os.Exit(2)
}
toRun, header := buildQuery()
// Output CSV header
fmt.Printf("%s, %s, %s\n", "timestamp", header, "querytime(ms)")
for ; *count != 0; *count-- {
tstart := time.Now()
// Collect and write screenshot if the screen flag is set. Do this first because queries can take a little while.
if *fScreen {
img := getScreenshot(conn)
if img != nil {
writeScreenshot(img)
}
}
result := queryScope(conn, toRun)
// Return from scope is semicolon separated, so just switch for commas.
result = strings.Replace(result, ";", ", ", -1)
// Clear history
if *fClear {
fmt.Fprintf(conn, ":CLE;MEAS:STAT:RES\n")
}
tdone := time.Now()
taken := tdone.Sub(tstart)
takenms := int64(taken / time.Millisecond)
fmt.Printf("%s, %s, %d\n", tdone.Format(time.RFC3339), result, takenms)
// Shorten the interval to allow for the time taken for the previous run.
// but if the time taken is longer than the interval, no need to sleep at all.
intervalms := int64(*interval * 1000)
if takenms < intervalms {
sleeptime := time.Duration(intervalms-takenms) * time.Millisecond
time.Sleep(sleeptime)
}
}
}
func queryScope(conn net.Conn, query string) string {
fmt.Fprintf(conn, fmt.Sprintf("%s\n", query))
c1, _ := bufio.NewReader(conn).ReadString('\n')
return strings.TrimSuffix(c1, "\n")
}
func buildQuery() (string, string) {
var command []string
var header []string
for i := 0; i < *chancount; i++ {
// Stacking queries together seems to knock about 10% off the query time
// compared to requesting one measurement at a time.
// 2 channels, 4 measurements resulted in 3.9 vs 3.5 seconds on my DS1054Z.
// Tell the scope which channel the following commands are for
//command = append(command, fmt.Sprintf(":MEAS:SOUR CHAN%d", i+1))
// Query measurement unit.
command = append(command, fmt.Sprintf(":CHAN%d:UNIT?", i+1))
header = append(header, fmt.Sprintf("CH%d Unit", i+1))
if *fVavg {
command = append(command, fmt.Sprintf(":MEAS:ITEM? VAVG,CHAN%d", i+1))
header = append(header, fmt.Sprintf("CH%d Vavg", i+1))
}
if *fVmin {
command = append(command, fmt.Sprintf(":MEAS:ITEM? VMIN,CHAN%d", i+1))
header = append(header, fmt.Sprintf("CH%d Vmin", i+1))
}
if *fVmax {
command = append(command, fmt.Sprintf(":MEAS:ITEM? VMAX,CHAN%d", i+1))
header = append(header, fmt.Sprintf("CH%d Vmax", i+1))
}
if *fVpp {
command = append(command, fmt.Sprintf(":MEAS:ITEM? VPP,CHAN%d", i+1))
header = append(header, fmt.Sprintf("CH%d Vpp", i+1))
}
if *fVrms {
command = append(command, fmt.Sprintf(":MEAS:ITEM? VRMS,CHAN%d", i+1))
header = append(header, fmt.Sprintf("CH%d Vrms", i+1))
}
if *fFreq {
command = append(command, fmt.Sprintf(":MEAS:ITEM? FREQ,CHAN%d", i+1))
header = append(header, fmt.Sprintf("CH%d freq", i+1))
}
}
return strings.Join(command, ";"), strings.Join(header, ", ")
}
func check(e error) {
if e != nil {
panic(e)
}
}
func getScreenshot(conn net.Conn) []byte {
// Args are Colour, Invert, Format.
fmt.Fprintf(conn, ":DISP:DATA? ON,FALSE,PNG\n")
reader := bufio.NewReader(conn)
header1, _ := reader.ReadByte()
// should be a #, but let's not panic if it's not
if header1 != 35 {
return nil
}
// Next character shows us the length of the length of the datastream!
header2, _ := reader.ReadByte()
buffsize := int(header2 - 48)
// Quick sanity check, skip if not valid.
if buffsize < 1 || buffsize > 9 {
return nil
}
// Read the length data from the buffer.
header3 := make([]byte, buffsize)
for i := 0; i < buffsize; i++ {
t, err := reader.ReadByte()
check(err)
header3[i] = t
}
// This is now the image size
buffsize, _ = strconv.Atoi(string(header3))
imgdata := make([]byte, buffsize)
for i := 0; i < buffsize; i++ {
t, err := reader.ReadByte()
check(err)
imgdata[i] = t
}
return imgdata
}
func writeScreenshot(img []byte) {
// Filename safe date format
tstamp := time.Now().Format("2006-01-02.150405")
filename := fmt.Sprintf("%s.%s.png", "screenshot", tstamp)
f, err := os.Create(filename)
check(err)
defer f.Close()
_, err = f.Write(img)
check(err)
}