diff --git a/Readme.md b/Readme.md index 9443110..0d12a4f 100644 --- a/Readme.md +++ b/Readme.md @@ -1274,4 +1274,194 @@ Make z to move over the grid. ?? what are the PV for the camera, zoom etc ??? +``` + + +30.9.22 Debug Synchronization +============================= + +https://docs.google.com/document/d/1soSuCZYyfGf_ntcgG_Y1_WeGuo_687OuFn0s4sMj1uY/edit + + +remote ssh tunnel + start gather_server +--------------------------------------- +``` +PPMAC=SAR-CPPM-EXPMX1 +rsync -va ~/Documents/prj/SwissFEL/PBTools/pbtools/gather/gather_server root@$PPMAC:/tmp/ +lsof -i -n | grep '127.0.0.1:1000' +ssh -L 10001:localhost:22 root@$PPMAC 'uname -a' +ssh -L 10002:localhost:2332 root@$PPMAC 'uname -a' +ssh root@$PPMAC +LD_LIBRARY_PATH=/opt/ppmac/libppmac/ /tmp/gather_server +``` + +cleanup /tmp/ +------------- +``` +PPMAC=SAR-CPPM-EXPMX1 +ssh root@$PPMAC rm /tmp/gather_server /tmp/triggerSync +ssh root@$PPMAC ls -l /tmp +``` + +start debug tools +----------------- +``` +PPMAC=SAR-CPPM-EXPMX1 +PBInspect --host=$PPMAC& +gpasciiCommander --host $PPMAC -i +ssh root@$PPMAC +ssh root@$PPMAC rm /tmp/gather_server /tmp/triggerSync +ssh root@$PPMAC ls -l /tmp +``` + +restart IOC +----------- +``` +ssh saresc-cons-03 +PPMAC=SAR-CPPM-EXPMX1 +telnet $PPMAC 50001 +Ctrl-X +dbgf SAR-CPPM-EXPMX1:MOD_VER + +caget SAR-CPPM-EXPMX1:MOD_VER + +``` + +checking versions +----------------- +``` +git: 7a968aac967 +asyn 427.0.2 +motorBase alpha_220518 +asynMotor alpha_220518 +powerPmac alpha_220518 +PB_COMMON 2.0.1 +gpasciiCommander 0.9.0 +ESB_MX 0.0.2 +``` + +zamofing_t@ganymede:~/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX$ +git loggraph -10 +* 7a968aa 2022-09-20 (HEAD -> master, tag: latest, tag: 0.0.2, psigithub/master) change speeds and directions [Thierry Zamofing] +* 00588f8 2022-09-16 minor changes [Thierry Zamofing] +* d52a6ce 2022-08-30 minor changes [Thierry Zamofing] +* f47e111 2022-05-20 (tag: 0.0.1) add DET_Z motor [Thierry Zamofing] +* 8e5b15e 2022-05-20 wip [Thierry Zamofing] +* 399282c 2019-03-20 enhance triggering [Thierry Zamofing] +* eda8caf 2019-03-19 wip [Thierry Zamofing] +* 0c45705 2019-03-08 optimize [Thierry Zamofing] +* c962ebd 2019-03-06 documentation [Thierry Zamofing] + +git reset --hard 7a968aa +rmake -e LIBVERSION=42.42.42 uninstall install +-> restart IOC + +ssh root@$PPMAC rm /tmp/triggerSync +cd python +git dt latest -- shapepath.py +./shapepath.py --host=localhost:10001:10002 + +removing test verion +ssh sf-lc7 ls -l /ioc/modules/ESB_MX/ +ssh sf-lc7 rm -rf /ioc/modules/ESB_MX/42.42.42 + + +IOC locations +------------- +``` +~/Documents/prj/SwissFEL/epics_ioc_boot_sf/ESC_all/ESB_MX_PowerBrick +They are just using the new alphy driver. That should have no impact on the motion config. +``` + + +Current (old) Synchronization +----------------------------- +``` +default: +/ESB_MX/src/triggerSync/triggerSync.c -> read usage +simulate start trigger -> pshm->Coord[1].Q[10]=1 to simulate a Jungfrau aquire start\n\ +simulate frame trigger -> pshm->Coord[1].Q[11] +Coord[1].Q[0] is incremented at each trigger + +Coord[1].DesTimeBase is adjusted at each frame trigger + +Coord[1].pDesTimeBase=Coord[1].DesTimeBase.a + + +gpascii: set Gather.Enable=1 +PMAC: LD_LIBRARY_PATH=/opt/ppmac/libppmac/ /tmp/triggerSync 10 0 11 -> wait for start trigger +gpascii: set Start trigger: pshm->Coord[1].Q[10]=1 or set EVR that generates the trigger +PMAC: start Gather (Gather.Enable=2) + count and sync frames: + Coord[1].Q[0] = frame counter +gpascii: stop Gather -> Gather.Enable=0 +PMAC: triggerSync stops when Gather.Enable=0 + + +``` + +Enhanced Synchronization +------------------------ +``` +(to be tested) +Coord[1].pDesTimeBase=Coord[1].DesTimeBase.a +For “external time base”, in which the coordinate system’s time base value is proportional to the +frequency of an incoming encoder signal or pulse train, Coord[x].pDesTimeBase should be set +to EncTable[i].DeltaPos.a + +Setup EncTable: +EncTable[n].type = (3)Software 1/T encoder extension (5)Four-byte read 32 bit int (11) Float 32f or 64f + +The ERV are mapped to +//Power PMAC Software Reference Manual.pdf Gate3[i].Chan[j].Status -> page 919 UserFlag +(gate3_1->Chan[0].Status&0x800) = Gate3[1].Chan[0].UserFlag Trigger start +(gate3_1->Chan[1].Status&0x800) = Gate3[1].Chan[1].UserFlag Trigger frame + + +Use EncTable 20 as Frame counter +Gate3[1].Chan[1].EncCtrl = $encctrl +EncTable[20].type = 3 +EncTable[20].pEnc = Gate3[1].Chan[1].UserFlag.a (is same as Gate3[1].Chan[1].Status) thus it will not work +EncTable[20].pEnc1 = Gate3[1].Chan[0].TimerA.a +EncTable[20].index1 = 0 +EncTable[20].index2 = 0 +EncTable[20].index3 = 0 +EncTable[20].index4 = 0 +EncTable[20].index5 = 0 +EncTable[20].ScaleFactor = 1/256 +-> THIS DOES NOT WORK WITH CURRENT CONNECTIONS ! +-> ONE PHYSICAL ENCODER WOULD NEED PULSE AND DIRECTION INPUT AND SET Gate3[1].Chan[1].EncCtrl TO 'pulse and direction' mode + + +> Sys.Ddata[0]=Sys.Ddata[0]+10 + +Use EncTable 20 as Frame counter +Gate3[1].Chan[1].EncCtrl = $encctrl +EncTable[20].type = 11 //loating point read +EncTable[20].pEnc = Sys.Ddata[0].a +EncTable[20].pEnc1 = Gate3[1].Chan[0].TimerA.a +EncTable[20].index1 = 0 +EncTable[20].index2 = 0 +EncTable[20].index3 = 0 +EncTable[20].index4 = 0 +EncTable[20].index5 = 99 //multiply with 100 +EncTable[20].index5 = 1 //float64 +EncTable[20].ScaleFactor = 1/256 +EncTable[20].ScaleFactor=1E-3 + + +Use EncTable 20 as Frame counter +EncTable[20].type = 1 //32 Bit uint +EncTable[20].pEnc = Sys.Udata[0].a +EncTable[20].index1 = 0 +EncTable[20].index2 = 0 +EncTable[20].index3 = 0 +EncTable[20].index4 = 0 +EncTable[20].index5 = 0 +EncTable[20].index5 = 0 +EncTable[20].ScaleFactor=1E-3 + + +2.1 trigger zu spät +1.9 trigger zu früh diff --git a/python/MXMotion.py b/python/MXMotion.py index 9d96634..26679db 100644 --- a/python/MXMotion.py +++ b/python/MXMotion.py @@ -7,6 +7,8 @@ # *-----------------------------------------------------------------------* ''' Coord[1].Q[0] : sync points when using setup_sync(mode=2) + -3: when armed (at start position) + -2: triggerSync waiting for start trigger 0: after setup_sync(mode=2) call idx: index of position during run -1: pvt motion is finished @@ -44,7 +46,7 @@ class MotionBase: self.meta={'srv_per':ServoPeriod,'pt2pt_time':40,'sync_flag':0,'sync_mode':2} self.meta.update(kwargs) - def setup_sync(self, crdId=1, prgId=2,verbose=False, timeOfs=0.): + def setup_sync(self, crdId=1, prgId=2,verbose=False, timeOfs=0.,timeCor=0.): '''setup the timing synchronization for the motion program kwargs: sync_mode : default=2 @@ -88,41 +90,43 @@ class MotionBase: flag0='Coord[{crdId}].Q[10]'.format(crdId=crdId) if sync_flag&1 else 'Gate3[1].Chan[0].UserFlag' flag1='Coord[{crdId}].Q[11]'.format(crdId=crdId) if sync_flag&2 else 'Gate3[1].Chan[1].UserFlag' if sync_mode==1: - prg = ''' - Coord[{crdId}].Q[0]=-2 - Coord[{crdId}].TimeBaseSlew=1 //1E-4 is default - Coord[{crdId}].DesTimeBase=0 - while({flag0}==0){{}} - Coord[{crdId}].Q[0]=-1 - Gather.Enable=2 - while({flag1}==0){{}} - Coord[1].DesTimeBase=Sys.ServoPeriod - '''.format(crdId=crdId, flag0=flag0, flag1=flag1) + prg = f'\n{flag0}=0\n' if sync_flag&1 else '' + prg += f''' +Coord[{crdId}].Q[0]=-2 motion program started and armed +Coord[{crdId}].TimeBaseSlew=1 //1E-4 is default +Coord[{crdId}].DesTimeBase=0 +while({flag0}==0){{}} +Coord[{crdId}].Q[0]=-1 +Gather.Enable=2 +while({flag1}==0){{}} +Coord[1].DesTimeBase=Sys.ServoPeriod +''' else: - prg = ''' - //Gather.Enable=2 is done in the sync program - Coord[1].TimeBaseSlew=1 //1E-4 is default - Coord[1].DesTimeBase=0 - //Coord[1].Q[0]=-1 is done in the sync program - '''.format(crdId=crdId, flag0=flag0, flag1=flag1) + prg = f''' +//Gather.Enable=2 is done in the triggerSync program +Coord[1].TimeBaseSlew=1 //1E-4 is default +Coord[1].DesTimeBase=0 +Coord[1].Q[0]=-3 //motion program started and waits. Arm(-2) is done in triggerSync program +''' self.sync_prg = prg #download and start triggerSync code comm=self.comm if comm is None: return - arg=0 #argument to pass to triggerSync program - if sync_mode==2:arg+=1 #synchronize - arg+=sync_flag*2 #simulated or real triggers - if verbose: arg+=8 - if sync_mode==2 or arg&4: + mode=0 #mode to pass to triggerSync program + if sync_mode==2:mode+=1 #synchronize + mode+=sync_flag*2 #simulated or real triggers + if verbose: mode+=8 + if sync_mode==2 or mode&4: sftp = comm.sftp dst = '/tmp/triggerSync' src = os.path.abspath(os.path.join(os.path.dirname(__file__), 'triggerSync')) sftp.put(src, dst) sftp.chmod(dst, 0o755) cmd = 'LD_LIBRARY_PATH=/opt/ppmac/libppmac/ ' + dst - cmd+=' %g %g %d'%(pt2pt_time,timeOfs,arg) + #cmd+=' %d %g %g %g'%(mode,pt2pt_time,timeOfs,timeCor) + cmd+=' %d %g %g'%(mode,pt2pt_time+timeCor,timeOfs) self.cmdSync = cmd print ('starting '+cmd) self.syncShell=comm.shell_channel(cmd) diff --git a/python/shapepath.py b/python/shapepath.py index fb97d59..9fd0563 100755 --- a/python/shapepath.py +++ b/python/shapepath.py @@ -17,63 +17,36 @@ verbose bits: 0x20 plot pvt trajectory (before motion) 0x40 print sync details -Gather motor order -idx 0 1 2 3 4 5 6 -OLD Motor[3].ActPos Motor[2].ActPos Motor[1].ActPos Motor[3].DesPos Motor[2].DesPos Motor[1].DesPos Gate3[1].Chan[1].UserFlag + if mode&1: + self.plot_trajectory() + + if mode&2: + self.plot_pos_error() + + if mode&4: + self.plot_bode(xy=(3,1),mode=31,db=True) # FX + self.plot_bode(xy=(2,0),mode=31,db=True) # FY + + if mode&8: + self.plot_trigger_jitter() + + +Gather motor order +idx 0 1 2 3 4 NEW Motor[1].ActPos Motor[2].ActPos Motor[1].DesPos Motor[2].DesPos Gate3[1].Chan[1].UserFlag NEW y.ActPos x.ActPos y.DesPos x.DesPos Gate3[1].Chan[1].UserFlag -OLD->NEW -0->none -1->1 -2->0 -3->none -4->3 -5->2 Mot 1: Stage Y Parker MX80L D11 25mm one pole cycle = 13mm = 2048 phase_step Mot 2: Stage X Parker MX80L D11 25mm one pole cycle = 13mm = 2048 phase_step Mot 3: Rotation stage LS Mecapion MDM-DC06DNC0H 32 poles = 1 rev = 16*2048=32768 phase_step Mot 4: Stage X Stada Stepper 670mA 200 poles 1 rev = 100*2048 phase_step (2 stepper motor) Mot 5: Stage Z Stada Stepper 670mA 200 poles 1 rev = 100*2048 phase_step (2 stepper motor) -Enc 6: Interferometer Y -Enc 7: Interferometer X - - -tunnel PowerBrick port locally ------------------------------- -Port 22 on PowerBrick is the ssh server port -Port 2332 on PowerBrick is the gather port of gather_server - -PPMAC=SAR-CPPM-EXPMX1 - -rsync -vai ~/Documents/prj/SwissFEL/PBTools/pbtools/gather/gather_server root@$PPMAC:/tmp/ -ssh root@$PPMAC -LD_LIBRARY_PATH=/opt/ppmac/libppmac/ /tmp/gather_server - - - -rsync -vai ~/Documents/prj/SwissFEL/PBTools/pbtools/gather/gather_server root@$PPMAC:/tmp - -ssh -L 10001:localhost:22 root@$PPMAC 'uname -a' -ssh -L 10002:localhost:2332 root@$PPMAC 'uname -a' --> this tunnels port 22 and 2332 of $PPMAC to 10001 and 10002 of localhost -('uname -a' is just to execute a command and return, because the port remains open) - -Tests: -nc localhost 10001 -nc localhost 10002 - -list close ssh tunnel ---------------------- -lsof -i -n | egrep 'ssh' -lsof -i -n | grep '127.0.0.1:1000' - - +s.a. https://docs.google.com/document/d/1soSuCZYyfGf_ntcgG_Y1_WeGuo_687OuFn0s4sMj1uY/ ''' + from __future__ import print_function -#from __future__ import absolute_import,division,generators,nested_scopes,print_function,unicode_literals,with_statement try: raw_input;input=raw_input except NameError: pass @@ -305,7 +278,7 @@ class DebugPlot: hl = ax.plot(pts[:, 0], pts[:, 1], 'r.', label='points') hl += ax.plot(pts[:, 0], pts[:, 1], 'y--', label='direct') hl += ax.plot(rec[:, 3], rec[:, 2], 'b-', label='DesPos') # desired path - hl += ax.plot(rec[:, 1], rec[:, 0], 'g-', label='ActPos') # actual path + hl += ax.plot(rec[:, 1], rec[:, 0], 'g.', label='ActPos') # actual path try: pvt = self.pvt except AttributeError: @@ -333,6 +306,23 @@ class DebugPlot: ax2.legend(loc='best') plt.show(block=False) + def plot_dbg(self): + rec = self.rec # yA,xA,yD,xD,trig + ts=self.meta['srv_per']*self.meta['acq_per'] + fig = plt.figure('debug plot') + ax = fig.add_subplot(1, 1, 1) + t=np.arange(rec.shape[0],dtype=np.uint32) + #address=("Motor[1].ActPos", "Motor[2].ActPos", "Motor[1].DesPos", "Motor[2].DesPos", "Gate3[1].Chan[1].UserFlag","EncTable[20].DeltaPos") + + hl = [] + rec[0, 5]=rec[0, 6]=0 + hl += ax.plot(t, rec[:, 6], 'rx', label='EncTable[20].DeltaPos') + hl += ax.plot(t, rec[:, 5], 'b-', label='Coord[1].TimeBase') + hl += ax.plot(t, rec[:, 4], 'g.', label='Gate3[1].Chan[1].UserFlag') + ax.xaxis.set_label_text('ms (timebase: %g ms per data point)' % ts) + ax.legend(loc='best') + plt.show(block=False) + def plot_gather(self,mode=255): try: meta=self.meta @@ -355,6 +345,10 @@ class DebugPlot: if mode&8: self.plot_trigger_jitter() + #self.plot_dbg() + + + plt.show(block=False) def plot_bode(self,xy=(0,1),mode=25,db=True): @@ -445,8 +439,8 @@ class DebugPlot: plt.show(block=False) def load_npz(self,fn='/tmp/shapepath.npz'): - fh=np.load(fn) - for k,v in fh.iteritems(): + fh=np.load(fn,allow_pickle=True) + for k,v in fh.items(): setattr(self,k,v) self.meta=self.meta.item() @@ -571,15 +565,6 @@ class ShapePath(MotionBase): for x in np.arange(mult)*shift: stack.append(pts+(x,y)) pts=np.vstack(stack) - - - #xx,yy=np.meshgrid(range(w), range(h)) - #pts=np.array([xx.reshape(-1),yy.reshape(-1)],dtype=np.float).transpose()*pitch - #if xy: - #else: - - # smlpitch - #pts+=ofs self.points=pts @@ -654,36 +639,26 @@ class ShapePath(MotionBase): comm=self.comm gt=self.gather gt.set_phasemode(False) - if self.meta['sync_flag']&2: + meta=self.meta + if meta['sync_flag']&2: address=("Motor[1].ActPos","Motor[2].ActPos","Motor[1].DesPos","Motor[2].DesPos","Coord[1].Q[11]") else: address=("Motor[1].ActPos","Motor[2].ActPos","Motor[1].DesPos","Motor[2].DesPos","Gate3[1].Chan[1].UserFlag") - + #address=("Motor[1].ActPos","Motor[2].ActPos","Motor[1].DesPos","Motor[2].DesPos","Gate3[1].Chan[1].UserFlag","EncTable[20].PrevEnc") + #address=("Motor[1].ActPos", "Motor[2].ActPos", "Motor[1].DesPos", "Motor[2].DesPos", "Gate3[1].Chan[1].UserFlag","Coord[1].TimeBase","EncTable[20].DeltaPos") gtMaxLn=gt.set_address(*address) if acq_per is None: ovhdTime=100 - acq_per=int(np.ceil((self.meta['pt2pt_time']*self.points.shape[0]+ovhdTime)/(gtMaxLn*self.meta['srv_per']))) + acq_per=int(np.ceil((meta['pt2pt_time']*self.points.shape[0]+ovhdTime)/(gtMaxLn*meta['srv_per']))) gt.set_property(MaxSamples=1000000, Period=acq_per) #gt.set_property(Period=acq_per) - self.meta.update({'acq_per':acq_per,'address':address}) + meta.update({'acq_per':acq_per,'address':address}) def setup_coord_trf(self,fx='X',fy='Y',cz='0'): # FY:1, FX:2, ROT_Y:3, CX:4, CZ:5, if self.comm is None: return comm = self.comm gpascii = comm.gpascii - prg = '''&1a -#1-> Y -#2-> X -#3-> A -&0#4->0 -&0#5->0 -&0#6->0 -&0#7->0 -#1..3j/ -//#8->0 -//#1..8j/ -''' prg=f'''&1a &1#3->0 &1#4->0 @@ -699,7 +674,6 @@ class ShapePath(MotionBase): #5->{cz} #1,2,5j/ ''' - gpascii.send_block(prg) def setup_motion(self,prgId=2,fnPrg=None,mode=0,**kwargs): @@ -719,6 +693,22 @@ class ShapePath(MotionBase): numPad : number of padding points to reduce aliasing (default=16) ''' prg=['close all buffers','open prog %d'%(prgId)] + + #Use EncTable 20 as Frame counter + #dont use Coord[1].DesTimeBase as the time base but use the virtual encoder: + # Coord[1].pDesTimeBase=Coord[1].DesTimeBase.a #(default) + prg.append('''\ +EncTable[20].type = 1 //32 Bit uint +EncTable[20].pEnc = Sys.Udata[0].a +EncTable[20].index1 = 0 +EncTable[20].index2 = 0 +EncTable[20].index3 = 0 +EncTable[20].index4 = 0 +EncTable[20].index5 = 0 +EncTable[20].index5 = 0 +EncTable[20].ScaleFactor=1E-3 +//Coord[1].pDesTimeBase=EncTable[20].DeltaPos.a +''') verb=self.verbose comm=self.comm if comm is not None: @@ -768,7 +758,8 @@ class ShapePath(MotionBase): plt.show(block=False) pv[1:-1, (2, 3)]*=CoordFeedTime #scaling for Deltatau - prg.append(' linear abs') + prg.append('linear abs') + #prg.append('X%g Y%g' % tuple(pv[0, (0,1)]-(120,120))) prg.append('X%g Y%g' % tuple(pv[0, (0,1)])) prg.append('dwell 10') try: prg.extend(self.sync_prg.split('\n')) @@ -781,6 +772,10 @@ class ShapePath(MotionBase): prg.append(' pvt%g abs'%pt2pt_time) #100ms to next position for idx in range(1,pv.shape[0]): prg.append('X%g:%g Y%g:%g'%tuple(pv[idx,(0,2,1,3)])) + #if idx%78==10: #sync data all 256 points + # prg.append('Coord[1].Q[12]=Sys.ServoCount') + # #prg.append(f'Coord[1].Q[13]={idx}') + # prg.append(f'Coord[1].Q[13]=Motor[1].DesPos') prg.append('X%g Y%g' % tuple(pv[-1, (0,1)])) if cnt>1: prg.append('dwell 10') @@ -813,6 +808,7 @@ class ShapePath(MotionBase): def gather_upload(self,fnRec=None): gt=self.gather + comm=self.comm gt.wait_stopped(verbose=True) self.rec=rec=gt.upload() @@ -824,23 +820,24 @@ class ShapePath(MotionBase): del self.syncShell pts=self.points - ofsy=-rec[0,2]+pts[0,1] - ofsx=-rec[0,3]+pts[0,0] - rec[:,(1,3)]+=ofsx - rec[:,(0,2)]+=ofsy + + ofsy=comm.gpascii.get_variable("Motor[1].HomePos", type_=float) + ofsx=comm.gpascii.get_variable("Motor[2].HomePos", type_=float) + rec[:,(0,2)]-=ofsy + rec[:,(1,3)]-=ofsx if fnRec: np.savez_compressed(fnRec, rec=rec, pts=pts, meta=self.meta) if __name__=='__main__': - #import logging - #logger = logging.getLogger(__name__) - #logger = logging.getLogger('pbtools.misc.pp_comm') - #logger.setLevel(logging.DEBUG) - #logging.basicConfig(format=('%(asctime)s %(name)-12s ' - # '%(levelname)-8s %(message)s'), - # datefmt='%m-%d %H:%M', - # ) + import logging + _log=logging.getLogger(__name__) + logging.getLogger('pbtools.misc.pp_comm').setLevel(logging.INFO) + logging.getLogger('paramiko').setLevel(logging.WARNING) + logging.getLogger('matplotlib').setLevel(logging.INFO) + #https://docs.python.org/3/library/logging.html#logging.Formatter add %(name)s to identify the logger + logging.basicConfig(level=logging.DEBUG, format='%(levelname)s:%(module)s:%(lineno)d:%(funcName)s:%(message)s ') + import argparse def unique_filename(fnBase): i = 0; @@ -854,20 +851,6 @@ if __name__=='__main__': def run_test(args): - #dp=DebugPlot();dp.plot_gather();return - #import socket - #s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # create an INET, STREAMing socket - #s.settimeout(.1) - #try: - # port=22 #ssh port - # s.connect((args.host, port)) # try to connect to port - # s.close() - #except (socket.error, socket.gaierror) as e: - # comm=gather=None - #else: - # comm = PPComm(host=args.host) - # gather = Gather(comm) - hpp=args.host.split(':') param={'host':hpp[0]} if len(hpp)>1: @@ -885,7 +868,7 @@ if __name__=='__main__': #sp = ShapePath(comm, gather, args.verbose,sync_mode=0,pt2pt_time=10) #simulated start and frame trigger no sync - sp = ShapePath(comm, gather, args.verbose,sync_mode=1,sync_flag=3) + #sp = ShapePath(comm, gather, args.verbose,sync_mode=1,sync_flag=3) #simulated start and frame trigger with sync #sp = ShapePath(comm, gather, args.verbose,sync_mode=2,sync_flag=3) @@ -894,7 +877,7 @@ if __name__=='__main__': #sp = ShapePath(comm, gather, args.verbose,sync_mode=1,sync_flag=1) #simulated start real frame trigger with sync - #sp = ShapePath(comm, gather, args.verbose,sync_mode=2,sync_flag=1) + sp = ShapePath(comm, gather, args.verbose,sync_mode=2,sync_flag=1) fn='/tmp/shapepath' #fn =unique_filename('ShapePathAnalyser/records/19_01_24/spiral') @@ -927,18 +910,36 @@ if __name__=='__main__': #sp.gen_spiral_points(rStart=100,rInc=130,numSeg=4,numCir=2, ofs=(0, 0)) #sp.gen_grid_points(w=20,h=20,pitch=100,rnd=0,ofs=(0,+2000));sp.sort_points(False); #sp.gen_grid_points(w=5,h=10,pitch=100,rnd=0,ofs=(0,+2000));sp.sort_points(False,10); - sp.gen_grid_points(w=125,h=125,pitch=3,rnd=0,ofs=(0,+2000));sp.sort_points(False,125); sp.meta['pt2pt_time']=5 - + + #sp.gen_grid_points(w=50,h=50,pitch=120,rnd=0,ofs=(0,+2000));sp.sort_points(False,50); sp.meta['pt2pt_time']=10 + #sp.gen_grid_points(w=16,h=16,pitch=120,rnd=0,ofs=(0,+2000));sp.sort_points(False,16); sp.meta['pt2pt_time']=10 + #12.5x12.5 + sp.gen_grid_points(w=78,h=78,pitch=120,rnd=0,ofs=(-10000,-12000));sp.sort_points(False,78); sp.meta['pt2pt_time']=10 + #23.0x23.0 -> only 3 data points from shot to shot: 6,9,12,14,17,20... + #sp.gen_grid_points(w=162,h=162,pitch=120,rnd=0,ofs=(-10000,-12000));sp.sort_points(False,162); sp.meta['pt2pt_time']=10 + #sp.gen_grid_points(w=1,h=10,pitch=100,rnd=0,ofs=(0,0)) #sp.gen_spiral_points(rStart=100,rInc=20,numSeg=8,numCir=32, ofs=(0, 0)) #sp.gen_spiral_points(rStart=100,rInc=10,numSeg=2,numCir=32, phase=45, ofs=(0, 0)) #sp.gen_spiral_points(rStart=100,rInc=10,numSeg=4,numCir=32, ofs=(0, 0)) #sp.gen_closed_shifted() - gtMaxLn=116508;ovhdTime=100 + gtMaxLn=int(sp.comm.gpascii.get_variable('Gather.MaxLines')) # 116508 + if gtMaxLn==0: + sp.setup_gather(acq_per=1) + gtMaxLn=int(sp.comm.gpascii.get_variable('Gather.MaxLines')) # 116508 + + ovhdTime=100 acq_per=int(np.ceil((sp.meta['pt2pt_time']*sp.points.shape[0]+ovhdTime)/(gtMaxLn*sp.meta['srv_per']))) + if args.verbose&0x01: + print(f'''\ +Gather.MaxLines:{gtMaxLn} +Gather.Period: {acq_per} +meta: {sp.meta} +Filename: {fn}.[prg|npz] +''') sp.setup_gather(acq_per=acq_per) - sp.setup_sync(verbose=args.verbose&32,timeOfs=0.05) + sp.setup_sync(verbose=args.verbose&0x40,timeOfs=0.03,timeCor=0.0005) sp.setup_coord_trf() # reset to shape path system #sp.meta['pt2pt_time']=10 #put between setup_sync and setup_motion to have more motion points than FEL syncs sp.setup_motion(fnPrg=fn+'.prg', mode=3, scale=1.,dwell=10) @@ -946,8 +947,11 @@ if __name__=='__main__': #sp.setup_motion(fnPrg=fn + '.prg', mode=1, scale=0,dwell=10) sp.homing() #homing if needed sp.run() #start motion program + print('wait_armed') sp.wait_armed() # wait until motors are at first position + print('trigger') sp.trigger(0.5) #send a start trigger (if needed) ater given time + print('progress..') if not comm is None: while True: p=sp.progress() @@ -955,55 +959,31 @@ if __name__=='__main__': print('progress %d/%d'%(p,sp.points.shape[0]));time.sleep(.1) sp.gather_upload(fnRec=fn+'.npz') dp=DebugPlot(sp);dp.plot_gather(mode=11) - print('done') plt.show(block=False) input('press return') - - #sp.plot_points(sp.points);plt.show() - - - - #>>>run gather and plot trajectory<<< - #return - - - from optparse import OptionParser, IndentedHelpFormatter - class MyFormatter(IndentedHelpFormatter): - 'helper class for formating the OptionParser' - - def __init__(self): - IndentedHelpFormatter.__init__(self) - - def format_epilog(self, epilog): - if epilog: - return epilog - else: - return "" - def parse_args(): 'main command line interpreter function' - #usage: gpasciiCommunicator.py --host=PPMACZT84 myPowerBRICK.cfg (h, t)=os.path.split(sys.argv[0]);cmd='\n '+(t if len(h)>3 else sys.argv[0])+' ' exampleCmd=('-v15', - '--host=localhost:10001:10002' - ) - epilog=__doc__+''' -Examples:'''+''.join(map(lambda s:cmd+s, exampleCmd))+'\n ' - - fmt=MyFormatter() - parser=OptionParser(epilog=epilog, formatter=fmt) - - parser.add_option('-v', '--verbose', type="int", dest='verbose', help='verbosity bits (see below)', default=0) - parser.add_option('--host', help='hostname', default='SAR-CPPM-EXPMX1') + '--host=localhost:10001:10002 -v 0x5d', + '--host=localhost:10001:10002 -v 0x59' + ) + epilog=__doc__+'\nExamples:'+''.join(map(lambda s:cmd+s, exampleCmd))+'\n ' + parser=argparse.ArgumentParser(epilog=epilog, formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument("-m", "--mode", type=lambda x:int(x, 0), help="mode (see bitmasks) default=0x%(default)x", default=0xff) + parser.add_argument('-v', '--verbose', type=lambda x:int(x, 0), dest='verbose', help='verbosity bits (see below) default=0x%(default)x', default=0x00) + parser.add_argument('--host', help='hostname', default='SAR-CPPM-EXPMX1') #parser.add_option('--host', help='hostname', default='localhost:10001:10002') - #parser.add_option('--host', help='hostname') - (args, other)=parser.parse_args() - args.other=other + args=parser.parse_args() + _log.info('Arguments:{}'.format(args.__dict__)) run_test(args) #------------------ Main Code ---------------------------------- + + #dp=DebugPlot('/tmp/shapepath.npz');dp.plot_gather(mode=11);plt.show() + #exit(0) #ssh_test() ret=parse_args() exit(ret) diff --git a/src/triggerSync/Makefile b/src/triggerSync/Makefile index 4494a19..b8e35fe 100644 --- a/src/triggerSync/Makefile +++ b/src/triggerSync/Makefile @@ -1,12 +1,13 @@ #HOST=MOTTEST-CPPM-CRM0573 HOST=SAR-CPPM-EXPMX1 -XENOMAI_INC_DIR=/opt/powerpc-465-rootfs/usr/local/xenomai-2.6.2.1/include -XENOMAI_LIB_DIR=/opt/powerpc-465-rootfs/usr/local/xenomai-2.6.2.1/lib +#XENOMAI_INC_DIR=/opt/powerpc-465-rootfs/usr/local/xenomai-2.6.2.1/include +#XENOMAI_LIB_DIR=/opt/powerpc-465-rootfs/usr/local/xenomai-2.6.2.1/lib + +XENOMAI_INC_DIR=/tmp/powerpc-465-rootfs/usr/local/xenomai-2.6.2.1/include +XENOMAI_LIB_DIR=/tmp/powerpc-465-rootfs/usr/local/xenomai-2.6.2.1/lib INC=-I/opt/eldk-4.2/PPMAC_rootfs-7-wheezy/opt/ppmac/libppmac -I/opt/eldk-4.2/PPMAC_rootfs-7-wheezy/opt/ppmac/rtpmac -I$(XENOMAI_INC_DIR) - - LIB=-L/opt/eldk-4.2/PPMAC_rootfs-7-wheezy/opt/ppmac/libppmac -lppmac -L/opt/eldk-4.2/PPMAC_rootfs-7-wheezy/usr/local/xenomai-2.6.2.1/lib -lnative -lxenomai -lpthread_rt -lpthread -lrt -ldl CC=/opt/eldk-4.2/usr/bin/ppc_4xxFP-g++ @@ -14,8 +15,15 @@ LD=$(CC) all: triggerSync +triggerSync.o: $(XENOMAI_INC_DIR) + +$(XENOMAI_INC_DIR): + mkdir -p /tmp/powerpc-465-rootfs/usr/local/xenomai-2.6.2.1/ + rsync -vai root@$(HOST):/usr/local/xenomai-2.6.2.1/ /tmp/powerpc-465-rootfs/usr/local/xenomai-2.6.2.1/ + + %.o: %.c - $(CC) -g $(INC) -c $^ -o $@ + $(CC) -g $(INC) -c $< -o $@ triggerSync: triggerSync.o $(LD) -g $(LIB) $^ -o $@ diff --git a/src/triggerSync/triggerSync b/src/triggerSync/triggerSync index 1fff135..0eb681f 100755 Binary files a/src/triggerSync/triggerSync and b/src/triggerSync/triggerSync differ diff --git a/src/triggerSync/triggerSync.c b/src/triggerSync/triggerSync.c index 097b626..9944c36 100644 --- a/src/triggerSync/triggerSync.c +++ b/src/triggerSync/triggerSync.c @@ -33,11 +33,23 @@ extern struct SHM *pshm; static char mode=0; static float mtPt2Pt=40.f; //motion point to point time -static float timeOfs=0.f; //time ofset +static float timeOfs=0.f; //time ofset (start time adjustment) +static float timeCor=0.f; //time correction (frame to frame time adjustment) + #define CLOCK_RES 1e-9 //Clock resolution is 1 ns by default #define SIMFLAG0 (pshm->Coord[1].Q[10]) #define SIMFLAG1 (pshm->Coord[1].Q[11]) + +//EncTable[20].pEnc= Coord[1].Q[12].a does not work +//EncTable[20].pEnc= Sys.Udata[0].a works uint32 +//EncTable[20].pEnc= Sys.Idata[0].a works int32 +//EncTable[20].pEnc= Sys.Fdata[0].a works float32 +//EncTable[20].pEnc= Sys.Ddata[0].a works float64 +//#define ENCVAL (*((double *)pushm+0)) +#define ENCVAL (*((unsigned int *)pushm+0)) + + //#define SIMFLAG0 (pshm->P[10]) //#define SIMFLAG1 (pshm->P[11]) //Power PMAC Software Reference Manual.pdf Gate3[i].Chan[j].Status -> page 919 UserFlag @@ -76,6 +88,14 @@ void trigsync_func(void *arg) printf("ending trigsync_func because Gather.Enable==0\n"); return; } + + //unsigned int lastQ12=0; //Q12 value for further sync + double mxActPos,mxDesPos,mxHomePos=pshm->Motor[2].HomePos; + double myActPos,myDesPos,myHomePos=pshm->Motor[1].HomePos; + + printf("Wait motion program arrived at start position...\n"); + while(pshm->Coord[1].Q[0]!=-3) + rt_task_wait_period(NULL); pshm->Coord[1].Q[0]=-2; srvPer=pshm->ServoPeriod; @@ -93,29 +113,30 @@ void trigsync_func(void *arg) } printf("Flag 0: %.5f ms\n", (rt_timer_read() - rtStart)/1E6); - pshm->Gather.Enable=2; //start gathering data - pshm->Coord[1].Q[0]=-1; if(mode&4) { + while(SIMFLAG1) + rt_task_wait_period(NULL); while(!SIMFLAG1) rt_task_wait_period(NULL); } else { + while(FLAG1) + rt_task_wait_period(NULL); while(!FLAG1) rt_task_wait_period(NULL); } -//puts("waitFlag1"); -//gate3_1->Chan[1].Status f057f77f -//gate3_1->Chan[1].Status f057ff7f -//printf("gate3_1->Chan[1].Status %x\n",gate3_1->Chan[1].Status); + //FEL shot arrived FLAG1 0->1: first frame trigger before first cristall + pshm->Gather.Enable=2; //start gathering data + pshm->Coord[1].Q[0]=-1; + ENCVAL=0; printf("Flag 1: %.5f ms\n", (rt_timer_read() - rtStart)/1E6); rtStart=rtLast=rt_timer_read(); scStart=scLast=pshm->ServoCount; mtAct=0.f; pshm->Coord[1].Q[0]=0; - srvPer=0.2f; //pshm->Coord[1].DesTimeBase=srvPer; //start motion at default speed pshm->Coord[1].DesTimeBase=srvPer*(mtPt2Pt+timeOfs)/mtPt2Pt; //start motion at default speed if(mode&8) @@ -134,24 +155,53 @@ void trigsync_func(void *arg) else { while(FLAG1) + { rt_task_wait_period(NULL); + ENCVAL=( (i-1)*mtPt2Pt + (pshm->ServoCount-scLast)*srvPer )*1000; + } while(!FLAG1) + { rt_task_wait_period(NULL); + ENCVAL=( (i-1)*mtPt2Pt + (pshm->ServoCount-scLast)*srvPer )*1000; + } } - //FEL shot arrived + //FEL shot arrived FLAG1 0->1 + //ENCVAL+=mtPt2Pt*1000; //ENCVAL in us + ENCVAL=i*mtPt2Pt*1000; //ENCVAL in us rtCur = rt_timer_read(); scCur=pshm->ServoCount; + //if (lastQ12!=(unsigned int)pshm->Coord[1].Q[12]) + //{ + // //'Coord[1].Q[12]=Sys.ServoCount' + // //'Coord[1].Q[13]={idxOfPoint}' + // //type of pshm->Coord[1].Q[12] is double + // lastQ12=(unsigned int)pshm->Coord[1].Q[12]; //saved ServoCount in program code + + // //mxActPos=pshm->Motor[2].ActPos;mxDesPos=pshm->Motor[2].DesPos; + // //myActPos=pshm->Motor[1].ActPos;myDesPos=pshm->Motor[1].DesPos; + + // //printf("*** SYNC *** Trigger count:%d, ProgIdx:%d, ServoCount diff:%d-%d=%d", i, (unsigned int)pshm->Coord[1].Q[13], lastQ12,scCur, lastQ12-scCur); + // printf("*** SYNC *** Trigger count:%d, myDesPos:%.2f, ServoCount diff:%d-%d=%d\n", i, pshm->Coord[1].Q[13]-myHomePos, lastQ12,scCur, lastQ12-scCur); + // //printf(" X,Y ActPos:(%.5g %.5g) DesPos:(%.5g %.5g)\n", mxActPos-mxHomePos, myActPos-myHomePos, mxDesPos-mxHomePos, myDesPos-myHomePos); + //} + rtDiff=rtCur-rtLast; scDiff=scCur-scLast; - mtAct+=scDiff*srvPer; + mtAct+=scDiff*srvPer+timeCor; mtDes=i*mtPt2Pt+timeOfs; srvPer=(mtPt2Pt+mtDes-mtAct)/scDiff; + //srvPer=pshm->ServoPeriod; //default speed pshm->Coord[1].DesTimeBase=srvPer; pshm->Coord[1].Q[0]++; if(mode&8) - printf("Trigger count:%d, rtDiff:%.3fms scDiff:%d mtAct:%.3f mtDes:%.3f srvPer:%.6f\n", i, rtDiff/1E6,scDiff, mtAct,mtDes,srvPer); + { + mxActPos=pshm->Motor[2].ActPos;mxDesPos=pshm->Motor[2].DesPos; + myActPos=pshm->Motor[1].ActPos;myDesPos=pshm->Motor[1].DesPos; + printf(" X,Y ActPos:(%.5g %.5g) DesPos:(%.5g %.5g) ", mxActPos-mxHomePos, myActPos-myHomePos, mxDesPos-mxHomePos, myDesPos-myHomePos); + printf("Trigger count:%d, rtDiff:%.3fms scDiff:%d mtAct:%.3f mtDes:%.3f srvPer:%.6f ENCVAL:%u \n", i, rtDiff/1E6,scDiff, mtAct,mtDes,srvPer,ENCVAL); + } rtLast=rtCur; scLast=scCur; } @@ -163,12 +213,13 @@ void trigsim_func(void *arg) RT_TASK *curtask; RT_TASK_INFO curtaskinfo; int iret = 0; + int loopPeriod=1e7;//Expressed in ticks (this is the default task period) curtask = rt_task_self(); rt_task_inquire(curtask, &curtaskinfo); //Print the info - //printf("Starting task %s with period of %f ms ....\n", curtaskinfo.name,10*1E6/1E6); + printf("Starting task %s with period of %f ms ....\n", curtaskinfo.name,loopPeriod/1E6); //Make the task periodic with a specified loop period - //rt_task_set_periodic(NULL, TM_NOW, 10*1E6); + //rt_task_set_periodic(NULL, TM_NOW, loopPeriod); //not critical here because not polling but rt_task_sleep_until ... printf("Starting task %s \n", curtaskinfo.name); int i,j=0; @@ -180,9 +231,8 @@ void trigsim_func(void *arg) for(i=0,rtSlice=rtStart;;i++) { - rtSlice=rtStart+i*40*1E6; // a slice is 40 ms - //rtSlice=rtStart+i*40.2*1E6; // a slice is 40 ms - //rtSlice+=(rand()%(int)(1*1E6)); //0.1ms jitter + rtSlice=rtStart+i*mtPt2Pt*1E6; // a slice is mtPt2Pt ms + //rtSlice+=(rand()%(int)(1*1E6)); //0.1ms jitter to test sync rt_task_sleep_until(rtSlice); //in ns if(mode&4) { @@ -275,6 +325,11 @@ mode:\n\ bit2:4: simulate frame trigger\n\ bit3:8: verbose\n\ \n\ +pt2ptTime: point to point time in ms (default=10, float value)\n\ +timeOfs: once added time offset in ms (default=0, float value)\n\ +scl: scale factor (so far unused, default=1, float value)\n\ +\n\ +\n\ simulate start trigger:\n\ set pshm->Coord[1].Q[10]=1 to simulate a Jungfrau aquire start\n\ \n\ @@ -297,7 +352,7 @@ Coord[1].Q[0]= 0 : got frame trigger 0\n\ Coord[1].Q[0] is incremented at each trigger\n\ sync task ends when Gather.Enable==0\n\ "; - printf("usage:\n%s pt2ptTime timeOfs mode\n",cmd); + printf("usage:\n%s mode pt2ptTime timeOfs(default=0) scl(default=1)\n",cmd); puts(s); return -1; } @@ -308,22 +363,21 @@ int main(int argc, char *argv[]) int initialized=0; int i; char *s; - if(argc!=4) - return usage(argv[0]); - mtPt2Pt=strtof(argv[1], &s); - if (argv[1]==s) - return usage(argv[0]); - timeOfs=strtof(argv[2], &s); - if (argv[2]==s) - return usage(argv[0]); - mode=(int)strtol(argv[3], &s, 10); - if (argv[3]==s) + if(argc<2) return usage(argv[0]); + mode=(int)strtol(argv[1], &s, 10); + if (argc>2) + mtPt2Pt=strtof(argv[2], &s); + if (argc>3) + timeOfs=strtof(argv[3], &s); + if (argc>4) + timeCor=strtof(argv[4], &s); puts(argv[0]); puts(argv[1]); - puts(argv[2]); - puts(argv[3]); - printf("mtPt2Pt:%g timeOfs:%g mode:%d\n",mtPt2Pt,timeOfs,mode); + //puts(argv[2]); + //puts(argv[3]); + //puts(argv[4]); + printf("mode:%d mtPt2Pt:%3.8gms timeOfs:%3.8gms timeCor:%3.8gms\n",mode,mtPt2Pt,timeOfs,timeCor); if ((err = InitLibrary()) != 0) { abort(); }