class DigitalScanFreq(object):
	scan_id = "digital_scan"

	def __init__(self, dut_conf=None):
		self.dut = fe65p2(dut_conf)
		self.dut.init()
		self.dut.power_up()
		time.sleep(0.1)
		self.dut['global_conf']['PrmpVbpDac'] = 36
		self.dut['global_conf']['vthin1Dac'] = 255
		self.dut['global_conf']['vthin2Dac'] = 0
		self.dut['global_conf']['vffDac'] = 42
		self.dut['global_conf']['PrmpVbnFolDac'] = 51
		self.dut['global_conf']['vbnLccDac'] = 1
		self.dut['global_conf']['compVbnDac'] = 25
		self.dut['global_conf']['preCompVbnDac'] = 50
		self.dut['global_conf']['Latency'] = 400
		# chip['global_conf']['ColEn'][0] = 1
		self.dut['global_conf']['ColEn'].setall(True)
		self.dut['global_conf']['ColSrEn'].setall(True)  # enable programming of all columns
		self.dut['global_conf']['ColSrOut'] = 15
		self.dut['global_conf']['OneSr'] = 0  # all multi columns in parallel
		self.dut.write_global()
		self.dut['control']['RESET'] = 0b10
		self.dut['control'].write()

		self.working_dir = os.path.join(os.getcwd(), "output_data")
		if not os.path.exists(self.working_dir):
			os.makedirs(self.working_dir)

	@contextmanager
	def readout(self, *args, **kwargs):
		timeout = kwargs.pop('timeout', 10.0)

		# self.fifo_readout.readout_interval = 10
		if not self._first_read:
			self.fifo_readout.reset_rx()
			time.sleep(0.1)
			self.fifo_readout.print_readout_status()
			self._first_read = True

		self.start_readout(*args, **kwargs)
		yield
		self.fifo_readout.stop(timeout=timeout)

	def start_readout(self, scan_param_id=0, *args, **kwargs):
		# Pop parameters for fifo_readout.start
		callback = kwargs.pop('callback', self.handle_data)
		clear_buffer = kwargs.pop('clear_buffer', False)
		fill_buffer = kwargs.pop('fill_buffer', False)
		reset_sram_fifo = kwargs.pop('reset_sram_fifo', False)
		errback = kwargs.pop('errback', self.handle_err)
		no_data_timeout = kwargs.pop('no_data_timeout', None)
		self.scan_param_id = scan_param_id
		self.fifo_readout.start(reset_sram_fifo=reset_sram_fifo, fill_buffer=fill_buffer, clear_buffer=clear_buffer,
								callback=callback, errback=errback, no_data_timeout=no_data_timeout)

	def handle_data(self, data_tuple):
		'''Handling of the data.
		'''
		# print data_tuple[0].shape[0] #, data_tuple

		total_words = self.raw_data_earray.nrows

		self.raw_data_earray.append(data_tuple[0])
		self.raw_data_earray.flush()

		len_raw_data = data_tuple[0].shape[0]
		self.meta_data_table.row['timestamp_start'] = data_tuple[1]
		self.meta_data_table.row['timestamp_stop'] = data_tuple[2]
		self.meta_data_table.row['error'] = data_tuple[3]
		self.meta_data_table.row['data_length'] = len_raw_data
		self.meta_data_table.row['index_start'] = total_words
		total_words += len_raw_data
		self.meta_data_table.row['index_stop'] = total_words
		self.meta_data_table.row['scan_param_id'] = self.scan_param_id
		self.meta_data_table.row.append()
		self.meta_data_table.flush()

	def handle_err(self, exc):
		msg = '%s' % exc[1]
		if msg:
			logging.error('%s%s Aborting run...', msg, msg[-1])
		else:
			logging.error('Aborting run...')

	def scan(self, mask_steps=4, repeat_command=100, columns=[True] * 16, **kwargs):
		'''Scan loop

		Parameters
		----------
		mask : int
			Number of mask steps.
		repeat : int
			Number of injections.
		'''
		self.not_fired = []

		path = "/home/carlo/fe65_p2/firmware/ise/digital_scan_bits/"
		self.bitfiles = OrderedDict([(160, "fe65p2_mio_160.bit"), (144, "fe65p2_mio_144.bit"), (120, "fe65p2_mio_120.bit"),
									 (96, "fe65p2_mio_96.bit"), (72,"fe65p2_mio_72.bit"), (64,"fe65p2_mio_64.bit"), (48,"fe65p2_mio_48.bit")])
#, (144, "fe65p2_mio_144.bit")
		self.voltages = [2.0, 1.8, 1.6, 1.4, 1.2, 1.0, 0.9, 0.85]

		for freq in self.bitfiles.iterkeys():
			logging.info("Loading " + self.bitfiles[freq])  #loading bitfile
			self.dut['intf']._sidev.DownloadXilinx(path + self.bitfiles[freq])

			for volt in self.voltages:
				# to change the supply voltage
				self.dut['VDDA'].set_current_limit(200, unit='mA')
				self.dut['VDDA'].set_voltage(volt, unit='V')
				self.dut['VDDA'].set_enable(True)
				self.dut['VDDD'].set_voltage(volt, unit='V')
				self.dut['VDDD'].set_enable(True)
				self.dut['VAUX'].set_voltage(volt, unit='V')
				self.dut['VAUX'].set_enable(True)
				logging.info(scan.dut.power_status())		#prints power supply
				self.run_name = time.strftime("%Y%m%d_%H%M%S_") + "_" + str(freq) + "MHz_" + str(volt) +"V"
				self.output_filename = os.path.join(self.working_dir, self.run_name)
				self._first_read = False
				self.scan_param_id = 0

				# .h5 output management
				filename = self.output_filename + '.h5'
				filter_raw_data = tb.Filters(complib='blosc', complevel=5, fletcher32=False)
				self.filter_tables = tb.Filters(complib='zlib', complevel=5, fletcher32=False)
				self.h5_file = tb.open_file(filename, mode='w', title=self.scan_id)
				self.raw_data_earray = self.h5_file.createEArray(self.h5_file.root, name='raw_data', atom=tb.UIntAtom(),
																 shape=(0,), title='raw_data', filters=filter_raw_data)
				self.meta_data_table = self.h5_file.createTable(self.h5_file.root, name='meta_data', description=MetaTable,
																title='meta_data', filters=self.filter_tables)

				self.meta_data_table.attrs.kwargs = yaml.dump(kwargs)
				self.dut['control']['RESET'] = 0b00
				self.dut['control'].write()
				time.sleep(0.1)

				self.fifo_readout = FifoReadout(self.dut)

				# write InjEnLd & PixConfLd to '1
				self.dut['pixel_conf'].setall(True)
				self.dut.write_pixel_col()
				self.dut['global_conf']['SignLd'] = 1
				self.dut['global_conf']['InjEnLd'] = 1
				self.dut['global_conf']['TDacLd'] = 0b1111
				self.dut['global_conf']['PixConfLd'] = 0b11
				self.dut.write_global()
				# write SignLd & TDacLd to '0
				self.dut['pixel_conf'].setall(False)
				self.dut.write_pixel_col()
				self.dut['global_conf']['SignLd'] = 0
				self.dut['global_conf']['InjEnLd'] = 0
				self.dut['global_conf']['TDacLd'] = 0b0000
				self.dut['global_conf']['PixConfLd'] = 0b00
				self.dut.write_global()
				# test hit
				self.dut['global_conf']['TestHit'] = 1
				self.dut['global_conf']['SignLd'] = 0
				self.dut['global_conf']['InjEnLd'] = 0
				self.dut['global_conf']['TDacLd'] = 0
				self.dut['global_conf']['PixConfLd'] = 0
				self.dut['global_conf']['OneSr'] = 0  # all multi columns in parallel
				self.dut['global_conf']['ColEn'][:] = bitarray.bitarray(columns)
				self.dut.write_global()
				self.dut['control']['RESET'] = 0b01
				self.dut['control']['DISABLE_LD'] = 1
				self.dut['control'].write()
				self.dut['control']['CLK_OUT_GATE'] = 1
				self.dut['control']['CLK_BX_GATE'] = 1
				self.dut['control'].write()
				time.sleep(0.1)

				self.dut['control']['RESET'] = 0b11
				self.dut['control'].write()

				# enable testhit pulse and trigger
				wiat_for_read = (16 + columns.count(True) * (4 * 64 / mask_steps) * 2) * (20 / 2) + 100
				self.dut['testhit'].set_delay(wiat_for_read)  # this should based on mask and enabled columns
				self.dut['testhit'].set_width(3)
				self.dut['testhit'].set_repeat(repeat_command)
				self.dut['testhit'].set_en(False)

				self.dut['trigger'].set_delay(400 - 4)
				self.dut['trigger'].set_width(8)
				self.dut['trigger'].set_repeat(1)
				self.dut['trigger'].set_en(True)

				lmask = [1] + ([0] * (mask_steps - 1))
				lmask = lmask * ((64 * 64) / mask_steps + 1)
				lmask = lmask[:64 * 64]
				bv_mask = bitarray.bitarray(lmask)

				with self.readout():

					for i in range(mask_steps):

						self.dut['pixel_conf'][:] = bv_mask
						bv_mask[1:] = bv_mask[0:-1]
						bv_mask[0] = 0

						self.dut.write_pixel_col()
						time.sleep(0.1)

						self.dut['testhit'].start()

						if os.environ.get('TRAVIS'):
							logging.debug('.')

						while not self.dut['testhit'].is_done():
							pass

						while not self.dut['trigger'].is_done():
							pass

						# just some time for last read
					self.dut['trigger'].set_en(False)

					self.fifo_readout.print_readout_status()
					self.meta_data_table.attrs.power_status = yaml.dump(self.dut.power_status())
					self.meta_data_table.attrs.dac_status = yaml.dump(self.dut.dac_status())
					self.h5_file.close()
					logging.info('Data Output Filename: %s', self.output_filename + '.h5')
					self.analyze()
		self.shmoo_plotting()

	def analyze(self):
		plots = False
		h5_filename = self.output_filename + '.h5'
		with tb.open_file(h5_filename, 'r+') as in_file_h5:
			raw_data = in_file_h5.root.raw_data[:]
			meta_data = in_file_h5.root.meta_data[:]
			hit_data = self.dut.interpret_raw_data(raw_data, meta_data)
			in_file_h5.createTable(in_file_h5.root, 'hit_data', hit_data, filters=self.filter_tables)
			hits = hit_data['col'].astype(np.uint16)
			hits = hits * 64
			hits = hits + hit_data['row']
			value = np.bincount(hits)
			value = np.pad(value, (0, 64*64 - value.shape[0]), 'constant')
			full_occupation = np.full(4096, 100, dtype=int)
			difference = full_occupation - value
			tot_diff = abs(np.sum(difference))
			if tot_diff<10000: plots=True;
			self.not_fired.append(tot_diff)
			logging.info('Shmoo plot entry: %s', str(tot_diff))

		if plots == True:
			occ_plot, H = plotting.plot_occupancy(h5_filename)
			tot_plot, _ = plotting.plot_tot_dist(h5_filename)
			lv1id_plot, _ = plotting.plot_lv1id_dist(h5_filename)
			output_file(self.output_filename + '.html', title=self.run_name)
			save(vplot(occ_plot, tot_plot, lv1id_plot))
			return H


	def shmoo_plotting(self):
		''' pixel register shmoo plot '''
		shmoopdf = PdfPages('digital_shmoo.pdf')
		shmoonp = np.array(self.not_fired)
		data = shmoonp.reshape(len(self.voltages), -1, order='F')
		fig, ax = plt.subplots()
		plt.title('Missed Voltage Injections (100 inj. x 4096 pix.)')
		ax.set_axis_off()
		tb = Table(ax, bbox=[0.05, 0.05, 0.95, 0.95])
		ncols = len(self.bitfiles)
		nrows = len(self.voltages)
		width, height = 1.0 / ncols, 1.0 / nrows
		# Add cells
		for (i, j), val in np.ndenumerate(data):
			color = ''
			val = abs(val)
			if (val == 0): color = 'green'
			if (val > 0 & val < 50): color = 'yellow'
			if val > 50: color = 'red'
			tb.add_cell(i, j, width, height, text=str(val),
						loc='center', facecolor=color)
		# Row Labels...
		for i in range(len(self.voltages)):
			tb.add_cell(i, -1, width, height, text=str(self.voltages[i]) + ' V', loc='right',
						edgecolor='none', facecolor='none')
		# Column Labels...
		colj = 0
		for j in self.bitfiles.iterkeys():
			tb.add_cell(nrows + 1, colj, width, height / 2, text=str(j) + ' MHz', loc='center',
						edgecolor='none', facecolor='none')
			colj+=1
		ax.add_table(tb)
		shmoopdf.savefig()
		shmoopdf.close()
class DigitalScanFreq(object):
	scan_id = "digital_scan"

	def __init__(self, dut_conf=None):
		self.dut = fe65p2(dut_conf)
		self.dut.init()
		self.dut.power_up()
		time.sleep(0.1)
		self.dut['global_conf']['PrmpVbpDac'] = 36
		self.dut['global_conf']['vthin1Dac'] = 255
		self.dut['global_conf']['vthin2Dac'] = 0
		self.dut['global_conf']['vffDac'] = 42
		self.dut['global_conf']['PrmpVbnFolDac'] = 51
		self.dut['global_conf']['vbnLccDac'] = 1
		self.dut['global_conf']['compVbnDac'] = 25
		self.dut['global_conf']['preCompVbnDac'] = 50
		self.dut['global_conf']['Latency'] = 400
		# chip['global_conf']['ColEn'][0] = 1
		self.dut['global_conf']['ColEn'].setall(True)
		self.dut['global_conf']['ColSrEn'].setall(True)  # enable programming of all columns
		self.dut['global_conf']['ColSrOut'] = 15
		self.dut['global_conf']['OneSr'] = 0  # all multi columns in parallel
		self.dut.write_global()
		self.dut['control']['RESET'] = 0b10
		self.dut['control'].write()

		self.working_dir = os.path.join(os.getcwd(), "output_data")
		if not os.path.exists(self.working_dir):
			os.makedirs(self.working_dir)

	@contextmanager
	def readout(self, *args, **kwargs):
		timeout = kwargs.pop('timeout', 10.0)

		# self.fifo_readout.readout_interval = 10
		if not self._first_read:
			self.fifo_readout.reset_rx()
			time.sleep(0.1)
			self.fifo_readout.print_readout_status()
			self._first_read = True

		self.start_readout(*args, **kwargs)
		yield
		self.fifo_readout.stop(timeout=timeout)

	def start_readout(self, scan_param_id=0, *args, **kwargs):
		# Pop parameters for fifo_readout.start
		callback = kwargs.pop('callback', self.handle_data)
		clear_buffer = kwargs.pop('clear_buffer', False)
		fill_buffer = kwargs.pop('fill_buffer', False)
		reset_sram_fifo = kwargs.pop('reset_sram_fifo', False)
		errback = kwargs.pop('errback', self.handle_err)
		no_data_timeout = kwargs.pop('no_data_timeout', None)
		self.scan_param_id = scan_param_id
		self.fifo_readout.start(reset_sram_fifo=reset_sram_fifo, fill_buffer=fill_buffer, clear_buffer=clear_buffer,
								callback=callback, errback=errback, no_data_timeout=no_data_timeout)

	def handle_data(self, data_tuple):
		'''Handling of the data.
		'''
		# print data_tuple[0].shape[0] #, data_tuple

		total_words = self.raw_data_earray.nrows

		self.raw_data_earray.append(data_tuple[0])
		self.raw_data_earray.flush()

		len_raw_data = data_tuple[0].shape[0]
		self.meta_data_table.row['timestamp_start'] = data_tuple[1]
		self.meta_data_table.row['timestamp_stop'] = data_tuple[2]
		self.meta_data_table.row['error'] = data_tuple[3]
		self.meta_data_table.row['data_length'] = len_raw_data
		self.meta_data_table.row['index_start'] = total_words
		total_words += len_raw_data
		self.meta_data_table.row['index_stop'] = total_words
		self.meta_data_table.row['scan_param_id'] = self.scan_param_id
		self.meta_data_table.row.append()
		self.meta_data_table.flush()

	def handle_err(self, exc):
		msg = '%s' % exc[1]
		if msg:
			logging.error('%s%s Aborting run...', msg, msg[-1])
		else:
			logging.error('Aborting run...')

	def scan(self, mask_steps=4, repeat_command=100, columns=[True] * 16, **kwargs):
		'''Scan loop

		Parameters
		----------
		mask : int
			Number of mask steps.
		repeat : int
			Number of injections.
		'''

		#bitfiles
		self.clock_name='DATA clock'
		path = "/home/carlo/fe65_p2/firmware/ise/DATA_bits/"
#		self.bitfiles = OrderedDict([(20,"fe65p2_mio_CMD20.bit"), (30,"fe65p2_mio_CMD30.bit"),(40,"fe65p2_mio_CMD40.bit"),(50,"fe65p2_mio_CMD50.bit"), (60,"fe65p2_mio_CMD60.bit"),(70,"fe65p2_mio_CMD70.bit"),(80,"fe65p2_mio_CMD80.bit"),(90,"fe65p2_mio_CMD90.bit"), (100,"fe65p2_mio_CMD100.bit"), (110,"fe65p2_mio_CMD110.bit"), (120,"fe65p2_mio_CMD120.bit"), (130,"fe65p2_mio_CMD130.bit"), (140,"fe65p2_mio_CMD140.bit"), (150,"fe65p2_mio_CMD150.bit"),  (160,"fe65p2_mio_CMD160.bit")])
		self.bitfiles = OrderedDict([(40, "fe65p2_mio_DATA40.bit"),(60, "fe65p2_mio_DATA60.bit"), (80, "fe65p2_mio_DATA80.bit"), (100, "fe65p2_mio_DATA100.bit"),(120, "fe65p2_mio_DATA120.bit"),(160, "fe65p2_mio_DATA160.bit")])


		self.voltages = [1.5, 1.4, 1.3, 1.2, 1.1, 1.0, 0.95, 0.9]
#		self.voltages = [1.3, 1.2, 1.1, 1.0]

		self.not_fired = []
		for freq in self.bitfiles.iterkeys():
			logging.info("Loading " + self.bitfiles[freq])  #loading bitfile
			self.dut['intf']._sidev.DownloadXilinx(path + self.bitfiles[freq])

			for volt in self.voltages:
				# to change the supply voltage
				self.dut['VDDA'].set_current_limit(200, unit='mA')
				self.dut['VDDA'].set_voltage(volt, unit='V')
				self.dut['VDDA'].set_enable(True)
				self.dut['VDDD'].set_voltage(volt, unit='V')
				self.dut['VDDD'].set_enable(True)
				self.dut['VAUX'].set_voltage(volt, unit='V')
				self.dut['VAUX'].set_enable(True)
				logging.info(scan.dut.power_status())		#prints power supply
				self.run_name = time.strftime("%Y%m%d_%H%M%S_") + "_" + str(freq) + "MHz_" + str(volt) +"V"
				self.output_filename = os.path.join(self.working_dir, self.run_name)
				self._first_read = False
				self.scan_param_id = 0

				# .h5 output management
				filename = self.output_filename + '.h5'
				filter_raw_data = tb.Filters(complib='blosc', complevel=5, fletcher32=False)
				self.filter_tables = tb.Filters(complib='zlib', complevel=5, fletcher32=False)
				self.h5_file = tb.open_file(filename, mode='w', title=self.scan_id)
				self.raw_data_earray = self.h5_file.createEArray(self.h5_file.root, name='raw_data', atom=tb.UIntAtom(),
																 shape=(0,), title='raw_data', filters=filter_raw_data)
				self.meta_data_table = self.h5_file.createTable(self.h5_file.root, name='meta_data', description=MetaTable,
																title='meta_data', filters=self.filter_tables)

				self.meta_data_table.attrs.kwargs = yaml.dump(kwargs)
				self.dut['control']['RESET'] = 0b00
				self.dut['control'].write()
				time.sleep(0.1)

				self.fifo_readout = FifoReadout(self.dut)

				# write InjEnLd & PixConfLd to '1
				self.dut['pixel_conf'].setall(True)
				self.dut.write_pixel_col()
				self.dut['global_conf']['SignLd'] = 1
				self.dut['global_conf']['InjEnLd'] = 1
				self.dut['global_conf']['TDacLd'] = 0b1111
				self.dut['global_conf']['PixConfLd'] = 0b11
				self.dut.write_global()
				# write SignLd & TDacLd to '0
				self.dut['pixel_conf'].setall(False)
				self.dut.write_pixel_col()
				self.dut['global_conf']['SignLd'] = 0
				self.dut['global_conf']['InjEnLd'] = 0
				self.dut['global_conf']['TDacLd'] = 0b0000
				self.dut['global_conf']['PixConfLd'] = 0b00
				self.dut.write_global()
				# test hit
				self.dut['global_conf']['TestHit'] = 1
				self.dut['global_conf']['SignLd'] = 0
				self.dut['global_conf']['InjEnLd'] = 0
				self.dut['global_conf']['TDacLd'] = 0
				self.dut['global_conf']['PixConfLd'] = 0
				self.dut['global_conf']['OneSr'] = 0  # all multi columns in parallel
				self.dut['global_conf']['ColEn'][:] = bitarray.bitarray(columns)
				self.dut.write_global()
				self.dut['control']['RESET'] = 0b01
				self.dut['control']['DISABLE_LD'] = 1
				self.dut['control'].write()
				self.dut['control']['CLK_OUT_GATE'] = 1
				self.dut['control']['CLK_BX_GATE'] = 1
				self.dut['control'].write()
				time.sleep(0.1)

				self.dut['control']['RESET'] = 0b11
				self.dut['control'].write()

				# enable testhit pulse and trigger
				wiat_for_read = (16 + columns.count(True) * (4 * 64 / mask_steps) * 2) * (20 / 2) + 100
				self.dut['testhit'].set_delay(wiat_for_read*4)  # this should based on mask and enabled columns
				self.dut['testhit'].set_width(3)
				self.dut['testhit'].set_repeat(repeat_command)
				self.dut['testhit'].set_en(False)

				self.dut['trigger'].set_delay(400 - 4)
				self.dut['trigger'].set_width(8)
				self.dut['trigger'].set_repeat(1)
				self.dut['trigger'].set_en(True)

				lmask = [1] + ([0] * (mask_steps - 1))
				lmask = lmask * ((64 * 64) / mask_steps + 1)
				lmask = lmask[:64 * 64]
				bv_mask = bitarray.bitarray(lmask)

				with self.readout():

					for i in range(mask_steps):

						self.dut['pixel_conf'][:] = bv_mask
						bv_mask[1:] = bv_mask[0:-1]
						bv_mask[0] = 0

						self.dut.write_pixel_col()
						time.sleep(0.1)

						self.dut['testhit'].start()

						if os.environ.get('TRAVIS'):
							logging.debug('.')

						while not self.dut['testhit'].is_done():
							pass

						while not self.dut['trigger'].is_done():
							pass

						# just some time for last read
					self.dut['trigger'].set_en(False)

					self.fifo_readout.print_readout_status()
					self.meta_data_table.attrs.power_status = yaml.dump(self.dut.power_status())
					self.meta_data_table.attrs.dac_status = yaml.dump(self.dut.dac_status())
					self.h5_file.close()
					logging.info('Data Output Filename: %s', self.output_filename + '.h5')
					self.analyze()
		self.shmoo_plotting()

	def analyze(self):
		plots = False
		h5_filename = self.output_filename + '.h5'
		with tb.open_file(h5_filename, 'r+') as in_file_h5:
			raw_data = in_file_h5.root.raw_data[:]
			meta_data = in_file_h5.root.meta_data[:]
			hit_data = self.dut.interpret_raw_data(raw_data, meta_data)
			in_file_h5.createTable(in_file_h5.root, 'hit_data', hit_data, filters=self.filter_tables)
			hits = hit_data['col'].astype(np.uint16)
			hits = hits * 64
			hits = hits + hit_data['row']
			value = np.bincount(hits)
			value = np.pad(value, (0, 64*64 - value.shape[0]), 'constant')
			full_occupation = np.full(4096, 100, dtype=int)
			difference = full_occupation - value
			tot_diff = abs(np.sum(difference))
			if tot_diff<400000: plots=True
			self.not_fired.append(tot_diff)
			logging.info('Shmoo plot entry: %s', str(tot_diff))

		if plots == True:
			occ_plot, H = plotting.plot_occupancy(h5_filename)
			tot_plot, _ = plotting.plot_tot_dist(h5_filename)
			lv1id_plot, _ = plotting.plot_lv1id_dist(h5_filename)
			output_file(self.output_filename + '.html', title=self.run_name)
			save(vplot(occ_plot, tot_plot, lv1id_plot))
			return H


	def shmoo_plotting(self):
		''' pixel register shmoo plot '''
		shmoopdf = PdfPages('digital_shmoo.pdf')
		shmoonp = np.array(self.not_fired)
		data = shmoonp.reshape(len(self.voltages), -1, order='F')
		fig, ax = plt.subplots()
		plt.title('Missed Voltage Pulses (100 inj. x 4096 pix.)')
		ax.set_axis_off()
		fig.text(0.70, 0.05, self.clock_name +' (MHz)', fontsize=14)
		fig.text(0.02, 0.90, 'Supply voltage (V)', fontsize=14, rotation=90)
		tb = Table(ax, bbox=[0.01, 0.01, 0.99, 0.99])
		ncols = len(self.bitfiles)
		nrows = len(self.voltages)
		width, height = 1.0 / ncols, 1.0 / nrows
		# Add cells
		for (i, j), val in np.ndenumerate(data):
			color = ''
			val = abs(val)
			#use different colors for frequencies above 110MHz where the FPGA is no more reliable
			if(j<10):
				if (val == 0): color = 'green'
				if (val > 0 & val < 50): color = 'yellow'
				if val > 50: color = 'red'
			#greyscale
			if(j>9):
				if (val == 0): color = 'white'
				if (val > 0 & val < 50): color ='#b2b2b2'
				if val > 50: color = '#9a9a9a'
			tb.add_cell(i, j, width, height, text=str(val),
						loc='center', facecolor=color)
		# Row Labels...
		for i in range(len(self.voltages)):
			tb.add_cell(i, -1, width, height, text=str(self.voltages[i]), loc='right',
						edgecolor='none', facecolor='none')
		# Column Labels...
		colj = 0
		for j in self.bitfiles.iterkeys():
			tb.add_cell(nrows + 1, colj, width, height / 2, text=str(j), loc='center',
						edgecolor='none', facecolor='none')
			colj+=1
		ax.add_table(tb)
		shmoopdf.savefig()
		shmoopdf.close()
	def scan(self, mask_steps=4, repeat_command=100, columns=[True] * 16, **kwargs):
		'''Scan loop

		Parameters
		----------
		mask : int
			Number of mask steps.
		repeat : int
			Number of injections.
		'''
		self.not_fired = []

		path = "/home/carlo/fe65_p2/firmware/ise/digital_scan_bits/"
		self.bitfiles = OrderedDict([(160, "fe65p2_mio_160.bit"), (144, "fe65p2_mio_144.bit"), (120, "fe65p2_mio_120.bit"),
									 (96, "fe65p2_mio_96.bit"), (72,"fe65p2_mio_72.bit"), (64,"fe65p2_mio_64.bit"), (48,"fe65p2_mio_48.bit")])
#, (144, "fe65p2_mio_144.bit")
		self.voltages = [2.0, 1.8, 1.6, 1.4, 1.2, 1.0, 0.9, 0.85]

		for freq in self.bitfiles.iterkeys():
			logging.info("Loading " + self.bitfiles[freq])  #loading bitfile
			self.dut['intf']._sidev.DownloadXilinx(path + self.bitfiles[freq])

			for volt in self.voltages:
				# to change the supply voltage
				self.dut['VDDA'].set_current_limit(200, unit='mA')
				self.dut['VDDA'].set_voltage(volt, unit='V')
				self.dut['VDDA'].set_enable(True)
				self.dut['VDDD'].set_voltage(volt, unit='V')
				self.dut['VDDD'].set_enable(True)
				self.dut['VAUX'].set_voltage(volt, unit='V')
				self.dut['VAUX'].set_enable(True)
				logging.info(scan.dut.power_status())		#prints power supply
				self.run_name = time.strftime("%Y%m%d_%H%M%S_") + "_" + str(freq) + "MHz_" + str(volt) +"V"
				self.output_filename = os.path.join(self.working_dir, self.run_name)
				self._first_read = False
				self.scan_param_id = 0

				# .h5 output management
				filename = self.output_filename + '.h5'
				filter_raw_data = tb.Filters(complib='blosc', complevel=5, fletcher32=False)
				self.filter_tables = tb.Filters(complib='zlib', complevel=5, fletcher32=False)
				self.h5_file = tb.open_file(filename, mode='w', title=self.scan_id)
				self.raw_data_earray = self.h5_file.createEArray(self.h5_file.root, name='raw_data', atom=tb.UIntAtom(),
																 shape=(0,), title='raw_data', filters=filter_raw_data)
				self.meta_data_table = self.h5_file.createTable(self.h5_file.root, name='meta_data', description=MetaTable,
																title='meta_data', filters=self.filter_tables)

				self.meta_data_table.attrs.kwargs = yaml.dump(kwargs)
				self.dut['control']['RESET'] = 0b00
				self.dut['control'].write()
				time.sleep(0.1)

				self.fifo_readout = FifoReadout(self.dut)

				# write InjEnLd & PixConfLd to '1
				self.dut['pixel_conf'].setall(True)
				self.dut.write_pixel_col()
				self.dut['global_conf']['SignLd'] = 1
				self.dut['global_conf']['InjEnLd'] = 1
				self.dut['global_conf']['TDacLd'] = 0b1111
				self.dut['global_conf']['PixConfLd'] = 0b11
				self.dut.write_global()
				# write SignLd & TDacLd to '0
				self.dut['pixel_conf'].setall(False)
				self.dut.write_pixel_col()
				self.dut['global_conf']['SignLd'] = 0
				self.dut['global_conf']['InjEnLd'] = 0
				self.dut['global_conf']['TDacLd'] = 0b0000
				self.dut['global_conf']['PixConfLd'] = 0b00
				self.dut.write_global()
				# test hit
				self.dut['global_conf']['TestHit'] = 1
				self.dut['global_conf']['SignLd'] = 0
				self.dut['global_conf']['InjEnLd'] = 0
				self.dut['global_conf']['TDacLd'] = 0
				self.dut['global_conf']['PixConfLd'] = 0
				self.dut['global_conf']['OneSr'] = 0  # all multi columns in parallel
				self.dut['global_conf']['ColEn'][:] = bitarray.bitarray(columns)
				self.dut.write_global()
				self.dut['control']['RESET'] = 0b01
				self.dut['control']['DISABLE_LD'] = 1
				self.dut['control'].write()
				self.dut['control']['CLK_OUT_GATE'] = 1
				self.dut['control']['CLK_BX_GATE'] = 1
				self.dut['control'].write()
				time.sleep(0.1)

				self.dut['control']['RESET'] = 0b11
				self.dut['control'].write()

				# enable testhit pulse and trigger
				wiat_for_read = (16 + columns.count(True) * (4 * 64 / mask_steps) * 2) * (20 / 2) + 100
				self.dut['testhit'].set_delay(wiat_for_read)  # this should based on mask and enabled columns
				self.dut['testhit'].set_width(3)
				self.dut['testhit'].set_repeat(repeat_command)
				self.dut['testhit'].set_en(False)

				self.dut['trigger'].set_delay(400 - 4)
				self.dut['trigger'].set_width(8)
				self.dut['trigger'].set_repeat(1)
				self.dut['trigger'].set_en(True)

				lmask = [1] + ([0] * (mask_steps - 1))
				lmask = lmask * ((64 * 64) / mask_steps + 1)
				lmask = lmask[:64 * 64]
				bv_mask = bitarray.bitarray(lmask)

				with self.readout():

					for i in range(mask_steps):

						self.dut['pixel_conf'][:] = bv_mask
						bv_mask[1:] = bv_mask[0:-1]
						bv_mask[0] = 0

						self.dut.write_pixel_col()
						time.sleep(0.1)

						self.dut['testhit'].start()

						if os.environ.get('TRAVIS'):
							logging.debug('.')

						while not self.dut['testhit'].is_done():
							pass

						while not self.dut['trigger'].is_done():
							pass

						# just some time for last read
					self.dut['trigger'].set_en(False)

					self.fifo_readout.print_readout_status()
					self.meta_data_table.attrs.power_status = yaml.dump(self.dut.power_status())
					self.meta_data_table.attrs.dac_status = yaml.dump(self.dut.dac_status())
					self.h5_file.close()
					logging.info('Data Output Filename: %s', self.output_filename + '.h5')
					self.analyze()
		self.shmoo_plotting()
	def scan(self, mask_steps=4, repeat_command=100, columns=[True] * 16, **kwargs):
		'''Scan loop

		Parameters
		----------
		mask : int
			Number of mask steps.
		repeat : int
			Number of injections.
		'''

		#bitfiles
		self.clock_name='DATA clock'
		path = "/home/carlo/fe65_p2/firmware/ise/DATA_bits/"
#		self.bitfiles = OrderedDict([(20,"fe65p2_mio_CMD20.bit"), (30,"fe65p2_mio_CMD30.bit"),(40,"fe65p2_mio_CMD40.bit"),(50,"fe65p2_mio_CMD50.bit"), (60,"fe65p2_mio_CMD60.bit"),(70,"fe65p2_mio_CMD70.bit"),(80,"fe65p2_mio_CMD80.bit"),(90,"fe65p2_mio_CMD90.bit"), (100,"fe65p2_mio_CMD100.bit"), (110,"fe65p2_mio_CMD110.bit"), (120,"fe65p2_mio_CMD120.bit"), (130,"fe65p2_mio_CMD130.bit"), (140,"fe65p2_mio_CMD140.bit"), (150,"fe65p2_mio_CMD150.bit"),  (160,"fe65p2_mio_CMD160.bit")])
		self.bitfiles = OrderedDict([(40, "fe65p2_mio_DATA40.bit"),(60, "fe65p2_mio_DATA60.bit"), (80, "fe65p2_mio_DATA80.bit"), (100, "fe65p2_mio_DATA100.bit"),(120, "fe65p2_mio_DATA120.bit"),(160, "fe65p2_mio_DATA160.bit")])


		self.voltages = [1.5, 1.4, 1.3, 1.2, 1.1, 1.0, 0.95, 0.9]
#		self.voltages = [1.3, 1.2, 1.1, 1.0]

		self.not_fired = []
		for freq in self.bitfiles.iterkeys():
			logging.info("Loading " + self.bitfiles[freq])  #loading bitfile
			self.dut['intf']._sidev.DownloadXilinx(path + self.bitfiles[freq])

			for volt in self.voltages:
				# to change the supply voltage
				self.dut['VDDA'].set_current_limit(200, unit='mA')
				self.dut['VDDA'].set_voltage(volt, unit='V')
				self.dut['VDDA'].set_enable(True)
				self.dut['VDDD'].set_voltage(volt, unit='V')
				self.dut['VDDD'].set_enable(True)
				self.dut['VAUX'].set_voltage(volt, unit='V')
				self.dut['VAUX'].set_enable(True)
				logging.info(scan.dut.power_status())		#prints power supply
				self.run_name = time.strftime("%Y%m%d_%H%M%S_") + "_" + str(freq) + "MHz_" + str(volt) +"V"
				self.output_filename = os.path.join(self.working_dir, self.run_name)
				self._first_read = False
				self.scan_param_id = 0

				# .h5 output management
				filename = self.output_filename + '.h5'
				filter_raw_data = tb.Filters(complib='blosc', complevel=5, fletcher32=False)
				self.filter_tables = tb.Filters(complib='zlib', complevel=5, fletcher32=False)
				self.h5_file = tb.open_file(filename, mode='w', title=self.scan_id)
				self.raw_data_earray = self.h5_file.createEArray(self.h5_file.root, name='raw_data', atom=tb.UIntAtom(),
																 shape=(0,), title='raw_data', filters=filter_raw_data)
				self.meta_data_table = self.h5_file.createTable(self.h5_file.root, name='meta_data', description=MetaTable,
																title='meta_data', filters=self.filter_tables)

				self.meta_data_table.attrs.kwargs = yaml.dump(kwargs)
				self.dut['control']['RESET'] = 0b00
				self.dut['control'].write()
				time.sleep(0.1)

				self.fifo_readout = FifoReadout(self.dut)

				# write InjEnLd & PixConfLd to '1
				self.dut['pixel_conf'].setall(True)
				self.dut.write_pixel_col()
				self.dut['global_conf']['SignLd'] = 1
				self.dut['global_conf']['InjEnLd'] = 1
				self.dut['global_conf']['TDacLd'] = 0b1111
				self.dut['global_conf']['PixConfLd'] = 0b11
				self.dut.write_global()
				# write SignLd & TDacLd to '0
				self.dut['pixel_conf'].setall(False)
				self.dut.write_pixel_col()
				self.dut['global_conf']['SignLd'] = 0
				self.dut['global_conf']['InjEnLd'] = 0
				self.dut['global_conf']['TDacLd'] = 0b0000
				self.dut['global_conf']['PixConfLd'] = 0b00
				self.dut.write_global()
				# test hit
				self.dut['global_conf']['TestHit'] = 1
				self.dut['global_conf']['SignLd'] = 0
				self.dut['global_conf']['InjEnLd'] = 0
				self.dut['global_conf']['TDacLd'] = 0
				self.dut['global_conf']['PixConfLd'] = 0
				self.dut['global_conf']['OneSr'] = 0  # all multi columns in parallel
				self.dut['global_conf']['ColEn'][:] = bitarray.bitarray(columns)
				self.dut.write_global()
				self.dut['control']['RESET'] = 0b01
				self.dut['control']['DISABLE_LD'] = 1
				self.dut['control'].write()
				self.dut['control']['CLK_OUT_GATE'] = 1
				self.dut['control']['CLK_BX_GATE'] = 1
				self.dut['control'].write()
				time.sleep(0.1)

				self.dut['control']['RESET'] = 0b11
				self.dut['control'].write()

				# enable testhit pulse and trigger
				wiat_for_read = (16 + columns.count(True) * (4 * 64 / mask_steps) * 2) * (20 / 2) + 100
				self.dut['testhit'].set_delay(wiat_for_read*4)  # this should based on mask and enabled columns
				self.dut['testhit'].set_width(3)
				self.dut['testhit'].set_repeat(repeat_command)
				self.dut['testhit'].set_en(False)

				self.dut['trigger'].set_delay(400 - 4)
				self.dut['trigger'].set_width(8)
				self.dut['trigger'].set_repeat(1)
				self.dut['trigger'].set_en(True)

				lmask = [1] + ([0] * (mask_steps - 1))
				lmask = lmask * ((64 * 64) / mask_steps + 1)
				lmask = lmask[:64 * 64]
				bv_mask = bitarray.bitarray(lmask)

				with self.readout():

					for i in range(mask_steps):

						self.dut['pixel_conf'][:] = bv_mask
						bv_mask[1:] = bv_mask[0:-1]
						bv_mask[0] = 0

						self.dut.write_pixel_col()
						time.sleep(0.1)

						self.dut['testhit'].start()

						if os.environ.get('TRAVIS'):
							logging.debug('.')

						while not self.dut['testhit'].is_done():
							pass

						while not self.dut['trigger'].is_done():
							pass

						# just some time for last read
					self.dut['trigger'].set_en(False)

					self.fifo_readout.print_readout_status()
					self.meta_data_table.attrs.power_status = yaml.dump(self.dut.power_status())
					self.meta_data_table.attrs.dac_status = yaml.dump(self.dut.dac_status())
					self.h5_file.close()
					logging.info('Data Output Filename: %s', self.output_filename + '.h5')
					self.analyze()
		self.shmoo_plotting()