Capture the display of a Rigol DS1000Z series oscilloscope by LAN using LXI SCPI commands
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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()