def test_configure_motion_controller_trigger(self): xs = LineGenerator("x", "mm", 0.0, 0.3, 4, alternate=True) ys = LineGenerator("y", "mm", 0.0, 0.1, 2) generator = CompoundGenerator([ys, xs], [], [], 1.0) self.set_motor_attributes() self.set_attributes(self.child, rowTrigger="Motion Controller") self.set_attributes(self.child_seq1, bita="TTLIN1.VAL") self.set_attributes(self.child_seq2, bita="TTLIN1.VAL") axes_to_move = ["x", "y"] seq_rows = self.get_sequencer_rows(generator, axes_to_move) # Triggers B0 = Trigger.BITA_0 B1 = Trigger.BITA_1 IT = Trigger.IMMEDIATE # Half a frame hf = 62500000 expected = SequencerRows() expected.add_seq_entry(count=1, trigger=B1, position=0, half_duration=hf, live=1, dead=0) expected.add_seq_entry(3, IT, 0, hf, 1, 0) expected.add_seq_entry(1, B0, 0, MIN_PULSE, 0, 1) expected.add_seq_entry(1, B1, 0, hf, 1, 0) expected.add_seq_entry(3, IT, 0, hf, 1, 0) expected.add_seq_entry(1, IT, 0, MIN_PULSE, 0, 1) expected.add_seq_entry(0, IT, 0, MIN_PULSE, 0, 0) assert seq_rows.as_tuples() == expected.as_tuples()
def test_configure_continuous(self): xs = LineGenerator("x", "mm", 0.0, 0.3, 4, alternate=True) ys = LineGenerator("y", "mm", 0.0, 0.1, 2) generator = CompoundGenerator([ys, xs], [], [], 1.0) self.set_motor_attributes() axes_to_move = ["x", "y"] seq_rows = self.get_sequencer_rows(generator, axes_to_move) # Triggers GT = Trigger.POSA_GT IT = Trigger.IMMEDIATE LT = Trigger.POSA_LT # Half a frame hf = 62500000 # Half how long to be blind for hb = 22500000 expected = SequencerRows() expected.add_seq_entry(count=1, trigger=LT, position=50, half_duration=hf, live=1, dead=0) expected.add_seq_entry(3, IT, 0, hf, 1, 0) expected.add_seq_entry(1, IT, 0, hb, 0, 1) expected.add_seq_entry(1, GT, -350, hf, 1, 0) expected.add_seq_entry(3, IT, 0, hf, 1, 0) expected.add_seq_entry(1, IT, 0, MIN_PULSE, 0, 1) expected.add_seq_entry(0, IT, 0, MIN_PULSE, 0, 0) assert seq_rows.as_tuples() == expected.as_tuples()
def test_configure_stepped(self): xs = LineGenerator("x", "mm", 0.0, 0.3, 4) ys = LineGenerator("y", "mm", 0.0, 0.2, 3) generator = CompoundGenerator([ys, xs], [], [], 1.0, continuous=False) generator.prepare() self.set_motor_attributes() self.set_attributes(self.child, rowTrigger="Motion Controller") self.set_attributes(self.child_seq1, bita="TTLIN1.VAL") self.set_attributes(self.child_seq2, bita="TTLIN1.VAL") axes_to_move = ["x", "y"] seq_rows = self.get_sequencer_rows(generator, axes_to_move) # Triggers B0 = Trigger.BITA_0 B1 = Trigger.BITA_1 IT = Trigger.IMMEDIATE # Half a frame hf = 62500000 expected = SequencerRows() for i in range(11): expected.add_seq_entry(1, B1, 0, hf, 1, 0) expected.add_seq_entry(1, B0, 0, MIN_PULSE, 0, 1) expected.add_seq_entry(1, B1, 0, hf, 1, 0) expected.add_seq_entry(1, IT, 0, MIN_PULSE, 0, 1) expected.add_seq_entry(0, IT, 0, MIN_PULSE, 0, 0) assert seq_rows.as_tuples() == expected.as_tuples()
def test_configure_with_zero_points(self): xs = LineGenerator("x", "mm", 0.0, 0.3, 4, alternate=True) ys = LineGenerator("y", "mm", 0.0, 0.1, 2) generator = CompoundGenerator([ys, xs], [], [], 1.0) self.set_motor_attributes() axes_to_move = ["x", "y"] seq_rows = self.get_sequencer_rows(generator, axes_to_move, steps=0) # Triggers IT = Trigger.IMMEDIATE expected = SequencerRows() expected.add_seq_entry(1, IT, 0, MIN_PULSE, 0, 1) expected.add_seq_entry(0, IT, 0, MIN_PULSE, 0, 0) assert seq_rows.as_tuples() == expected.as_tuples()
def test_acquire_scan(self): generator = CompoundGenerator([StaticPointGenerator(size=5)], [], [], 1.0) generator.prepare() seq_rows = self.get_sequencer_rows(generator, []) # Triggers IT = Trigger.IMMEDIATE # Half a frame hf = 62500000 expected = SequencerRows() expected.add_seq_entry(count=5, trigger=IT, position=0, half_duration=hf, live=1, dead=0) expected.add_seq_entry(1, IT, 0, MIN_PULSE, 0, 1) expected.add_seq_entry(0, IT, 0, MIN_PULSE, 0, 0) assert seq_rows.as_tuples() == expected.as_tuples()
def test_split_with_final_row_zero_repeat(self): seq_rows = SequencerRows() seq_rows.add_seq_entry(4, Trigger.POSB_LT, 400, 1000, 0, 1, 50) seq_rows.add_seq_entry(3, Trigger.BITA_0, 300, 2000, 1, 0, 100) seq_rows.add_seq_entry(0, Trigger.IMMEDIATE, 300, 2000, 0, 1, 100) expected = SequencerRows() # End of scan - no switch delay expected.add_seq_entry(4, Trigger.POSB_LT, 400, 1000, 0, 1, 50) expected.add_seq_entry(3, Trigger.BITA_0, 300, 2000, 1, 0, 100) expected.add_seq_entry(0, Trigger.IMMEDIATE, 300, 2000, 0, 1, 100) remainder = seq_rows.split(3) assert seq_rows.as_tuples() == expected.as_tuples() assert remainder.as_tuples() == SequencerRows().as_tuples()
def test_split_with_final_row_one_repeat(self): seq_rows = SequencerRows() seq_rows.add_seq_entry(4, Trigger.POSB_LT, 400, 1000, 0, 1, 50) seq_rows.add_seq_entry(3, Trigger.BITA_0, 300, 2000, 1, 0, 100) seq_rows.add_seq_entry(1, Trigger.POSB_LT, 300, 2000, 0, 1, 100) expected = SequencerRows() expected.add_seq_entry(4, Trigger.POSB_LT, 400, 1000, 0, 1, 50) expected.add_seq_entry(3, Trigger.BITA_0, 300, 2000, 1, 0, 100) expected.add_seq_entry(1, Trigger.POSB_LT, 300, 2000, 0, 1, 100 + SEQ_TABLE_SWITCH_DELAY) remainder = seq_rows.split(3) assert seq_rows.as_tuples() == expected.as_tuples() assert remainder.as_tuples() == SequencerRows().as_tuples()
def test_extend(self): seq_rows = SequencerRows() seq_rows.add_seq_entry() seq_rows2 = SequencerRows() seq_rows2.add_seq_entry(4, Trigger.POSB_LT, 400, 1000, 0, 1, 50) seq_rows.extend(seq_rows2) total_ticks = (MIN_PULSE * 2) + 4 * (1000 + 950) assert isclose(seq_rows.duration, total_ticks * TICK) assert len(seq_rows) == 2 table = seq_rows.get_table() assert table.repeats == [1, 4] assert table.trigger == [Trigger.IMMEDIATE, Trigger.POSB_LT] assert table.position == [0, 400] assert table.time1 == [MIN_PULSE, 1000] assert table.outa1 == [0, 0] # Live assert table.outb1 == [0, 1] # Dead assert table.outc1 == table.outd1 == table.oute1 == table.outf1 == [ 0, 0 ] assert table.time2 == [MIN_PULSE, 950] assert (table.outa2 == table.outb2 == table.outc2 == table.outd2 == table.oute2 == table.outf2 == [0, 0])
def test_configure_with_one_point(self): xs = LineGenerator("x", "mm", 0.0, 0.3, 4, alternate=True) ys = LineGenerator("y", "mm", 0.0, 0.1, 2) generator = CompoundGenerator([ys, xs], [], [], 1.0) self.set_motor_attributes() axes_to_move = ["x", "y"] seq_rows = self.get_sequencer_rows(generator, axes_to_move, steps=1) # Triggers IT = Trigger.IMMEDIATE LT = Trigger.POSA_LT # Half a frame hf = 62500000 expected = SequencerRows() expected.add_seq_entry(count=1, trigger=LT, position=50, half_duration=hf, live=1, dead=0) expected.add_seq_entry(1, IT, 0, MIN_PULSE, 0, 1) expected.add_seq_entry(0, IT, 0, MIN_PULSE, 0, 0) assert seq_rows.as_tuples() == expected.as_tuples()
def test_split_below_max_table_size(self): seq_rows = SequencerRows() seq_rows.add_seq_entry(4, Trigger.POSB_LT, 400, 1000, 0, 1, 50) seq_rows.add_seq_entry(3, Trigger.BITA_0, 300, 2000, 1, 0, 100) expected = SequencerRows() expected.add_seq_entry(4, Trigger.POSB_LT, 400, 1000, 0, 1, 50) expected.add_seq_entry(2, Trigger.BITA_0, 300, 2000, 1, 0, 100) expected.add_seq_entry(1, Trigger.BITA_0, 300, 2000, 1, 0, 100 + SEQ_TABLE_SWITCH_DELAY) remainder = seq_rows.split(100) assert seq_rows.as_tuples() == expected.as_tuples() assert remainder.as_tuples() == SequencerRows().as_tuples()
def get_sequencer_rows(position=0): min_ticks = int(MIN_TABLE_DURATION / TICK) rows = SequencerRows() rows.add_seq_entry(count=2, half_duration=min_ticks // 4 + 100, position=position) expected = SequencerRows() expected.add_seq_entry(count=1, half_duration=min_ticks // 4 + 100, position=position) expected.add_seq_entry( count=1, half_duration=min_ticks // 4 + 100, position=position, trim=SEQ_TABLE_SWITCH_DELAY, ) return rows, expected
def test_tables_are_set_correctly_on_configure(self): min_ticks = int(MIN_TABLE_DURATION / TICK) rows1 = SequencerRows() # Just over half min duration rows1.add_seq_entry(count=2, half_duration=min_ticks // 8 + 1000) rows2 = SequencerRows() # Just over minimum duration rows2.add_seq_entry(count=1, half_duration=min_ticks // 8 + 1000) rows2.add_seq_entry(count=3, half_duration=min_ticks // 8 + 1000) extra = SequencerRows() # Extra tables are ignored for configure() extra.add_seq_entry(count=2, half_duration=min_ticks // 8 + 1000) extra.add_seq_entry(count=2, half_duration=min_ticks // 8 + 1000) self.db.configure(self.rows_generator([rows1, rows1, rows2, extra])) # Check to ensure repeats is set correctly for table in self.db._table_map.values(): assert table.repeats.value == 1 self.seq_parts[1].table_set.assert_called_once() table1 = self.seq_parts[1].table_set.call_args[0][0] expected1 = SequencerRows() expected1.add_seq_entry(count=2, half_duration=min_ticks // 8 + 1000) expected1.add_seq_entry(count=1, half_duration=min_ticks // 8 + 1000) expected1.add_seq_entry(count=1, half_duration=min_ticks // 8 + 1000, trim=SEQ_TABLE_SWITCH_DELAY) self.assert_rows_equal_table(expected1, table1) self.seq_parts[2].table_set.assert_called_once() table2 = self.seq_parts[2].table_set.call_args[0][0] expected2 = SequencerRows() expected2.add_seq_entry(count=1, half_duration=min_ticks // 8 + 1000) expected2.add_seq_entry(count=2, half_duration=min_ticks // 8 + 1000) expected2.add_seq_entry(count=1, half_duration=min_ticks // 8 + 1000, trim=SEQ_TABLE_SWITCH_DELAY) self.assert_rows_equal_table(expected2, table2)
def test_configure_with_delay_after(self): # a test to show that delay_after inserts a "loop_back" turnaround delay = 1.0 x_steps, y_steps = 3, 2 xs = LineGenerator("x", "mm", 0.0, 0.5, x_steps, alternate=True) ys = LineGenerator("y", "mm", 0.0, 0.1, y_steps) generator = CompoundGenerator([ys, xs], [], [], 1.0, delay_after=delay) self.set_motor_attributes() axes_to_move = ["x", "y"] seq_rows = self.get_sequencer_rows(generator, axes_to_move) # Triggers GT = Trigger.POSA_GT IT = Trigger.IMMEDIATE LT = Trigger.POSA_LT # Half a frame hf = 62500000 # Half how long to be blind for a single point hfb = 55625000 # Half how long to be blind for end of row hrb = 56500000 expected = SequencerRows() expected.add_seq_entry(count=1, trigger=LT, position=125, half_duration=hf, live=1, dead=0) expected.add_seq_entry(1, IT, 0, hfb, 0, 1) expected.add_seq_entry(1, LT, -125, hf, 1, 0) expected.add_seq_entry(1, IT, 0, hfb, 0, 1) expected.add_seq_entry(1, LT, -375, hf, 1, 0) expected.add_seq_entry(1, IT, 0, hrb, 0, 1) expected.add_seq_entry(1, GT, -625, hf, 1, 0) expected.add_seq_entry(1, IT, 0, hfb, 0, 1) expected.add_seq_entry(1, GT, -375, hf, 1, 0) expected.add_seq_entry(1, IT, 0, hfb, 0, 1) expected.add_seq_entry(1, GT, -125, hf, 1, 0) expected.add_seq_entry(1, IT, 0, MIN_PULSE, 0, 1) expected.add_seq_entry(0, IT, 0, MIN_PULSE, 0, 0) assert seq_rows.as_tuples() == expected.as_tuples()
def test_configure_pcomp_row_trigger_with_single_point_rows(self): x_steps, y_steps = 1, 5 xs = LineGenerator("x", "mm", 0.0, 0.5, x_steps, alternate=True) ys = LineGenerator("y", "mm", 0.0, 4, y_steps) generator = CompoundGenerator([ys, xs], [], [], 1.0) self.set_motor_attributes() axes_to_move = ["x", "y"] seq_rows = self.get_sequencer_rows(generator, axes_to_move) # Triggers GT = Trigger.POSA_GT LT = Trigger.POSA_LT IT = Trigger.IMMEDIATE # Half a frame hf = 62500000 # Half blind hb = 75000000 expected = SequencerRows() expected.add_seq_entry(count=1, trigger=LT, position=0, half_duration=hf, live=1, dead=0) expected.add_seq_entry(1, IT, 0, hb, 0, 1) expected.add_seq_entry(1, GT, -500, hf, 1, 0) expected.add_seq_entry(1, IT, 0, hb, 0, 1) expected.add_seq_entry(1, LT, 0, hf, 1, 0) expected.add_seq_entry(1, IT, 0, hb, 0, 1) expected.add_seq_entry(1, GT, -500, hf, 1, 0) expected.add_seq_entry(1, IT, 0, hb, 0, 1) expected.add_seq_entry(1, LT, 0, hf, 1, 0) expected.add_seq_entry(1, IT, 0, MIN_PULSE, 0, 1) expected.add_seq_entry(0, IT, 0, MIN_PULSE, 0, 0) assert seq_rows.as_tuples() == expected.as_tuples()