mirror of
https://github.com/slsdetectorgroup/slsDetectorPackage.git
synced 2026-08-07 01:22:26 +02:00
221 lines
6.6 KiB
Python
221 lines
6.6 KiB
Python
from . import Pattern
|
|
from .bits import setbit, clearbit, flipbit
|
|
import textwrap
|
|
|
|
|
|
class PatternGenerator:
|
|
"""
|
|
Class to generate a pattern for the SLS detector. Intents to as closely as possible
|
|
mimic the old pattern generation in the C code.
|
|
"""
|
|
|
|
def __init__(self, verbose=False):
|
|
self.pattern = Pattern()
|
|
self.iaddr = 0
|
|
self.verbose = verbose
|
|
|
|
def clear_pattern(self):
|
|
"""
|
|
Clear the pattern and reset the address to 0.
|
|
"""
|
|
self.pattern[:] = 0
|
|
self.iaddr = 0
|
|
|
|
def SB(self, *bits):
|
|
"""
|
|
Set one or multiple bits. Change will take affect with the next PW.
|
|
"""
|
|
for bit in bits:
|
|
self.pattern.word[self.iaddr] = setbit(bit, self.pattern.word[self.iaddr])
|
|
return self.pattern.word[self.iaddr]
|
|
|
|
def CB(self, *bits):
|
|
"""
|
|
Clear one or multiple bits. Change will take affect with the next PW.
|
|
"""
|
|
for bit in bits:
|
|
self.pattern.word[self.iaddr] = clearbit(bit, self.pattern.word[self.iaddr])
|
|
return self.pattern.word[self.iaddr]
|
|
|
|
def FB(self, *bits):
|
|
"""
|
|
Flip one or multiple bits. Change will take affect with the next PW.
|
|
"""
|
|
for bit in bits:
|
|
self.pattern.word[self.iaddr] = flipbit(bit, self.pattern.word[self.iaddr])
|
|
return self.pattern.word[self.iaddr]
|
|
|
|
def _pw(self):
|
|
if self.verbose:
|
|
print(f"{self.iaddr:#06x} {self.pattern.word[self.iaddr]:#018x}")
|
|
|
|
# Increment the address before the next word since limits are inclusive
|
|
self.pattern.limits[1] = self.iaddr
|
|
self.iaddr += 1
|
|
self.pattern.word[self.iaddr] = self.pattern.word[self.iaddr - 1]
|
|
|
|
def PW(self, words=1):
|
|
for _ in range(words):
|
|
self._pw()
|
|
|
|
def CLOCKS(self, bits, repeats=1, half_period=1):
|
|
"""
|
|
Generate clock pulses on the specified bits.
|
|
|
|
Parameters
|
|
----------
|
|
bit_mask : int
|
|
Bitmask selecting which clock line(s) to pulse.
|
|
repeats : int, optional
|
|
Number of full clock cycles to generate (default 1).
|
|
half_period : int, optional
|
|
Hold time for each half of the cycle (default 1).
|
|
verbose : bool, optional
|
|
If True, print timing/debug info during the wait (default False).
|
|
"""
|
|
if isinstance(bits, int):
|
|
bits = [bits]
|
|
for _ in range(repeats):
|
|
self.FB(*bits)
|
|
self.PW(half_period)
|
|
self.FB(*bits)
|
|
self.PW(half_period)
|
|
|
|
def serializer(self, value, ser_in_bit, clk_bit, nbits, msb_first=True, length=1):
|
|
"""
|
|
Serialize `value` into a shift register via ser_in_bit/clk_bit.
|
|
|
|
Parameters
|
|
----------
|
|
value : int
|
|
Value to serialize.
|
|
ser_in_bit : int
|
|
Control bit corresponding to serial in.
|
|
clk_bit : int
|
|
Control bit corresponding to the clock.
|
|
nbits : int
|
|
Number of bits of the target register to load.
|
|
msb_first : bool, optional
|
|
Push in the MSB first if True (default), else LSB first.
|
|
length : int, optional
|
|
Duration of each PW in the pattern (default 1).
|
|
"""
|
|
bit_order = range(nbits - 1, -1, -1) if msb_first else range(nbits)
|
|
|
|
self.CB(ser_in_bit, clk_bit)
|
|
self.PW(length) # initial line with clk and serIn low
|
|
|
|
for i in bit_order:
|
|
if value & (1 << i):
|
|
self.SB(ser_in_bit)
|
|
else:
|
|
self.CB(ser_in_bit)
|
|
self.PW(length)
|
|
self.SB(clk_bit)
|
|
self.PW(length)
|
|
self.CB(clk_bit)
|
|
self.PW(length)
|
|
|
|
self.CB(ser_in_bit, clk_bit)
|
|
self.PW(length) # final line with clk and serIn low
|
|
|
|
def setoutput(self, *bits):
|
|
"""
|
|
Define one or multiple bits as output.
|
|
"""
|
|
for bit in bits:
|
|
self.pattern.ioctrl = setbit(bit, self.pattern.ioctrl)
|
|
|
|
def setinput(self, *bits):
|
|
"""
|
|
Define one or multiple bits as input.
|
|
"""
|
|
for bit in bits:
|
|
self.pattern.ioctrl = clearbit(bit, self.pattern.ioctrl)
|
|
|
|
# TODO! What should setclk do? Or can we remove it?
|
|
# def setclk(bit):
|
|
# self.clkctrl=self.setbit(bit,self.clkctrl)
|
|
|
|
# def setclks(self, *args):
|
|
# for i in args:
|
|
# self.setclk(i)
|
|
|
|
def setnloop(self, i, reps):
|
|
self.pattern.nloop[i] = reps
|
|
|
|
def setstartloop(self, i):
|
|
"""
|
|
Set startloop[i] to the current address.
|
|
"""
|
|
self.pattern.startloop[i] = self.iaddr
|
|
|
|
def setstoploop(self, i):
|
|
"""
|
|
Set stoploop[i] to the current address.
|
|
"""
|
|
self.pattern.stoploop[i] = self.iaddr
|
|
|
|
def setstart(self):
|
|
"""
|
|
Set start of pattern to the current address.
|
|
"""
|
|
self.pattern.limits[0] = self.iaddr
|
|
|
|
def setstop(self):
|
|
"""
|
|
Set stop of pattern to the current address.
|
|
"""
|
|
self.pattern.limits[1] = self.iaddr
|
|
|
|
def setwaitpoint(self, i):
|
|
"""
|
|
Set wait[i] to the current address.
|
|
"""
|
|
self.pattern.wait[i] = self.iaddr
|
|
|
|
def setwaittime(self, i, t):
|
|
"""
|
|
Set waittime[i] to t.
|
|
"""
|
|
self.pattern.waittime[i] = t
|
|
|
|
def setwait(self, i, t):
|
|
"""
|
|
Set wait[i] to the current address and waittime[i] to t.
|
|
"""
|
|
self.setwait(i)
|
|
self.setwaittime(i, t)
|
|
|
|
def __repr__(self):
|
|
return textwrap.dedent(f"""\
|
|
PatternGenerator:
|
|
patlimits: {self.pattern.limits}
|
|
startloop: {self.pattern.startloop}
|
|
stoploop: {self.pattern.stoploop}
|
|
nloop: {self.pattern.nloop}
|
|
wait: {self.pattern.wait}
|
|
waittime: {self.pattern.waittime}""")
|
|
|
|
def __str__(self):
|
|
return self.pattern.str()
|
|
|
|
def export_pattern(self):
|
|
"""
|
|
Generate the pattern and return it as a Pattern object.
|
|
"""
|
|
return self.pattern.copy()
|
|
|
|
def load_pattern(self, fname):
|
|
"""Load pattern from text file"""
|
|
iaddr = self.pattern.load(fname)
|
|
|
|
# Assume an empty pattern if the first and only word is zero
|
|
if iaddr == 1 and self.pattern.word[0] == 0:
|
|
iaddr = 0
|
|
self.iaddr = iaddr
|
|
|
|
# Set (last + 1) word to the last word
|
|
if iaddr > 0:
|
|
self.pattern.word[iaddr] = self.pattern.word[iaddr - 1]
|