Capture the display of a Rigol DS1000Z series oscilloscope by LAN using LXI SCPI commands
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

OscScreenGrabLAN.py 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. #!/usr/bin/env python
  2. __author__ = 'RoGeorge'
  3. #
  4. # TODO: Add timestamp and mark the trigger point as t0
  5. # TODO: Use channels label instead of chan1, chan2, chan3, chan4, math
  6. # TODO: Add command line parameters file path
  7. # TODO: Add GUI
  8. # TODO: Add browse and custom filename selection
  9. # TODO: Create executable distributions
  10. #
  11. import telnetlib_receive_all
  12. import time
  13. import Image
  14. import StringIO
  15. import sys
  16. import os
  17. import platform
  18. # Update the next lines for your own default settings:
  19. path_to_save = ""
  20. save_format = "PNG"
  21. IP_DS1104Z = "192.168.1.3"
  22. # Rigol/LXI specific constants
  23. port = 5555
  24. expected_len = 1152068
  25. TMC_header_len = 11
  26. terminator_len = 3
  27. big_wait = 10
  28. small_wait = 1
  29. company = 0
  30. model = 1
  31. serial = 2
  32. # Check command line parameters
  33. script_name = os.path.basename(sys.argv[0])
  34. def print_help():
  35. # Print usage
  36. print
  37. print "Usage:"
  38. print " " + "python " + script_name + " png|bmp|csv [oscilloscope_IP [save_path]]"
  39. print
  40. print "Usage examples:"
  41. print " " + "python " + script_name + " png"
  42. print " " + "python " + script_name + " csv 192.168.1.3"
  43. print
  44. print "The following usage cases are not yet implemented:"
  45. print " " + "python " + script_name + " bmp 192.168.1.3 my_place_for_captures"
  46. print
  47. print "This program captures either the waveform or the whole screen"
  48. print " of a Rigol DS1000Z series oscilloscope, then save it on the computer"
  49. print " as a CSV, PNG or BMP file with a timestamp in the file name."
  50. print
  51. print " The program is using LXI protocol, so the computer"
  52. print " must have LAN connection with the oscilloscope."
  53. print " USB and/or GPIB connections are not used by this software."
  54. print
  55. print " No VISA, IVI or Rigol drivers are needed."
  56. print
  57. # Read/verify file type
  58. if len(sys.argv) <= 1:
  59. print_help()
  60. sys.exit("Warning - wrong command line parameters.")
  61. elif sys.argv[1].lower() not in ["png", "bmp", "csv"]:
  62. print_help()
  63. print "This file type is not supported: ", sys.argv[1]
  64. sys.exit("ERROR")
  65. file_format = sys.argv[1].lower()
  66. # Read IP
  67. if len(sys.argv) > 1:
  68. IP_DS1104Z = sys.argv[2]
  69. # Create/check if 'path' exists
  70. # Check network response (ping)
  71. if platform.system() == "Windows":
  72. response = os.system("ping -n 1 " + IP_DS1104Z + " > nul")
  73. else:
  74. response = os.system("ping -c 1 " + IP_DS1104Z + " > /dev/null")
  75. if response != 0:
  76. print
  77. print "No response pinging " + IP_DS1104Z
  78. print "Check network cables and settings."
  79. print "You should be able to ping the oscilloscope."
  80. # Open a modified telnet session
  81. # The default telnetlib drops 0x00 characters,
  82. # so a modified library 'telnetlib_receive_all' is used instead
  83. tn = telnetlib_receive_all.Telnet(IP_DS1104Z, port)
  84. tn.write("*idn?") # ask for instrument ID
  85. instrument_id = tn.read_until("\n", 1)
  86. # Check if instrument is set to accept LAN commands
  87. if instrument_id == "command error":
  88. print instrument_id
  89. print "Check the oscilloscope settings."
  90. print "Utility -> IO Setting -> RemoteIO -> LAN must be ON"
  91. sys.exit("ERROR")
  92. # Check if instrument is indeed a Rigol DS1000Z series
  93. id_fields = instrument_id.split(",")
  94. if (id_fields[company] != "RIGOL TECHNOLOGIES") or \
  95. (id_fields[model][:3] != "DS1") or (id_fields[model][-1] != "Z"):
  96. print
  97. print "ERROR: No Rigol from series DS1000Z found at ", IP_DS1104Z
  98. sys.exit("ERROR")
  99. print "Instrument ID:",
  100. print instrument_id
  101. # Prepare filename as C:\MODEL_SERIAL_YYYY-MM-DD_HH.MM.SS
  102. timestamp = time.strftime("%Y-%m-%d_%H.%M.%S", time.localtime())
  103. filename = path_to_save + id_fields[model] + "_" + id_fields[serial] + "_" + timestamp
  104. if file_format in ["png", "bmp"]:
  105. # Ask for an oscilloscope display print screen
  106. tn.write("display:data?")
  107. print "Receiving screen capture..."
  108. buff = tn.read_until("\n", big_wait)
  109. # Just in case the transfer did not complete in the expected time
  110. while len(buff) < expected_len:
  111. tmp = tn.read_until("\n", small_wait)
  112. if len(tmp) == 0:
  113. break
  114. buff += tmp
  115. # Strip TMC Blockheader and terminator bytes
  116. buff = buff[TMC_header_len:-terminator_len]
  117. # Save as PNG or BMP according to file_format
  118. im = Image.open(StringIO.StringIO(buff))
  119. im.save(filename + "." + file_format, file_format)
  120. print "Saved file:", filename + "." + file_format
  121. elif file_format == "csv":
  122. # Put osc in STOP mode
  123. # tn.write("stop")
  124. # response = tn.read_until("\n", 1)
  125. # Scan for displayed channels
  126. channel_list = []
  127. for channel in ["chan1", "chan2", "chan3", "chan4", "math"]:
  128. tn.write(channel + ":display?")
  129. response = tn.read_until("\n", 1)
  130. # Strip '\n' terminator
  131. response = response[:-1]
  132. if response == '1':
  133. channel_list += [channel]
  134. print "Active channels on the display:", channel_list
  135. csv_buff = ""
  136. # for each active channel
  137. for channel in channel_list:
  138. # Read WAVE parameters
  139. # Set WAVE parameters
  140. tn.write("waveform:source " + channel)
  141. time.sleep(0.2)
  142. # Maximum - only displayed data when osc. in RUN mode, or full memory data when STOPed
  143. tn.write("waveform:mode normal")
  144. time.sleep(0.2)
  145. tn.write("waveform:format ASCII")
  146. time.sleep(0.2)
  147. # Get data
  148. tn.write("waveform:data?")
  149. print "Receiving data for channel " + str(channel) + "..."
  150. buff = tn.read_until("\n", big_wait)
  151. # Just in case the transfer did not complete in the expected time
  152. while buff[-1] != "\n":
  153. tmp = tn.read_until("\n", small_wait)
  154. if len(tmp) == 0:
  155. break
  156. buff += tmp
  157. # Append each value to csv_buff
  158. # Strip headers (TMC and points number)
  159. TMC_header = buff[:TMC_header_len]
  160. data_points = float(TMC_header[2:])
  161. # Strip TMC Blockheader and terminator bytes
  162. buff = buff[TMC_header_len:-1]
  163. # Process data
  164. buff_list = buff.split(",")
  165. buff_rows = len(buff_list)
  166. # Put red data into csv_buff
  167. csv_buff_list = csv_buff.split(os.linesep)
  168. csv_rows = len(csv_buff_list)
  169. current_row = 0
  170. if csv_buff == "":
  171. csv_first_column = True
  172. csv_buff = str(channel) + os.linesep
  173. else:
  174. csv_first_column = False
  175. csv_buff = str(csv_buff_list[current_row]) + "," + str(channel) + os.linesep
  176. for point in buff_list:
  177. current_row += 1
  178. if csv_first_column:
  179. csv_buff += str(point) + os.linesep
  180. else:
  181. if current_row < csv_rows:
  182. csv_buff += str(csv_buff_list[current_row]) + "," + str(point) + os.linesep
  183. else:
  184. csv_buff += "," + str(point) + os.linesep
  185. # Save data as CSV
  186. scr_file = open(filename + "." + file_format, "wb")
  187. scr_file.write(csv_buff)
  188. scr_file.close()
  189. print "Saved file:", filename + "." + file_format
  190. tn.close()