def test_kill_resets_cs_demands(self): tb = TestBrick() tb.set_cs_group(tb.g3) tb.cs3.set_deferred_moves(True) tb.cs3.set_move_time(3000) tb.height.go(1000, wait=False) tb.cs3.M1.go_direct(1000, wait=False) # verify no motion yet Sleep(.1) self.assertAlmostEqual(tb.height.pos, 0, DECIMALS) self.assertAlmostEqual(tb.m1.pos, 0, DECIMALS) # start motion and then kill all tb.cs3.set_deferred_moves(False) Sleep(.5) tb.send_command('&3a') tb.send_command('#1k') # let the motors settle Sleep(1) h = tb.height.pos m1 = tb.m1.pos self.assertGreater(h, 0) self.assertGreater(m1, 0) # now move a different motor in the CS, the other two would continue to # their previous destinations if makeCSDemandsConsistent has failed tb.cs3.M2.go_direct(10) self.assertAlmostEqual(h, tb.height.pos, DECIMALS) self.assertAlmostEqual(m1, tb.m1.pos, DECIMALS) self.assertAlmostEqual(10, tb.m2.pos, DECIMALS)
def test_stop_on_limit_resets_cs_demands(self): tb = TestBrick() tb.set_cs_group(tb.g3) m = MoveMonitor(tb.height.pv_root) tb.cs3.set_deferred_moves(True) tb.cs3.set_move_time(3000) tb.height.go(10, wait=False) tb.cs3.M1.go_direct(10, wait=False) # verify no motion yet Sleep(.1) self.assertAlmostEqual(tb.height.pos, 0, DECIMALS) self.assertAlmostEqual(tb.m1.pos, 0, DECIMALS) # start motion but stop on lim tb.m3.set_limits(-1, 1) tb.cs3.set_deferred_moves(False) # let axes settle m.wait_for_one_move(2) h = tb.height.pos m1 = tb.m1.pos self.assertLess(h, 10) self.assertLess(m1, 10) # for some reason a large wait is required before go_direct # in a real scenario this is fine even though I don't understand it Sleep(5) # now move a different motor in the CS, the other two would continue to # their previous destinations if makeCSDemandsConsistent has failed tb.cs3.M2.go_direct(10) self.assertAlmostEqual(h, tb.height.pos, DECIMALS) self.assertAlmostEqual(m1, tb.m1.pos, DECIMALS) self.assertAlmostEqual(10, tb.m2.pos, DECIMALS)
def test_abort_cs_resets_cs_demands(self): tb = TestBrick() tb.set_cs_group(tb.g3) tb.cs3.set_deferred_moves(True) tb.cs3.set_move_time(3000) tb.height.go(1000, wait=False) tb.cs3.M1.go_direct(1000, wait=False) # verify no motion yet Sleep(.1) self.assertAlmostEqual(tb.height.pos, 0, DECIMALS) self.assertAlmostEqual(tb.m1.pos, 0, DECIMALS) # start motion and then abort CS moves tb.cs3.set_deferred_moves(False) # allow the axes to get started Sleep(.1) tb.cs3.abort() # let the motors settle Sleep(.5) h = tb.height.pos m1 = tb.m1.pos self.assertGreater(h, 0) self.assertGreater(m1, 0) # now move a different motor in the CS, the other two would continue to # their previous destinations if makeCSDemandsConsistent has failed tb.cs3.M2.go_direct(10) self.assertLess(tb.height.pos, h+1) # some settling after abort is OK self.assertAlmostEqual(m1, tb.m1.pos, DECIMALS) self.assertAlmostEqual(10, tb.m2.pos, DECIMALS)
def animate(i, ax1, thread_1): if thread_1.new_data == 1: axis_bk = axis() ax1.clear() sca(ax1) xlabel('Bunch #') ylabel('Amplitude') title("Bunch " + thread_1.axis + " oscillation amplitude @ NCO={:.5f}".format(thread_1.tune)) plot(thread_1.I, '-o') plot(thread_1.Q, '-o') if not thread_1.reset_axis: axis(axis_bk) else: thread_1.reset_axis = False thread_1.new_data = 0 # Ask for a new capture as soon as previous mem_read is finished with thread_1.trigger_cdt: thread_1.tune = catools.caget(thread_1.device + ':' + thread_1.axis + ':NCO:FREQ_S') # Capture command doesn't work so well (mis-aligned data) #catools.caput(thread_1.device+':MEM:CAPTURE_S', 1, wait=True) catools.caput(thread_1.device + ':TRG:MEM:ARM_S', 1, wait=True) catools.caput(thread_1.device + ':TRG:SOFT_S', 1, wait=True) # Wait for memory to be actually triggered Sleep(0.05) thread_1.trigger_cdt.notify()
def test_real_defer(self): """ check that real axes update as expected on virtual axis moves """ for _ in range(4): # retry for possible occasional race condition tb = TestBrick() tb.set_cs_group(tb.g2) tb.set_deferred_moves(True) tb.jack1.go(5, wait=False) tb.jack2.go(4, wait=False) Sleep(1) # verify no motion yet self.assertAlmostEqual(tb.jack1.pos, 0, DECIMALS) self.assertAlmostEqual(tb.jack2.pos, 0, DECIMALS) m = MoveMonitor(tb.jack1.pv_root) start = datetime.now() tb.set_deferred_moves(False) m.wait_for_one_move(10) elapsed = datetime.now() - start print(elapsed) # verify motion self.assertAlmostEqual(tb.jack1.pos, 5, DECIMALS) self.assertAlmostEqual(tb.jack2.pos, 4, DECIMALS) self.assertTrue(elapsed.seconds < 4)
def go_direct(self, position, wait=True, callback=None): ca.caput(self.direct_demand, position, wait=wait, timeout=60, callback=callback) Sleep(.05) # test clipper reports in position a little early sometimes
def test_auto_home(self): """ verify that autohome works as expected """ tb = TestBrick() for axis in tb.real_axes.values(): axis.go(1, False) Sleep(.5) ca.caput('PMAC_BRICK_TEST:HM:HMGRP', 'All') ca.caput('PMAC_BRICK_TEST:HM:HOME', 1, timeout=15, wait=True) Sleep(.5) # ensure good state if homing failed ca.caput('PMAC_BRICK_TEST:HM:ABORT.PROC', 1) for axis in tb.real_axes.values(): self.assertAlmostEquals(axis.pos, 0)
def set_cs_group(self, group): ca.caput(self.pv_cs_group, group, wait=True) # TODO we have race conditions on switch of CS:- # (1) if the direct demand resolutions need to change there is a small delay # (2) the brick itself may take a short time to do the CS mappings # for now we require a short wait after a switch # (this may not be fixable - (1) showed up on ppmac (2) showed up on VMXI) Sleep(.3)
def test_cs_feedrate_protection(self): """ verify that feedrate protection works for only those CS we have configured """ tb = TestBrick() try: problem = ca.caget("BRICK1:FEEDRATE_PROBLEM_RBV") self.assertEquals(problem, 0) # create a feedrate problem by manually setting a configured feedrate tb.send_command("&2%50") tb.poll_all_now() Sleep(2) # Todo, does requiring this represent an issue? problem = ca.caget("BRICK1:FEEDRATE_PROBLEM_RBV") self.assertEquals(problem, 1) # use driver feature to reset All feedrates ca.caput("BRICK1:FEEDRATE", 100, wait=True) tb.poll_all_now() Sleep(2) problem = ca.caget("BRICK1:FEEDRATE_PROBLEM_RBV") self.assertEquals(problem, 0) # create a feedrate problem by manually setting another configured feedrate tb.send_command("&3%50") tb.poll_all_now() Sleep(2) problem = ca.caget("BRICK1:FEEDRATE_PROBLEM_RBV") self.assertEquals(problem, 1) # use driver feature to reset All feedrates ca.caput("BRICK1:FEEDRATE", 100, wait=True) tb.poll_all_now() Sleep(2) problem = ca.caget("BRICK1:FEEDRATE_PROBLEM_RBV") self.assertEquals(problem, 0) # check that non-configured CS has no effect tb.send_command("&4%50") tb.poll_all_now() Sleep(2) problem = ca.caget("BRICK1:FEEDRATE_PROBLEM_RBV") self.assertEquals(problem, 0) finally: ca.caput("BRICK1:FEEDRATE", 100, wait=True)
def trajectory_quick_scan(test, test_brick): """ Do a short 4D grid scan involving 2 1-1 motors and 2 virtual axes of two jack CS :param test_brick: the test brick instance to run against :param (TestCase) test: the calling test object, used to make assertions """ tr = test_brick.trajectory assert isinstance(tr, Trajectory) # set up the axis parameters tr.axisA.use = 'Yes' tr.axisB.use = 'Yes' tr.axisX.use = 'Yes' tr.axisY.use = 'Yes' # build trajectories (its a 4d raster) heights = [] rows = [] cols = [] angles = [] points = 0 for angle in [-1, 0]: for height in range(2): for col_b in range(3): for row_a in range(4): points += 1 heights.append(height) rows.append(row_a) cols.append(col_b) angles.append(angle) tr.axisA.positions = rows tr.axisB.positions = cols tr.axisX.positions = heights tr.axisY.positions = angles # each step is 50 mill secs times = [50000] * points modes = [0] * points for i in range(0, points, 5): modes[i] = 2 tr.setup_scan(times, modes, points, points, 'CS3') tr.ProfileExecute(timeout=30) test.assertTrue(tr.execute_OK) while test_brick.height.moving: Sleep( .01 ) # allow deceleration todo need to put this in the driver itself test.assertEquals(test_brick.m1.pos, rows[-1]) test.assertEquals(test_brick.m2.pos, cols[-1]) test.assertEquals(test_brick.height.pos, heights[-1]) test.assertEquals(test_brick.angle.pos, angles[-1])
def test_direct_deferred_moves(self): """ verify real motor deferred direct moves work in quick succession using virtual 1-1 mapped axes which also have a CS motor record """ tb = TestBrick() tb.set_cs_group(tb.g1) waiter = MotorCallback() for iteration in range(1): for height1 in range(10, 1, -2): height2 = height1 / 2.0 # todo mixing direct and standard moves to verify no race conditions FAILS # todo the occasional failure is probably due to the two separate busy records # todo interaction - I think this is noncritical since it is not a required # todo use case # tb.all_go([tb.jack1, tb.jack2], [0, 0]) tb.all_go_direct([tb.jack1, tb.jack2], [0, 0]) # tb.all_go_direct([tb.jack1, tb.jack2], [0, 0]) self.assertAlmostEqual(tb.jack1.pos, 0, DECIMALS) self.assertAlmostEqual(tb.jack2.pos, 0, DECIMALS) tb.set_deferred_moves(True) waiter.reset_done() tb.jack1.go_direct(height1, callback=waiter.moves_done, wait=False) tb.jack1.go_direct(height1, wait=False) tb.jack2.go_direct(height2, wait=False) Sleep(.2) # verify no motion yet self.assertAlmostEqual(tb.jack1.pos, 0, DECIMALS) self.assertAlmostEqual(tb.jack2.pos, 0, DECIMALS) start = datetime.now() tb.set_deferred_moves(False) Sleep(.1) waiter.wait_for_done() elapsed = datetime.now() - start print("Iteration {}. Direct Deferred real motors to height {} took {}".format(iteration, height1, elapsed)) # verify motion self.assertAlmostEqual(tb.jack1.pos, height1, DECIMALS) self.assertAlmostEqual(tb.jack2.pos, height2, DECIMALS)
def test_unmapped_real_stop(self): tb = TestBrick() tb.set_cs_group(tb.g3) big_move = 1000 monitor = MoveMonitor(tb.m8.pv_root) tb.m8.go(big_move, wait=False) Sleep(.2) tb.m8.stop() monitor.wait_for_one_move(2) self.assertTrue(0 < tb.m8.pos < big_move)
def wait_for_one_move(self, timeout, throw=True): interval = .1 waited = 0 while not self._completed_one_move: Sleep(interval) waited += interval if waited > timeout: if throw: raise RuntimeError("timeout waiting for motor {}".format( self._motor_pv)) else: break
def test_virtual_abort(self): tb = TestBrick() tb.set_cs_group(tb.g3) big_move = 1000 monitor = MoveMonitor(tb.height.pv_root) tb.height.go(big_move, wait=False) Sleep(.2) tb.cs3.abort() monitor.wait_for_one_move(2) self.assertTrue(0 < tb.height.pos < big_move)
def main(args): with Session(args) as S: while True: try: S.setup() T = time.time() + 1.0 while True: now = time.time() caput(args.prefix + ':LTIME', T - now) if now >= T: _log.warn('Loop too long %f >= %f', now, T) T = now + 1.0 else: # now < T _log.debug('Sleep %f', T - now) Sleep(T - now) T += 1.0 S.loop() except KeyboardInterrupt: _log.debug('Done') break except: # errors, including timeout _log.exception('Error') Sleep(10) # hold-off before reconnect
def test_auto_home_readonly(self): """ verify that auto home makes the motor records read only so that soft limits and user intervention cannot interfere with homing """ tb = TestBrick() ca.caput('PMAC_BRICK_TESTX:HM:HMGRP', 'All') ca.caput('PMAC_BRICK_TESTX:HM:HOME', 1) tb.poll_all_now() tb.jack1.go(20) Sleep(1) ca.caput('PMAC_BRICK_TESTX:HM:ABORT.PROC', 1) self.assertAlmostEqual(tb.jack1.pos, 0, DECIMALS)
def test_i16_small_steps(self): """ verify real motor deferred direct moves work in quick succession using virtual 1-1 mapped axes with CS motor record (copied from i16 tests) """ tb = TestBrick() tb.set_cs_group(tb.g1) waiter = MotorCallback() kphi = tb.kphi.pos kappa = tb.kappa.pos ktheta = tb.ktheta.pos for i in range(1, 5): # set up deferred move waiter.reset_done() tb.cs2.set_deferred_moves(True) next_kphi = kphi + 1 next_kappa = kappa + .01 next_ktheta = ktheta + .01 print('deferred move to kphi {}, kappa {}, ktheta {}'.format( next_kphi, next_kappa, next_ktheta)) tb.cs2.kphi.go_direct(next_kphi, callback=waiter.moves_done, wait=False) tb.cs2.kappa.go_direct(next_kappa, wait=False) tb.cs2.ktheta.go_direct(next_ktheta, wait=False) Sleep(.1) # verify no motion yet self.assertAlmostEquals(tb.kphi.pos, kphi, DECIMALS) self.assertAlmostEquals(tb.kappa.pos, kappa, DECIMALS) self.assertAlmostEquals(tb.ktheta.pos, ktheta, DECIMALS) # make the move tb.cs2.set_deferred_moves(False) waiter.wait_for_done() # verify motion self.assertAlmostEquals(tb.kphi.pos, next_kphi, DECIMALS) self.assertAlmostEquals(tb.kappa.pos, next_kappa, DECIMALS) self.assertAlmostEquals(tb.ktheta.pos, next_ktheta, DECIMALS) kphi = next_kphi kappa = next_kappa ktheta = next_ktheta
def waitpid(self, pid, timeout=None, consume=False): import time if timeout is None: timeout = self.timeout S = time.time() while time.time() - S < timeout: try: cpid, sts = os.waitpid(pid, os.WNOHANG) if cpid != 0: return True except OSError as e: if e.errno == errno.EINTR: pass elif consume: return True else: raise Sleep(0.05) return False
def test_cs_defer(self): """ check timed deferred moves and also individual cs moves """ tb = TestBrick() tb.set_cs_group(tb.g3) tb.cs3.set_deferred_moves(True) tb.cs3.set_move_time(3000) tb.height.go(5, wait=False) tb.angle.go(1, wait=False) # verify no motion yet Sleep(1) self.assertAlmostEqual(tb.height.pos, 0, DECIMALS) self.assertAlmostEqual(tb.angle.pos, 0, DECIMALS) m = MoveMonitor(tb.height.pv_root) start = datetime.now() tb.cs3.set_deferred_moves(False) m.wait_for_one_move(10) elapsed = datetime.now() - start print(elapsed) # verify motion self.assertAlmostEqual(tb.angle.pos, 1, DECIMALS) self.assertAlmostEqual(tb.height.pos, 5, DECIMALS) # todo this seems to take longer than I would expect - is this an issue? # todo YES - moves to real and virtual axes are taking an extra SLOW POLL # todo before DMOV is set True self.assertTrue(3 <= elapsed.seconds < 6) # single axis move should be controlled by speed setting, not CsMoveTime start = datetime.now() tb.height.go(0) elapsed = datetime.now() - start print(elapsed) self.assertAlmostEqual(tb.height.pos, 0, DECIMALS) self.assertTrue(elapsed.seconds < 2)
def test_direct_deferred_moves_cs(self): """ verify coordinated deferred direct moves work in quick succession i16 diffractometer style """ tb = TestBrick() tb.set_cs_group(tb.g3) waiter = MotorCallback() for iteration in range(1): for height in range(10, 0, -2): angle = height / 2.0 # todo mixing direct and standard moves to check for race conditions FAILS tb.all_go_direct([tb.jack1, tb.jack2], [0, 0]) self.assertAlmostEqual(tb.height.pos, 0, DECIMALS) self.assertAlmostEqual(tb.angle.pos, 0, DECIMALS) tb.cs3.set_deferred_moves(True) waiter.reset_done() tb.height.go_direct(height, callback=waiter.moves_done, wait=False) tb.angle.go_direct(angle, wait=False) Sleep(.2) # verify no motion yet self.assertAlmostEqual(tb.height.pos, 0, DECIMALS) self.assertAlmostEqual(tb.angle.pos, 0, DECIMALS) start = datetime.now() tb.cs3.set_deferred_moves(False) waiter.wait_for_done() elapsed = datetime.now() - start print("Iteration {}. Direct Deferred Coordinated to height {} took {}".format(iteration, height, elapsed)) # verify motion self.assertAlmostEqual(tb.height.pos, height, DECIMALS) # only checking to 1 decimal because this is regularly failing - dont think this is an issue self.assertAlmostEqual(tb.angle.pos * 10, angle * 10, 1)
def trajectory_fast_scan(test, test_brick, n_axes, cs='CS3', millisecs=5000): """ Do a fast scan involving n_axes motors :param n_axes: no. of axes to include in trajectory :param test_brick: the test brick instance to run against :param (TestCase) test: the calling test object, used to make assertions """ tr = test_brick.trajectory assert isinstance(tr, Trajectory) # build simple trajectory heights = [] points = 0 for height in range(11): points += 1 heights.append(height / 10.0) # set up the axis parameters axis_count = 0 while axis_count < n_axes: tr.axes[axis_count].use = 'Yes' tr.axes[axis_count].positions = heights axis_count += 1 # each point takes 5 milli sec per axis times = [millisecs * n_axes] * points # all points are interpolated modes = [0] * points tr.setup_scan(times, modes, points, points, cs) tr.ProfileExecute(timeout=30) test.assertTrue(tr.execute_OK) while test_brick.m1.moving: Sleep( .01 ) # allow deceleration todo need to put this in the driver itself
def go(self, position, wait=True): ca.caput(self.demand, position, wait=wait, timeout=60) Sleep(.05) # test clipper reports in position a little early sometimes
bunches_i = arange(bunch, bunch+BUNCH_NB_SCAN)%bunch_nb scan_a = zeros((STEP_NB*FDLY_NB, BUNCH_NB_SCAN+1)) decimation = mbf.get_max_decimation() count = mbf.get_count_max(decimation)//8 tune = caget(pv_base+':'+mbf_axis+':NCO:FREQ_S') offset = 0 ii = 0 print "Scanning DAC delay:" for step in range(STEP_NB): for fine_delay in range(FDLY_NB): printProgressBar(ii+1, STEP_NB*FDLY_NB, prefix=' ', length=50) # set delay caput(pv_base+':DLY:DAC:FINE_DELAY_S', fine_delay) Sleep(0.01) if ii%scan_step == 0: # Capture command doesn't work so well (mis-aligned data) #caput(pv_base+':MEM:CAPTURE_S', 1) caput(pv_base+':TRG:MEM:ARM_S', 1, wait=True) caput(pv_base+':TRG:SOFT_S', 1, wait=True) Sleep(0.1) dly = caget(pv_base+':DLY:DAC:DELAY_PS') scan_a[ii, 0] = dly # Measure bunch amplitude at NCO frequency std_wf = mbf.read_mem_avg(count, offset, channel, decimation, tune) scan_a[ii, 1:BUNCH_NB_SCAN+1] = abs(std_wf[bunches_i]) ii += 1 caput(pv_base+':DLY:DAC:STEP_S', 0) figure()
def trajectory_scan_appending(test, test_brick): """ Do a short 4D grid scan involving 2 1-1 motors and 2 virtual axes of two jack CS :param test_brick: the test brick instance to run against :param (TestCase) test: the calling test object, used to make assertions """ tr = test_brick.trajectory buff_len = tr.BufferLength assert isinstance(tr, Trajectory) # switch to correct CS mappings test_brick.set_cs_group(test_brick.g3) # set up the axis parameters tr.axisX.use = 'Yes' # build trajectory ascend = [] descend = [] points = int(buff_len * 1.1) # must start with > 1 buffer of points total_points = points * 4 for height in range(points): ascend.append(height / 100.0) descend.append((points - height) / 100.0) tr.axisX.positions = ascend is_clipper = True # don't have a good test for this (was is_clipper = buff_len < 1000) time_period = 5000 if is_clipper else 2000 # each point takes 2 milli sec for brick and 3 for clipper times = [time_period] * points # all points are interpolated modes = [0] * points tr.setup_scan(times, modes, points, total_points, 'CS3') tr.axisX.positions = descend tr.configure_axes() tr.AppendPoints() tr.ProfileExecute(wait=False) Sleep(0) for iteration in range(total_points / points / 2 - 1): tr.axisX.positions = ascend tr.configure_axes() tr.AppendPoints() Sleep(1) tr.axisX.positions = descend tr.configure_axes() tr.AppendPoints() Sleep(1) start = datetime.now() while not tr.execute_done: Sleep(.5) elapsed = datetime.now() - start test.assertLess(elapsed.seconds, 120) test.assertTrue(tr.execute_OK) while test_brick.height.moving: Sleep( .01 ) # allow deceleration todo need to put this in the driver itself test.assertAlmostEqual(test_brick.height.pos, descend[-1], 1)
#!/usr/bin/env python from cothread import Sleep from cothread.catools import * NAN=float('nan') INFP=float('inf') INFN=float('-inf') alm='TST-CT{}Alrm-SP' sig='TST-CT{}Sig:1-I' # Reset caput(alm, 0, wait=True) caput(sig, 0, wait=True) Sleep(1) # Swing the value up 0->9 for N in range(10): caput(sig, N, wait=True) Sleep(1) # move around within deadband caput(sig, 8, wait=True) caput(sig, 9, wait=True) caput(sig, 10, wait=True) caput(sig, 8, wait=True) caput(sig, 7, wait=True) caput(sig, 6, wait=True) Sleep(1)
catools.caput(device+':'+dev_axis+':TRG:SEQ:DISARM_S', 1, wait=True) catools.caput(device+':'+dev_axis+':SEQ:RESET_S', 1, wait=True) # Set runout to 99.5 % catools.caput(device+':MEM:RUNOUT_S', 4, wait=True) # Set Long Buffer Selection to ADC0/ADC1 catools.caput(device+':MEM:SELECT_S', 0) # MEM source after FIR catools.caput(device+':'+dev_axis+':ADC:DRAM_SOURCE_S', 1, wait=True) # Set mode to 'One Shot', enable soft trig. catools.caput(device+':TRG:MEM:MODE_S', 0, wait=True) catools.caput(device+':TRG:MEM:SOFT:EN_S', 1, wait=True) # Arm and trig memory catools.caput(device+':TRG:MEM:ARM_S', 1, wait=True) catools.caput(device+':TRG:SOFT_S', 1, wait=True) Sleep(0.1) mbf = MBF_mem(device) decimation = mbf.get_max_decimation() _, max_turn = mbf.get_turn_min_max() count = max_turn//decimation try: ampl_cplx = mbf.read_mem_avg(count, offset, channel, decimation, tune) except: print("Error in read_mem (Timeout?)") raise else: max_i = argmax(abs(ampl_cplx)) f = ampl_cplx*conj(ampl_cplx[max_i]/abs(ampl_cplx[max_i])) I = f.real
def wait_for_done(self): while self.moving: Sleep(.05)