#!/usr/bin/python

# tds-2012.py
# version 0.2 -- 22 December 2006
#
# Plot display of Tektronix TDS-2012 (or other TDS-10xx or TDS-20xx DSO)
#
# Copyright 2004 by John R. Ackermann  N8UR (jra@febo.com)
# Licensed under the GPL version 2 or later; see the file COPYING
# included with this distribution.  I request, but do not require, that
# any modifications that correct bugs or errors, or increase the program's
# functionality, be sent via email to the author at the address above.
#
# Current status:
# Version 0.1 -- first version, and first ever Python program.  Note that
#   binary read requires updated linux-gpib python bindings (post version
#   3.1.99).  If you don't have that version, you can convert to use an
#   ASCII data read as commented below.  Assumes that "scope" is defined 
#   in /etc/gpib.conf.

from Gpib import *
from matplotlib.pylab import *
from matplotlib.ticker import MultipleLocator, FormatStrFormatter
from string import *
from time import *
from struct import *

# how long to sleep after issuing a write
sleeptime = 0.1

# do we gather and display measurements?
show_measurements = 0

# set up GPIB comms and clear device
scope = gpib.find('scope')
gpib.clear(scope)

# set SRQ operation
gpib.write(scope,'DESE 1')
gpib.write(scope,'*ESE 1')
gpib.write(scope,'*SRE 32')

# turn off response headers and set waveform output to default binary
# it seems like these need to be sent separately and not concatenated
gpib.write(scope,'head 0')
gpib.write(scope,'dat INIT')

# get instrument settings
gpib.write(scope,'ch1:scale?')
voltsdiv_ch1 = float(gpib.read(scope,80))
if voltsdiv_ch1 >= 1:
	volt_string_ch1 = '%i V/div' % (voltsdiv_ch1)
else:
	volt_string_ch1 = '%i mv/div' % (voltsdiv_ch1 * 1000)

gpib.write(scope,'ch2:scale?')
voltsdiv_ch2 = float(gpib.read(scope,80))
if voltsdiv_ch2 >= 1:
	volt_string_ch2 = '%i V/div' % (voltsdiv_ch2)
else:
	volt_string_ch2 = '%i mv/div' % (voltsdiv_ch2 * 1000)

gpib.write(scope,'hor:mai:sca?')
tmp = float(gpib.read(scope,80))
rawsweep = tmp
if tmp >= 1:
	sweep_val = tmp
	sweep_suf = "S"
if tmp < 1:
	sweep_val = tmp * 10e2
	sweep_suf = "mS"
	if tmp < 0.001:
		sweep_val = tmp * 10e5
		sweep_suf = "uS"
		if tmp < 0.000001:
			sweep_val = tmp * 10e8
			sweep_suf = "nS"
sweep_val = '%.f' % sweep_val
sweep_string = sweep_val + ' ' + (sweep_suf) + " / div"

# acquire
gpib.write(scope,'acquire:stopafter sequence')
gpib.write(scope,'acquire:state on')

busy = 1
while busy == 1:
	gpib.write(scope,'BUSY?')
	busy = gpib.read(scope,4)
	sleep(0.1)

sleep(1)

# get channel 1
tmp = ""
preamble = []
gpib.write(scope,'data:source CH1')
gpib.write(scope,'wfmpre?')
tmp = gpib.read(scope,256)
preamble = split(tmp,';')
# number of points in trace
points = int(preamble[5])
# volts per bit (-127 to +128)
voltsbit_ch1 = float(preamble[12])

gpib.write(scope,'curv?')
tmp = gpib.readbin(scope,2507)
formatstring = '%ib' % (len(tmp))
tmplist = unpack(formatstring,tmp)
print len(tmplist)
trace_ch1 = []
# there's a newline at the end of the data, thus the strange slice
for x in tmplist[len(tmplist)-points-1:-1]:
	trace_ch1.append(int(x)*voltsbit_ch1)

# get channel 2
tmp = ""
preamble = []
gpib.write(scope,'data:source CH2')
gpib.write(scope,'wfmpre?')
tmp = gpib.read(scope,256)
preamble = split(tmp,';')
points = int(preamble[5])
# volts per bit (-127 to +128)
voltsbit_ch2 = float(preamble[12])

gpib.write(scope,'curv?')
tmp = gpib.readbin(scope,2507)
formatstring = '%ib' % (len(tmp))
tmplist = unpack(formatstring,tmp)
print len(tmplist)
trace_ch2 = []

# scale channel 2 so that the amplitude matches channel 1
for x in tmplist[len(tmplist)-points-1:-1]:
	trace_ch2.append(int(x)*voltsbit_ch2*(voltsbit_ch1/voltsbit_ch2))

# get some measurements, just for fun
if show_measurements:
	tmp = 9.9E37
	gpib.write(scope,'measu:imm:typ PK2;:measu:imm:sou CH1')
	sleep(sleeptime)
	gpib.write(scope,'measu:imm:val?')
	sleep(sleeptime)
	tmp = float(gpib.read(scope,80))
	if tmp != 9.9E37:
		peak_string = 'Pk-Pk: %.3f V' % (tmp)
	else: peak_string = ''

	gpib.write(scope,'measu:imm:typ MEAN;:measu:imm:sou CH1')
	sleep(sleeptime)
	gpib.write(scope,'measu:imm:val?')
	tmp = float(gpib.read(scope,80))
	if tmp != 9.9E37:
		mean_string = 'Mean: %.3f V' % (tmp)
	else: mean_string = ''

	gpib.write(scope,'measu:imm:typ PERI;:measu:imm:sou CH1')
	sleep(sleeptime)
	gpib.write(scope,'measu:imm:val?')
	tmp = float(gpib.read(scope,80))
	if tmp >= 1:
		period_val = tmp
		period_suf = "S"
	if tmp < 1:
		period_val = tmp * 10e2
		period_suf = "mS"
		if tmp < 0.001:
			sweep_val = tmp * 10e5
			sweep_suf = "uS"
			if tmp < 0.000001:
				period_val = tmp * 10e8
				period_suf = "nS"
	if tmp != 9.9E37:
		period_string = 'Period: %.3f' % (period_val) + ' ' + period_suf
	else: period_string = ''

	gpib.write(scope,'measu:imm:typ FREQ;:measu:imm:sou CH1')
	sleep(sleeptime)
	gpib.write(scope,'measu:imm:val?')
	tmp = float(gpib.read(scope,80))
	if tmp < 1e3:
		freq_val = tmp
		freq_suf = "Hz"
	if tmp < 1e6:
		freq_val = tmp / 10e2
		freq_suf = "kHz"
	if tmp >= 1e6:
		freq_val = tmp / 10e5
		freq_suf = "MHz"

	if tmp != 9.9E37:
		freq_string = 'Freq: %.3f' % (freq_val) + ' ' + freq_suf
	else: freq_string = ''

gpib.clear(scope)

# plot

ax = subplot(111)
plot(trace_ch1)
plot(trace_ch2)
axis([0,points,-5*voltsdiv_ch1,5*voltsdiv_ch1])

majorLocator = MultipleLocator(250)
#majorFormatter = FormatStrFormatter('%d')
#minorLocator = MultipleLocator(250)
ax.xaxis.set_major_locator(majorLocator)

yrange = (5*voltsdiv_ch1) * 2
majorLocator = MultipleLocator(yrange/10)
ax.yaxis.set_major_locator(majorLocator)
volt_string = "Ch1: " + volt_string_ch1 + "   " + "Ch2: " + volt_string_ch2
xlabel(volt_string + "                       " + sweep_string)
title('FatPPS Input vs. Output')

setp(gca(), 'xticklabels', [])
if not gca().is_first_col():
	set(gca(), 'yticklabels', [])
if not gca().is_last_row():
	set(gca(), 'xticklabels', [])
grid(1)

if show_measurements:
	text(0.03*points,-4.9*voltsdiv_ch1, peak_string)
	text(0.03*points,-4.4*voltsdiv_ch1, mean_string)
	text(0.72*points,-4.93*voltsdiv_ch1, freq_string)
	text(0.72*points,-4.4*voltsdiv_ch1, period_string)

show()
