|
@@ -1,12 +1,25 @@
|
1
|
1
|
#!/usr/bin/env python3
|
|
2
|
+"""Take screen captures from DS1000Z-series oscilloscopes
|
2
|
3
|
|
3
|
|
-from telnetlib_receive_all import Telnet
|
4
|
|
-from Rigol_functions import *
|
5
|
|
-import time
|
6
|
|
-import sys
|
|
4
|
+This program captures either the waveform or the whole screen of a Rigol
|
|
5
|
+DS1000Z series oscilloscope, then saves it on the computer as a CSV, PNG
|
|
6
|
+or BMP file.
|
|
7
|
+
|
|
8
|
+The program uses the LXI protocol, so the computer must have a LAN
|
|
9
|
+connection with the oscilloscope.
|
|
10
|
+"""
|
|
11
|
+
|
|
12
|
+from enum import Enum, auto
|
|
13
|
+import argparse
|
|
14
|
+import logging
|
7
|
15
|
import os
|
8
|
16
|
import platform
|
9
|
|
-import logging
|
|
17
|
+import subprocess
|
|
18
|
+import sys
|
|
19
|
+import time
|
|
20
|
+
|
|
21
|
+from Rigol_functions import *
|
|
22
|
+from telnetlib_receive_all import Telnet
|
10
|
23
|
|
11
|
24
|
__version__ = 'v1.1.0'
|
12
|
25
|
# Added TMC Blockheader decoding
|
|
@@ -54,7 +67,6 @@ log_running_python_versions()
|
54
|
67
|
|
55
|
68
|
# Update the next lines for your own default settings:
|
56
|
69
|
path_to_save = "captures/"
|
57
|
|
-save_format = "PNG"
|
58
|
70
|
IP_DS1104Z = "192.168.1.3"
|
59
|
71
|
|
60
|
72
|
# Rigol/LXI specific constants
|
|
@@ -67,221 +79,220 @@ company = 0
|
67
|
79
|
model = 1
|
68
|
80
|
serial = 2
|
69
|
81
|
|
70
|
|
-# Check command line parameters
|
71
|
|
-script_name = os.path.basename(sys.argv[0])
|
72
|
|
-
|
73
|
|
-
|
74
|
|
-def print_help():
|
75
|
|
- print ()
|
76
|
|
- print ("Usage:")
|
77
|
|
- print (" " + "python " + script_name + " png|bmp|csv [oscilloscope_IP [save_path]]")
|
78
|
|
- print ()
|
79
|
|
- print ("Usage examples:")
|
80
|
|
- print (" " + "python " + script_name + " png")
|
81
|
|
- print (" " + "python " + script_name + " csv 192.168.1.3")
|
82
|
|
- print ()
|
83
|
|
- print ("The following usage cases are not yet implemented:")
|
84
|
|
- print (" " + "python " + script_name + " bmp 192.168.1.3 my_place_for_captures")
|
85
|
|
- print ()
|
86
|
|
- print ("This program captures either the waveform or the whole screen")
|
87
|
|
- print (" of a Rigol DS1000Z series oscilloscope, then save it on the computer")
|
88
|
|
- print (" as a CSV, PNG or BMP file with a timestamp in the file name.")
|
89
|
|
- print ()
|
90
|
|
- print (" The program is using LXI protocol, so the computer")
|
91
|
|
- print (" must have LAN connection with the oscilloscope.")
|
92
|
|
- print (" USB and/or GPIB connections are not used by this software.")
|
93
|
|
- print ()
|
94
|
|
- print (" No VISA, IVI or Rigol drivers are needed.")
|
95
|
|
- print ()
|
96
|
82
|
|
97
|
83
|
# Read/verify file type
|
98
|
|
-if len(sys.argv) <= 1:
|
99
|
|
- print_help()
|
100
|
|
- sys.exit("Warning - wrong command line parameters.")
|
101
|
|
-elif sys.argv[1].lower() not in ["png", "bmp", "csv"]:
|
102
|
|
- print_help()
|
103
|
|
- print ("This file type is not supported: ", sys.argv[1])
|
104
|
|
- sys.exit("ERROR")
|
|
84
|
+class FileType(Enum):
|
|
85
|
+ png = auto()
|
|
86
|
+ bmp = auto()
|
|
87
|
+ csv = auto()
|
105
|
88
|
|
106
|
|
-file_format = sys.argv[1].lower()
|
107
|
|
-
|
108
|
|
-# Read IP
|
109
|
|
-if len(sys.argv) > 1:
|
110
|
|
- IP_DS1104Z = sys.argv[2]
|
111
|
89
|
|
112
|
90
|
# Check network response (ping)
|
113
|
|
-if platform.system() == "Windows":
|
114
|
|
- response = os.system("ping -n 1 " + IP_DS1104Z + " > nul")
|
115
|
|
-else:
|
116
|
|
- response = os.system("ping -c 1 " + IP_DS1104Z + " > /dev/null")
|
117
|
|
-
|
118
|
|
-if response != 0:
|
119
|
|
- print ()
|
120
|
|
- print ("WARNING! No response pinging " + IP_DS1104Z)
|
121
|
|
- print ("Check network cables and settings.")
|
122
|
|
- print ("You should be able to ping the oscilloscope.")
|
123
|
|
-
|
124
|
|
-# Open a modified telnet session
|
125
|
|
-# The default telnetlib drops 0x00 characters,
|
126
|
|
-# so a modified library 'telnetlib_receive_all' is used instead
|
127
|
|
-tn = Telnet(IP_DS1104Z, port)
|
128
|
|
-instrument_id = command(tn, "*IDN?").decode() # ask for instrument ID
|
129
|
|
-
|
130
|
|
-# Check if instrument is set to accept LAN commands
|
131
|
|
-if instrument_id == "command error":
|
132
|
|
- print ("Instrument reply:", instrument_id)
|
133
|
|
- print ("Check the oscilloscope settings.")
|
134
|
|
- print ("Utility -> IO Setting -> RemoteIO -> LAN must be ON")
|
135
|
|
- sys.exit("ERROR")
|
136
|
|
-
|
137
|
|
-# Check if instrument is indeed a Rigol DS1000Z series
|
138
|
|
-id_fields = instrument_id.split(",")
|
139
|
|
-if (id_fields[company] != "RIGOL TECHNOLOGIES") or \
|
140
|
|
- (id_fields[model][:3] != "DS1") or (id_fields[model][-1] != "Z"):
|
141
|
|
- print ("Found instrument model '{}' from '{}'".format(id_fields[model], id_fields[company]))
|
142
|
|
- print ("WARNING: No Rigol from series DS1000Z found at", IP_DS1104Z)
|
143
|
|
- print ()
|
144
|
|
- typed = raw_input("ARE YOU SURE YOU WANT TO CONTINUE? (No/Yes):")
|
145
|
|
- if typed != 'Yes':
|
146
|
|
- sys.exit('Nothing done. Bye!')
|
147
|
|
-
|
148
|
|
-print ("Instrument ID:", instrument_id)
|
149
|
|
-
|
150
|
|
-# Prepare filename as C:\MODEL_SERIAL_YYYY-MM-DD_HH.MM.SS
|
151
|
|
-timestamp = time.strftime("%Y-%m-%d_%H.%M.%S", time.localtime())
|
152
|
|
-if len(sys.argv) > 3:
|
153
|
|
- filename = sys.argv[3]
|
154
|
|
-else:
|
155
|
|
- filename = path_to_save + id_fields[model] + "_" + id_fields[serial] + "_" + timestamp + "." + file_format
|
156
|
|
-
|
157
|
|
-if file_format in ["png", "bmp"]:
|
158
|
|
- # Ask for an oscilloscope display print screen
|
159
|
|
- print ("Receiving screen capture...")
|
160
|
|
-
|
161
|
|
- if file_format == "png":
|
162
|
|
- buff = command(tn, ":DISP:DATA? ON,OFF,PNG")
|
|
91
|
+def test_ping(hostname):
|
|
92
|
+ """Ping hostname once"""
|
|
93
|
+ if platform.system() == "Windows":
|
|
94
|
+ command = ['ping', '-n', '1', hostname]
|
163
|
95
|
else:
|
164
|
|
- buff = command(tn, ":DISP:DATA? ON,OFF,BMP8")
|
165
|
|
-
|
166
|
|
- expectedBuffLen = expected_buff_bytes(buff)
|
167
|
|
- # Just in case the transfer did not complete in the expected time, read the remaining 'buff' chunks
|
168
|
|
- while len(buff) < expectedBuffLen:
|
169
|
|
- logging.warning("Received LESS data then expected! (" +
|
170
|
|
- str(len(buff)) + " out of " + str(expectedBuffLen) + " expected 'buff' bytes.)")
|
171
|
|
- tmp = tn.read_until(b"\n", smallWait)
|
172
|
|
- if len(tmp) == 0:
|
173
|
|
- break
|
174
|
|
- buff += tmp
|
175
|
|
- logging.warning(str(len(tmp)) + " leftover bytes added to 'buff'.")
|
176
|
|
-
|
177
|
|
- if len(buff) < expectedBuffLen:
|
178
|
|
- logging.error("After reading all data chunks, 'buff' is still shorter then expected! (" +
|
179
|
|
- str(len(buff)) + " out of " + str(expectedBuffLen) + " expected 'buff' bytes.)")
|
|
96
|
+ command = ['ping', '-c', '1', hostname]
|
|
97
|
+ completed = subprocess.run(command, stdout=subprocess.DEVNULL,
|
|
98
|
+ stderr=subprocess.DEVNULL)
|
|
99
|
+
|
|
100
|
+ if completed.returncode != 0:
|
|
101
|
+ print()
|
|
102
|
+ print("WARNING! No response pinging", hostname)
|
|
103
|
+ print("Check network cables and settings.")
|
|
104
|
+ print("You should be able to ping the oscilloscope.")
|
|
105
|
+
|
|
106
|
+def run(hostname, filename, filetype):
|
|
107
|
+ test_ping(hostname)
|
|
108
|
+
|
|
109
|
+ # Open a modified telnet session
|
|
110
|
+ # The default telnetlib drops 0x00 characters,
|
|
111
|
+ # so a modified library 'telnetlib_receive_all' is used instead
|
|
112
|
+ tn = Telnet(hostname, port)
|
|
113
|
+ instrument_id = command(tn, "*IDN?").decode() # ask for instrument ID
|
|
114
|
+
|
|
115
|
+ # Check if instrument is set to accept LAN commands
|
|
116
|
+ if instrument_id == "command error":
|
|
117
|
+ print ("Instrument reply:", instrument_id)
|
|
118
|
+ print ("Check the oscilloscope settings.")
|
|
119
|
+ print ("Utility -> IO Setting -> RemoteIO -> LAN must be ON")
|
180
|
120
|
sys.exit("ERROR")
|
181
|
121
|
|
182
|
|
- # Strip TMC Blockheader and keep only the data
|
183
|
|
- tmcHeaderLen = tmc_header_bytes(buff)
|
184
|
|
- expectedDataLen = expected_data_bytes(buff)
|
185
|
|
- buff = buff[tmcHeaderLen: tmcHeaderLen+expectedDataLen]
|
186
|
|
-
|
187
|
|
- # Write raw data to file
|
188
|
|
- with open(filename, 'wb') as f:
|
189
|
|
- f.write(buff)
|
190
|
|
- print('Saved raw data to {}'.format(filename))
|
191
|
|
-
|
192
|
|
-# TODO: Change WAV:FORM from ASC to BYTE
|
193
|
|
-elif file_format == "csv":
|
194
|
|
- # Put the scope in STOP mode - for the moment, deal with it by manually stopping the scope
|
195
|
|
- # TODO: Add command line switch and code logic for 1200 vs ALL memory data points
|
196
|
|
- # tn.write("stop")
|
197
|
|
- # response = tn.read_until("\n", 1)
|
198
|
|
-
|
199
|
|
- # Scan for displayed channels
|
200
|
|
- chanList = []
|
201
|
|
- for channel in ["CHAN1", "CHAN2", "CHAN3", "CHAN4", "MATH"]:
|
202
|
|
- response = command(tn, ":" + channel + ":DISP?")
|
203
|
|
-
|
204
|
|
- # If channel is active
|
205
|
|
- if response == '1\n':
|
206
|
|
- chanList += [channel]
|
207
|
|
-
|
208
|
|
- # the meaning of 'max' is - will read only the displayed data when the scope is in RUN mode,
|
209
|
|
- # or when the MATH channel is selected
|
210
|
|
- # - will read all the acquired data points when the scope is in STOP mode
|
211
|
|
- # TODO: Change mode to MAX
|
212
|
|
- # TODO: Add command line switch for MAX/NORM
|
213
|
|
- command(tn, ":WAV:MODE NORM")
|
214
|
|
- command(tn, ":WAV:STAR 0")
|
215
|
|
- command(tn, ":WAV:MODE NORM")
|
216
|
|
-
|
217
|
|
- csv_buff = ""
|
218
|
|
-
|
219
|
|
- # for each active channel
|
220
|
|
- for channel in chanList:
|
|
122
|
+ # Check if instrument is indeed a Rigol DS1000Z series
|
|
123
|
+ id_fields = instrument_id.split(",")
|
|
124
|
+ if (id_fields[company] != "RIGOL TECHNOLOGIES") or \
|
|
125
|
+ (id_fields[model][:3] != "DS1") or (id_fields[model][-1] != "Z"):
|
|
126
|
+ print ("Found instrument model '{}' from '{}'".format(id_fields[model], id_fields[company]))
|
|
127
|
+ print ("WARNING: No Rigol from series DS1000Z found at", hostname)
|
221
|
128
|
print ()
|
|
129
|
+ typed = raw_input("ARE YOU SURE YOU WANT TO CONTINUE? (No/Yes):")
|
|
130
|
+ if typed != 'Yes':
|
|
131
|
+ sys.exit('Nothing done. Bye!')
|
222
|
132
|
|
223
|
|
- # Set WAVE parameters
|
224
|
|
- command(tn, ":WAV:SOUR " + channel)
|
225
|
|
- command(tn, ":WAV:FORM ASC")
|
|
133
|
+ print ("Instrument ID:", instrument_id)
|
226
|
134
|
|
227
|
|
- # MATH channel does not allow START and STOP to be set. They are always 0 and 1200
|
228
|
|
- if channel != "MATH":
|
229
|
|
- command(tn, ":WAV:STAR 1")
|
230
|
|
- command(tn, ":WAV:STOP 1200")
|
|
135
|
+ # Prepare filename as C:\MODEL_SERIAL_YYYY-MM-DD_HH.MM.SS
|
|
136
|
+ timestamp = time.strftime("%Y-%m-%d_%H.%M.%S", time.localtime())
|
|
137
|
+ if filename is None:
|
|
138
|
+ filename = "{}{}_{}_{}.{}".format(path_to_save, id_fields[model],
|
|
139
|
+ id_fields[serial], timestamp,
|
|
140
|
+ filetype.name)
|
231
|
141
|
|
232
|
|
- buff = ""
|
233
|
|
- print ("Data from channel '" + str(channel) + "', points " + str(1) + "-" + str(1200) + ": Receiving...")
|
234
|
|
- buffChunk = command(tn, ":WAV:DATA?")
|
|
142
|
+ if filetype in {FileType.png, FileType.bmp}:
|
|
143
|
+ # Ask for an oscilloscope display print screen
|
|
144
|
+ print ("Receiving screen capture...")
|
235
|
145
|
|
236
|
|
- # Just in case the transfer did not complete in the expected time
|
237
|
|
- while buffChunk[-1] != "\n":
|
238
|
|
- logging.warning("The data transfer did not complete in the expected time of " +
|
239
|
|
- str(smallWait) + " second(s).")
|
|
146
|
+ if filetype is FileType.png:
|
|
147
|
+ buff = command(tn, ":DISP:DATA? ON,OFF,PNG")
|
|
148
|
+ else:
|
|
149
|
+ buff = command(tn, ":DISP:DATA? ON,OFF,BMP8")
|
240
|
150
|
|
|
151
|
+ expectedBuffLen = expected_buff_bytes(buff)
|
|
152
|
+ # Just in case the transfer did not complete in the expected time, read the remaining 'buff' chunks
|
|
153
|
+ while len(buff) < expectedBuffLen:
|
|
154
|
+ logging.warning("Received LESS data then expected! (" +
|
|
155
|
+ str(len(buff)) + " out of " + str(expectedBuffLen) + " expected 'buff' bytes.)")
|
241
|
156
|
tmp = tn.read_until(b"\n", smallWait)
|
242
|
157
|
if len(tmp) == 0:
|
243
|
158
|
break
|
244
|
|
- buffChunk += tmp
|
245
|
|
- logging.warning(str(len(tmp)) + " leftover bytes added to 'buff_chunks'.")
|
246
|
|
-
|
247
|
|
- # Append data chunks
|
248
|
|
- # Strip TMC Blockheader and terminator bytes
|
249
|
|
- buff += buffChunk[tmc_header_bytes(buffChunk):-1] + ","
|
250
|
|
-
|
251
|
|
- # Strip the last \n char
|
252
|
|
- buff = buff[:-1]
|
253
|
|
-
|
254
|
|
- # Process data
|
255
|
|
- buff_list = buff.split(",")
|
256
|
|
- buff_rows = len(buff_list)
|
257
|
|
-
|
258
|
|
- # Put read data into csv_buff
|
259
|
|
- csv_buff_list = csv_buff.split(os.linesep)
|
260
|
|
- csv_rows = len(csv_buff_list)
|
261
|
|
-
|
262
|
|
- current_row = 0
|
263
|
|
- if csv_buff == "":
|
264
|
|
- csv_first_column = True
|
265
|
|
- csv_buff = str(channel) + os.linesep
|
266
|
|
- else:
|
267
|
|
- csv_first_column = False
|
268
|
|
- csv_buff = str(csv_buff_list[current_row]) + "," + str(channel) + os.linesep
|
269
|
|
-
|
270
|
|
- for point in buff_list:
|
271
|
|
- current_row += 1
|
272
|
|
- if csv_first_column:
|
273
|
|
- csv_buff += str(point) + os.linesep
|
|
159
|
+ buff += tmp
|
|
160
|
+ logging.warning(str(len(tmp)) + " leftover bytes added to 'buff'.")
|
|
161
|
+
|
|
162
|
+ if len(buff) < expectedBuffLen:
|
|
163
|
+ logging.error("After reading all data chunks, 'buff' is still shorter then expected! (" +
|
|
164
|
+ str(len(buff)) + " out of " + str(expectedBuffLen) + " expected 'buff' bytes.)")
|
|
165
|
+ sys.exit("ERROR")
|
|
166
|
+
|
|
167
|
+ # Strip TMC Blockheader and keep only the data
|
|
168
|
+ tmcHeaderLen = tmc_header_bytes(buff)
|
|
169
|
+ expectedDataLen = expected_data_bytes(buff)
|
|
170
|
+ buff = buff[tmcHeaderLen: tmcHeaderLen+expectedDataLen]
|
|
171
|
+
|
|
172
|
+ # Write raw data to file
|
|
173
|
+ with open(filename, 'wb') as f:
|
|
174
|
+ f.write(buff)
|
|
175
|
+ print('Saved raw data to {}'.format(filename))
|
|
176
|
+
|
|
177
|
+ # TODO: Change WAV:FORM from ASC to BYTE
|
|
178
|
+ elif filetype is FileType.csv:
|
|
179
|
+ # Put the scope in STOP mode - for the moment, deal with it by manually stopping the scope
|
|
180
|
+ # TODO: Add command line switch and code logic for 1200 vs ALL memory data points
|
|
181
|
+ # tn.write("stop")
|
|
182
|
+ # response = tn.read_until("\n", 1)
|
|
183
|
+
|
|
184
|
+ # Scan for displayed channels
|
|
185
|
+ chanList = []
|
|
186
|
+ for channel in ["CHAN1", "CHAN2", "CHAN3", "CHAN4", "MATH"]:
|
|
187
|
+ response = command(tn, ":" + channel + ":DISP?")
|
|
188
|
+
|
|
189
|
+ # If channel is active
|
|
190
|
+ if response == '1\n':
|
|
191
|
+ chanList += [channel]
|
|
192
|
+
|
|
193
|
+ # the meaning of 'max' is - will read only the displayed data when the scope is in RUN mode,
|
|
194
|
+ # or when the MATH channel is selected
|
|
195
|
+ # - will read all the acquired data points when the scope is in STOP mode
|
|
196
|
+ # TODO: Change mode to MAX
|
|
197
|
+ # TODO: Add command line switch for MAX/NORM
|
|
198
|
+ command(tn, ":WAV:MODE NORM")
|
|
199
|
+ command(tn, ":WAV:STAR 0")
|
|
200
|
+ command(tn, ":WAV:MODE NORM")
|
|
201
|
+
|
|
202
|
+ csv_buff = ""
|
|
203
|
+
|
|
204
|
+ # for each active channel
|
|
205
|
+ for channel in chanList:
|
|
206
|
+ print ()
|
|
207
|
+
|
|
208
|
+ # Set WAVE parameters
|
|
209
|
+ command(tn, ":WAV:SOUR " + channel)
|
|
210
|
+ command(tn, ":WAV:FORM ASC")
|
|
211
|
+
|
|
212
|
+ # MATH channel does not allow START and STOP to be set. They are always 0 and 1200
|
|
213
|
+ if channel != "MATH":
|
|
214
|
+ command(tn, ":WAV:STAR 1")
|
|
215
|
+ command(tn, ":WAV:STOP 1200")
|
|
216
|
+
|
|
217
|
+ buff = ""
|
|
218
|
+ print ("Data from channel '" + str(channel) + "', points " + str(1) + "-" + str(1200) + ": Receiving...")
|
|
219
|
+ buffChunk = command(tn, ":WAV:DATA?")
|
|
220
|
+
|
|
221
|
+ # Just in case the transfer did not complete in the expected time
|
|
222
|
+ while buffChunk[-1] != "\n":
|
|
223
|
+ logging.warning("The data transfer did not complete in the expected time of " +
|
|
224
|
+ str(smallWait) + " second(s).")
|
|
225
|
+
|
|
226
|
+ tmp = tn.read_until(b"\n", smallWait)
|
|
227
|
+ if len(tmp) == 0:
|
|
228
|
+ break
|
|
229
|
+ buffChunk += tmp
|
|
230
|
+ logging.warning(str(len(tmp)) + " leftover bytes added to 'buff_chunks'.")
|
|
231
|
+
|
|
232
|
+ # Append data chunks
|
|
233
|
+ # Strip TMC Blockheader and terminator bytes
|
|
234
|
+ buff += buffChunk[tmc_header_bytes(buffChunk):-1] + ","
|
|
235
|
+
|
|
236
|
+ # Strip the last \n char
|
|
237
|
+ buff = buff[:-1]
|
|
238
|
+
|
|
239
|
+ # Process data
|
|
240
|
+ buff_list = buff.split(",")
|
|
241
|
+ buff_rows = len(buff_list)
|
|
242
|
+
|
|
243
|
+ # Put read data into csv_buff
|
|
244
|
+ csv_buff_list = csv_buff.split(os.linesep)
|
|
245
|
+ csv_rows = len(csv_buff_list)
|
|
246
|
+
|
|
247
|
+ current_row = 0
|
|
248
|
+ if csv_buff == "":
|
|
249
|
+ csv_first_column = True
|
|
250
|
+ csv_buff = str(channel) + os.linesep
|
274
|
251
|
else:
|
275
|
|
- if current_row < csv_rows:
|
276
|
|
- csv_buff += str(csv_buff_list[current_row]) + "," + str(point) + os.linesep
|
277
|
|
- else:
|
278
|
|
- csv_buff += "," + str(point) + os.linesep
|
|
252
|
+ csv_first_column = False
|
|
253
|
+ csv_buff = str(csv_buff_list[current_row]) + "," + str(channel) + os.linesep
|
279
|
254
|
|
280
|
|
- # Save data as CSV
|
281
|
|
- scr_file = open(filename, "wb")
|
282
|
|
- scr_file.write(csv_buff)
|
283
|
|
- scr_file.close()
|
284
|
|
-
|
285
|
|
- print ("Saved file:", "'" + filename + "'")
|
286
|
|
-
|
287
|
|
-tn.close()
|
|
255
|
+ for point in buff_list:
|
|
256
|
+ current_row += 1
|
|
257
|
+ if csv_first_column:
|
|
258
|
+ csv_buff += str(point) + os.linesep
|
|
259
|
+ else:
|
|
260
|
+ if current_row < csv_rows:
|
|
261
|
+ csv_buff += str(csv_buff_list[current_row]) + "," + str(point) + os.linesep
|
|
262
|
+ else:
|
|
263
|
+ csv_buff += "," + str(point) + os.linesep
|
|
264
|
+
|
|
265
|
+ # Save data as CSV
|
|
266
|
+ scr_file = open(filename, "wb")
|
|
267
|
+ scr_file.write(csv_buff)
|
|
268
|
+ scr_file.close()
|
|
269
|
+
|
|
270
|
+ print ("Saved file:", "'" + filename + "'")
|
|
271
|
+
|
|
272
|
+ tn.close()
|
|
273
|
+
|
|
274
|
+if __name__ == "__main__":
|
|
275
|
+ parser = argparse.ArgumentParser(description="Take screen captures from"
|
|
276
|
+ " DS1000Z-series oscilloscopes")
|
|
277
|
+ parser.add_argument("-t", "--type",
|
|
278
|
+ choices=FileType.__members__,
|
|
279
|
+ help="Optional type of file to save")
|
|
280
|
+ parser.add_argument("hostname",
|
|
281
|
+ help="Hostname or IP address of the oscilloscope")
|
|
282
|
+ parser.add_argument("filename", nargs="?",
|
|
283
|
+ help="Optional name of output file")
|
|
284
|
+
|
|
285
|
+ args = parser.parse_args()
|
|
286
|
+
|
|
287
|
+ # If no type is specified, auto-detect from the filename
|
|
288
|
+ if args.type is None:
|
|
289
|
+ if args.filename is None:
|
|
290
|
+ parser.error("Either a file type or a filename must be specified")
|
|
291
|
+ args.type = os.path.splitext(args.filename)[1][1:]
|
|
292
|
+
|
|
293
|
+ try:
|
|
294
|
+ args.type = FileType[args.type]
|
|
295
|
+ except KeyError:
|
|
296
|
+ parser.error("Unknown file type: {}".format(args.type))
|
|
297
|
+
|
|
298
|
+ run(args.hostname, args.filename, args.type)
|