marhw.cpp

Go to the documentation of this file.
00001 /***********************************************************************
00002  *
00003  * scan345: marhw.c
00004  *
00005  * Copyright by:        Dr. Claudio Klein
00006  *                      X-ray Research GmbH, Hamburg
00007  *
00008  * Version:     2.2
00009  * Date:        15/06/2000
00010  *
00011  * History:
00012  *
00013  * Date         Version         Description
00014  * ---------------------------------------------------------------------
00015  * 15/06/00     2.2             Added feature COMMAND SCAN ADD x ERASE y
00016  *                              Get firmware params at startup (USE SPY)
00017  *
00018  *
00019  ***********************************************************************/
00020 
00021 #include        <stdio.h>
00022 #include        <time.h>
00023 #include        <math.h>
00024 #include        <string.h>
00025 #include        <errno.h>
00026 #include        <signal.h>
00027 #include        <stdlib.h>
00028 #include        <unistd.h>
00029 
00030 #include        "esd.h"
00031 #include        "esd_error.h"
00032 #include        "marcmd.h"
00033 #include        "mar_command.h"
00034 #include        "marglobals.h"
00035 #include        "twopower.h"
00036 #include        "config.h"
00037 
00038 #include "marhw.h"
00039 
00040 #define min0(a,b)       if ( b < a ) a = b
00041 #define max0(a,b)       if ( b > a ) a = b
00042 #define MAX_DOSE        2000
00043 /*
00044  * Global variables 
00045  */
00046 char                    start_time[32];
00047 char                    motor_op                = 0;
00048 char                    skip_op                 = 0;
00049 char                    keep_image              = 1;
00050 int                     mar_error               = 0;
00051 int                     target_steps            = 0;
00052 int                     ict1                    = 0;
00053 int                     ict2                    = 0;
00054 int                     adc1                    = 0;
00055 int                     adc2                    = 0;
00056 
00057 time_t                  exposure_time;
00058 time_t                  exposure_start          = 0;
00059 int                     erase_start;
00060 
00061 int                     fehler_index            = 0;
00062 int                     stat_scan_add           = 0;
00063 int                     stat_task_number;
00064 int                     stat_task_active;
00065 int                     stat_task_done;
00066 int                     stat_task_mode;
00067 int                     stat_task_error;
00068 int                     stat_pixels;
00069 int                     stat_blocks_sent;
00070 int                     stat_blocks_scanned;
00071 int                     stat_reference_status;
00072 int                     stat_plate_locked;
00073 int                     stat_lock_permit;
00074 int                     stat_sending_data;
00075 int                     stat_oscil_msg          = (-1);
00076 char                    stat_home               = 1;
00077 char                    stat_scan_active        = 0;
00078 int                     com_phi_steps;
00079 
00080 int                     op_dosen;
00081 float                   op_dosebeg,op_doseend,op_dosemin,op_dosemax;
00082 float                   op_doseavg,op_dosesig;
00083 double                  target_distance,        original_distance;
00084 double                  target_phi,             original_phi;
00085 double                  target_omega,           original_omega;
00086 
00087 static  float           expo_dosebeg            = 99999; 
00088 static  float           expo_doseend            = 0.0;
00089 static  float           expo_doseavg            = 0.0;
00090 static  float           expo_dosesig            = 0.0;
00091 static  float           expo_dosemin            = 999999.0;
00092 static  float           expo_dosemax            = 0.0;
00093 static  int             expo_dosen              = 0;
00094                                     
00095 /*
00096  * Local variables
00097  */
00098 static int              i, j;
00099 
00100 static char             motor_moving[6]         = {0,0,0,0,0,0};
00101 static char             change_mode             =0;
00102 static char             scan_started            =0;
00103 static char             stop_image              =0;
00104 
00105 static int              last_mar_mode           =0;
00106 static int              dist_retry              =0;
00107 static int              intensity_counter       =0;
00108 static int              open_shutter_counter    =0;
00109 static int              close_shutter_counter   =0;
00110 static int              scan_error              =0;
00111 static int              p_task_active           =0;
00112 static int              erase_lamps_ok          =0;
00113 static int              expo_dose[MAX_DOSE];
00114 static time_t           now,tick;
00115 static time_t           last=0;
00116 static float            ftmp;
00117 static float            erase_time=1.0;
00118 static float            xray_start = -999.0;
00119 static float            stat_start_phi = 0.0;
00120 
00121 static int              stat_erase_T,stat_erase_R,stat_erase_L;
00122 static int              stat_erase_T_temp,stat_erase_R_temp,stat_erase_L_temp;
00123 static int              stat_servo_warning,stat_laser_status;
00124 static int              task_done       [MAX_CMD];
00125 static int              task_error      [MAX_CMD];
00126 static int              task_active     [MAX_CMD];
00127 static int              task_queued     [MAX_CMD];
00128 static int              task_started    [MAX_CMD];
00129 
00130 /*
00131  * External variables
00132  */
00133 
00134 extern char             op_in_progress;
00135 extern char             scan_in_progress;
00136 extern int              images_per_sweep;
00137 extern int              current_block,maximum_block;
00138 extern int              current_pixel;
00139 extern int              maximum_pixels;
00140 
00141 /*
00142  * External functions
00143  */
00144 extern "C" {
00145   float GetDiskSpace(char*);
00146   int   mar_io();
00147   void  swaplong(char*, int);
00148 }
00149 
00150 static MarHW* marhw=NULL;
00151 
00152 MarHW::MarHW(QObject *parent)
00153   : inherited(parent),
00154     p_counter(-1)
00155 {
00156   marhw=this;
00157 }
00158 
00159 void
00160 MarHW::restart()
00161 {
00162   p_counter = -1;
00163 }
00164 
00165 MarHW* MarHW::mar_hw()
00166 {
00167   return marhw;
00168 }
00169 
00170 /******************************************************************
00171  * Function: mar_abort = sends ABORT to current task
00172  ******************************************************************/
00173 void MarHW::mar_abort(int)
00174 {
00175   int i;
00176   emit mar_hw()->print_message("scan345: Trying to abort current task ...\n");
00177 
00178   i=mar_hw()->marTask( MDC_COM_ABORT, 1.0);
00179 
00180   /* Reenter SIGQUIT */
00181   signal( SIGQUIT, mar_abort);
00182 }
00183 
00184 /******************************************************************
00185  * Function: mar_command = sends a command to mar controller
00186  ******************************************************************/
00187 int     
00188 MarHW::mar_command() 
00189 {
00190   /* Return if scanner is not available */
00191   if ( netcontrol==0 ) return( 0 );
00192   time( &now );
00193 
00194   emit print_message(QString("scan345: Task %1 STARTED at %2\n").arg(cmdstr[mar_number]).arg((char *)ctime( &now )));
00195   fflush( stdout );
00196 
00197   esd_cmd.cmd   = mar_number;
00198   esd_cmd.mode  = mar_mode;
00199   esd_cmd.par1  = mar_par1;
00200   esd_cmd.par2  = mar_par2;
00201   esd_cmd.par3  = mar_par3;
00202   esd_cmd.par4  = mar_par4;
00203   esd_cmd.par5  = mar_par5;
00204         
00205   strcpy( esd_cmd.id , "IPS"   );
00206   if ( mar_number != CMD_SHELL ) mar_str[0]= '\0';
00207                 
00208   strcpy( esd_cmd.str, mar_str );
00209 
00210   if ( verbose  )
00211     emit print_message(
00212                        QString().sprintf( "scan345: IPS  %d %d %d %d %d %d %d %s\n",
00213                                           mar_number,mar_mode,mar_par1,mar_par2,mar_par3,mar_par4,mar_par5,mar_str));
00214   if ( net_comm( (int)1, (char *)&esd_cmd ) < 1 ) {
00215     marError( 1000, mar_number);
00216     return( 0 );
00217   }
00218 
00219   last_mar_mode = mar_mode;
00220 
00221   return 1;
00222 }
00223 
00224 /******************************************************************
00225  * Function: mar_move_phi = moves phi
00226  ******************************************************************/
00227 int
00228 MarHW::mar_move_phi(double d)
00229 {
00230 
00231   double                delta;
00232   int           wanted,nsteps_to_move;
00233 
00234   if ( dc_stop > 1 )
00235     return( 1 );
00236   /*
00237     delta = stat_phibeg + com_dphi * (com_phiosc - totimg);
00238   */
00239   delta = com_phibeg;
00240 
00241   while (delta <    0.0) delta += 360.;
00242   while (delta >= 360.0) delta -= 360.;
00243 
00244   target_phi = delta;
00245 
00246   /* Phi movement is disabled ... */
00247   if( !cfg.use_phi ) {
00248     stat_phi = delta;
00249     i = mar_start_expo();
00250     return( 1 );
00251   }
00252 
00253   wanted = (delta + 0.5 * (1. / cfg.phi_steps)) * cfg.phi_steps;
00254                         
00255   nsteps_to_move = wanted - phi_steps;
00256 
00257   if ( d > -9999. ) {
00258     if ( d <  0.0 )
00259       nsteps_to_move = wanted = ( d - 0.5 * (1. / cfg.phi_steps)) * cfg.phi_steps;
00260     else
00261       nsteps_to_move = wanted = ( d + 0.5 * (1. / cfg.phi_steps)) * cfg.phi_steps;
00262   }
00263 
00264   while ( abs(nsteps_to_move) > 180 * cfg.phi_steps) {
00265     if(nsteps_to_move < 0)
00266       nsteps_to_move += 360 * cfg.phi_steps;
00267     else
00268       nsteps_to_move -= 360 * cfg.phi_steps;
00269   }
00270 
00271   /* Phi movement finished */
00272   if(nsteps_to_move == 0) {
00273     /* Start exposure */
00274     i = mar_start_expo( );
00275     return( 1 );
00276   }
00277   /* Phi movement negative: drive 250 more steps than necessary */
00278   else if ( nsteps_to_move < 0 ) {
00279     nsteps_to_move -= 125;
00280     mar_par4            = 125;
00281     mar_par5            = cfg.phi_speed/2;
00282   }
00283   else {
00284     mar_par4            = 0;
00285     mar_par5            = cfg.phi_speed;
00286   }
00287 
00288   /* Phi movement goes on */
00289   stat_scanner_op = CMD_MOVE_PHI;
00290   motor_op      = stat_scanner_op;
00291 
00292   mar_number    = CMD_MOVE;
00293   mar_mode      = ARG_PHI;
00294   mar_par1      = ARG_MOVE_REL;
00295   mar_par2      = nsteps_to_move;
00296   mar_par3      = cfg.phi_speed;
00297   mar_str[0]    = '\0';
00298 
00299   if( 0 == mar_command( )) return( -1 ); 
00300 
00301   return( 1 );
00302 }
00303 /******************************************************************
00304  * Function: mar_quit
00305  ******************************************************************/
00306 void
00307 MarHW::mar_quit(int m)
00308 {
00309   static char   call=0;
00310 
00311   if ( call > 0 ) {
00312     //     remove( msg_file );
00313     exit(0);
00314   }
00315 
00316   /* Enable ion chamber switching */
00317   mar_number      = CMD_ION_CHAMBER;
00318   mar_mode      = ARG_ENABLE;
00319   mar_par1      = mar_par2 = 0;
00320   i             = mar_command();
00321   sleep( 1 );
00322 
00323   /* Check Modulo of PHI */
00324   i = Modulo360();
00325 
00326   /* Close socket */
00327   for ( i=0; i<4; i++ ) {
00328     net_close( i );
00329   }
00330 
00331   emit print_message("scan345: Sockets have been closed! No more scanner control...\n");
00332   call = 1;
00333 
00334   exit( 0 );
00335 }
00336 
00337 /******************************************************************
00338  * Function: mar_change_mode
00339  ******************************************************************/
00340 int     
00341 MarHW::mar_change_mode()
00342 {
00343   int           i;
00344   static int    previous_mode= 99;
00345 
00346   /* Mode change not required , go ahead */
00347   if ( netcontrol == 0 || change_mode == 0 || cur_mode == previous_mode || cur_mode == stat_scanmode ){
00348 
00349     if ( mar_cmd != MDC_COM_MODE && mar_cmd != MDC_COM_STARTUP ) {
00350 
00351       /* We are doing an ERASE automatically ... */
00352       sprintf(str,"scan345: Diameter increased for next scan mode!\nscan345: Plate will be erased first ...\n");
00353       if ( mar_cmd != MDC_COM_ERASE )
00354         emit print_message(str);
00355 
00356       i = mar_erase();
00357       return 1;
00358     }
00359   }
00360 
00361   /* Mode change required!!! */
00362   previous_mode         = cur_mode;
00363   stat_scanner_msg= 0;
00364   stat_scanner_op = CMD_CHANGE;
00365 
00366   /* New scanning mode requested */
00367   mar_number    = CMD_CHANGE;
00368   mar_mode      = cur_mode+1;
00369   mar_par1      = mar_par2 = mar_par3 = mar_par4 = mar_par5 = 0;
00370   mar_str[0]    = '\0';
00371 
00372   mar_command() ;
00373 
00374   return 1;
00375 }
00376 
00377 /******************************************************************
00378  * Function: mar_erase
00379  ******************************************************************/
00380 int     
00381 MarHW::mar_erase()
00382 {
00383   int           i;
00384 
00385   if ( netcontrol == 0 ) return 1;
00386 
00387   if ( mar_cmd == MDC_COM_SCAN ) {
00388     i = StartScan();
00389     return 1;
00390   }
00391         
00392   /* Send ERASE command to scanner */
00393   erase_start   = time(NULL);
00394   erase_time    = cfg.erasetime[ stat_scanmode ];
00395   stat_scanner_op = CMD_ERASE; 
00396   stat_scanner_msg= 0;
00397 
00398   /* New scanning mode requested */
00399   mar_number    = CMD_ERASE;
00400   mar_mode      = stat_scanmode+1;
00401   mar_par1      = mar_par2 = mar_par3 = mar_par4 = mar_par5 = 0;
00402   mar_str[0]    = '\0';
00403 
00404   i= mar_command();
00405 
00406   return 1;
00407 }
00408 
00409 /******************************************************************
00410  * Function: NotEnoughDiskSpace
00411  ******************************************************************/
00412 int  
00413 MarHW::NotEnoughDiskSpace()
00414 {
00415   int           i;
00416   float         disk,dfree;
00417 
00418   /* 
00419    * Is there enough disk space to produce this image ?
00420    */
00421   dfree         = GetDiskSpace( stat_dir );
00422   i     = cfg.size[ run_p[SET].scanmode ];
00423   disk  = (i*i*2 + 2*i)/1000000.;
00424 
00425   if ( ( com_format == OUT_PCK || com_format == OUT_MAR || 
00426          com_format == OUT_CBF || com_format == OUT_CIF ) && keep_image )
00427     disk *= 0.5;            /* PCK: 50 % compression */
00428 
00429   /* Keep spiral active: add space for spiral */
00430   if ( keep_spiral )
00431     disk += (i*i*2 + 2*i)/1000000.;
00432 
00433   if ( disk > dfree ) {
00434     /* Try to continue writing in working_dir */
00435     sprintf( str, "scan345: Disk %s is full!\n", stat_dir );
00436     emit print_message(str);
00437 
00438     /* In working dir there is more room, so continue here */
00439     if ( disk < dfree ) {
00440       strcpy( stat_dir, working_dir );
00441       sprintf( str, "scan345: Continue to write data into %s\n", stat_dir );
00442       emit print_message(str);
00443     }
00444   }
00445 
00446   return 0;
00447 }
00448 
00449 /******************************************************************
00450  * Function: marTask = starts a scanner command
00451  ******************************************************************/
00452 int     
00453 MarHW::marTask(int task, float val )
00454 {
00455   int                   wanted,nsteps_to_move;
00456   struct tm               *cur_time;
00457   char                    curtime[16];
00458   int                   i,sys_param[5] = { 279, 97, 278, 95, 0 };
00459   double                        delta;
00460   extern char                   input_keep_spiral;
00461   extern char                   input_keep_image ;
00462 
00463   dc_stop                               = 0;
00464   stat_scanner_control          = MAR_CONTROL_ACTIVE;
00465 
00466   /* Set MAR command to 0 */
00467   if ( task != MDC_COM_SHELL && task != MDC_COM_IPS ) {
00468     mar_number  = mar_mode      = 0;
00469     mar_par1    = mar_par2      = 0;
00470     mar_par3    = mar_par4      = 0;
00471     mar_par5                    = 0;
00472     mar_str[0]                  = '\0';
00473   }
00474 
00475   switch( (int)task ) {
00476 
00477   case MDC_COM_IDLE:                    /* Send NULL command */
00478     if( 0 == mar_command( )) return( 0 ); 
00479     break;
00480 
00481   case MDC_COM_IPS:                     /* General IPS command */
00482     mar_cmd             = MDC_COM_IPS;
00483     if( 0 == mar_command( )) return( 0 ); 
00484     break;
00485 
00486   case MDC_COM_SHELL:                   /* Shell command */
00487     mar_cmd             = MDC_COM_SHELL;
00488     mar_number  = CMD_SHELL;
00489     mar_mode    = 0;
00490     mar_par1    = 0;
00491     mar_par2    = 0;
00492     mar_par3    = 0;
00493     mar_par4    = 0;
00494     mar_par5    = 0;
00495     strcpy( mar_str, ips_command );
00496     if( 0 == mar_command( )) return( 0 ); 
00497     break;
00498 
00499   case MDC_COM_RESTART:                 /* Reset on controller */
00500     return( 1 );
00501     break;
00502 
00503   case MDC_COM_QUIT:
00504     mar_quit(0);
00505     return( 1 );
00506     break;
00507 
00508   case MDC_COM_STARTUP:                 /* Abort any active commands */
00509   case MDC_COM_INIT:            
00510     mar_cmd     = MDC_COM_INIT;
00511     stop_image  = 0;
00512     target_distance = val;
00513 
00514     /* Close shutter , if open */
00515     if ( stat_xray_shutter == SHUTTER_IS_OPEN ) {
00516       mar_cmd   = (int)task;
00517       stat_scanner_op = CMD_SHUTTER;
00518       mar_number        = CMD_SHUTTER;
00519       mar_mode          = ARG_CLOSE;
00520       if( 0 == mar_command( )) return( 0 ); 
00521       sleep ( 1 );
00522     }
00523 
00524     if ( task == MDC_COM_STARTUP ) {
00525       mar_cmd   = MDC_COM_STARTUP;
00526 
00527       if ( esd_stb.task[CMD_SCAN] & 0x02 ) {
00528         emit print_message("scan345: Task SCAN found active ...\n");
00529         emit print_message("scan345: Please wait and restart program after SCAN has finished!\n");
00530         mar_quit( 0 );
00531         exit( 0 );
00532       }
00533 
00534       /* Check for active stepper task */
00535       for ( i=13; i<13; i++ ) {
00536         if ( esd_stb.task[i] &  0x02 ) {
00537           sprintf( str, "scan345: Task %2d found active ...\n",i );
00538           emit print_message(str);
00539           if ( i == CMD_MOVE ) {
00540             for ( j=0; j<6; j++ ) {
00541               if ( motor_moving[j] == 0 || (j+1)==ARG_RADIAL ) continue;
00542 
00543               mar_number        = CMD_ABORT;
00544               mar_mode  = i;
00545               mar_par1  = 0;
00546               if( 0 == mar_command( )) return( 0 );
00547               sleep( 1 );
00548             }
00549           }
00550           else {
00551             mar_number          = CMD_ABORT;
00552             mar_mode            = i;
00553             if( 0 == mar_command( )) return( 0 );
00554             sleep( 1 );
00555           }
00556         }
00557       }
00558 
00559       time( &now );
00560       cur_time = localtime( &now );
00561 
00562       /* Synchronize time and date */
00563       mar_number        = CMD_SHELL;
00564       strftime( curtime, 16, "%H:%M:%S", cur_time);
00565       sprintf ( mar_str, "clockset %s\r", curtime);
00566       if( 0 == mar_command( )) return( 0 ); 
00567       sleep( 1 );
00568 
00569       strftime( curtime, 16, "%d-%m-%Y", cur_time);
00570       sprintf ( mar_str, "dateset %s\r", curtime);
00571       if( 0 == mar_command( )) return( 0 ); 
00572       sleep( 1 );
00573 
00574       /* Enable ion chambers */
00575       mar_number      = CMD_ION_CHAMBER;
00576       mar_mode  = ARG_ENABLE;
00577       if( 0 == mar_command( )) return( 0 ); 
00578 
00579 
00580       /* Get some more system params */
00581       for ( i=0; i<4; i++ ) {
00582         mar_number      = CMD_SET;
00583         mar_mode        = ARG_READ;
00584         mar_par1        = sys_param[ i ];
00585         if( 0 == mar_command( )) return( 0 );
00586         sleep( 1 );
00587       }
00588 
00589       /* Initialize servo system */
00590       if ( esd_stb.servo_state != 0 ) {
00591         emit print_message("scan345: Initializing SERVO system ...\n");
00592         sprintf ( mar_str, "SERVO_INIT 1,3,5\r");
00593         if( 0 == mar_command( )) return( 0 ); 
00594         sleep( 1 );
00595         i = mar_servo();
00596         break;
00597       }
00598       /* Lock plate */
00599       mar_lock();
00600 
00601       /* Are we done ? */
00602       if ( esd_stb.scanmode > 0 && esd_stb.scanmode < 9 ) {
00603         /* Adjust PHI to modulo 360.0 deg */
00604         i = Modulo360();
00605       }
00606 
00607       /* ... not yet: go to defined scan mode */
00608       sprintf( str, "scan345: Current scan mode: %d ...\n", stat_scanmode );
00609       emit print_message(str);
00610       
00611       break;
00612     }
00613 
00614     mar_number          = CMD_MOVE;
00615     mar_mode    = ARG_DISTANCE;
00616     if (target_distance == cfg.dist_max) {
00617       mar_par1  = ARG_INIT_FAR;
00618       mar_par2  = (cfg.dist_max + 0.5 * (1. / cfg.dist_steps)) * cfg.dist_steps;
00619     }
00620     else {
00621       mar_par1  = ARG_INIT_NEAR;
00622       mar_par2  = (cfg.dist_min + 0.5 * (1. / cfg.dist_steps)) * cfg.dist_steps;
00623     }
00624     mar_par3 = cfg.dist_speed;
00625     mar_par4 = 0;
00626     mar_par5 = cfg.dist_speed/10;       /* CHECK !!! */
00627     if( 0 == mar_command( )) return( 0 ); 
00628 
00629     stat_scanner_op = CMD_MOVE_DISTANCE;
00630     motor_op    = stat_scanner_op;
00631 
00632     break;
00633 
00634   case MDC_COM_ABORT:                   /* Abort all active commands*/
00635 
00636     /* We do not want to interrupt scan or erase... */
00637     if ( scan_in_progress && ( stat_task_number == CMD_SCAN || stat_task_number == CMD_ERASE ) ) {
00638       break;
00639     }
00640 
00641     /* Set up MAR command */
00642     mar_number          = CMD_ABORT;
00643     mar_par1    = mar_par2 = 0;
00644     for ( i=j=0; j<6; j++ ) {
00645       if ( motor_moving[j] == 0 || (j+1)==ARG_RADIAL ) continue;
00646 
00647       if ( (j+1) == ARG_DISTANCE ) {
00648         sprintf( str ,"scan345: Abort DRIVE DETECTOR\n");
00649         if ( stat_scanner_op != CMD_MOVE_DISTANCE ) continue;
00650       }
00651       else if ( (j+1) == ARG_OMEGA ) { 
00652         sprintf( str ,"scan345: Abort DRIVE OMEGA\n");
00653         if ( stat_scanner_op != CMD_MOVE_OMEGA ) continue;
00654       }
00655       else if ( (j+1) == ARG_CHI   ) {
00656         sprintf( str ,"scan345: Abort DRIVE CHI\n");
00657         if ( stat_scanner_op != CMD_MOVE_CHI) continue;
00658       }
00659       else if ( (j+1) == ARG_THETA ) {
00660         sprintf( str ,"scan345: Abort DRIVE THETA\n");
00661         if ( stat_scanner_op != CMD_MOVE_THETA ) continue;
00662       }
00663       else if ( (j+1)== ARG_PHI )  {
00664         sprintf( str ,"scan345: Abort DRIVE PHI\n");
00665         if ( stat_scanner_op != CMD_MOVE_PHI ) continue;
00666       }
00667       //       fprintf( fpout, str);
00668       emit print_message(str);
00669 
00670       mar_number        = CMD_ABORT;
00671       mar_mode          = CMD_MOVE;
00672       mar_par1  = 0;
00673       dc_stop           = 2;
00674 
00675       if( 0 == mar_command( )) return( 0 );
00676       i++;
00677 
00678       if ( (j+1) == ARG_PHI ) {
00679         /* Adjust PHI to modulo 360.0 deg */
00680         Modulo360();
00681       }
00682 
00683     }
00684     if ( mar_cmd != MDC_COM_COLL) break;
00685 
00686     emit print_message("\nscan345: Abort EXPOSURE\n");
00687 
00688     /* Abort exposure... */
00689     mar_number  = CMD_ABORT;
00690     mar_mode    = CMD_COLLECT; 
00691 
00692     if( 0 == mar_command( )) return( 0 );
00693 
00694     /* Adjust PHI to modulo 360.0 deg */
00695     Modulo360();
00696                 
00697     break;
00698 
00699   case MDC_COM_SHUT:                    /* Operate shutter */
00700     mar_cmd     = (int)task;
00701     stat_scanner_op = CMD_SHUTTER;
00702     mar_number      = CMD_SHUTTER;
00703     mar_par1    = mar_par2 = 0;
00704     /* Open shutter */
00705     if( val == 1.0 ) {
00706       mar_mode = ARG_OPEN;
00707     }
00708     /* Close shutter */
00709     else {
00710       mar_mode = ARG_CLOSE;
00711     }
00712 
00713     if( 0 == mar_command( )) return( 0 ); 
00714     break;
00715 
00716   case MDC_COM_CHAMBER:                 /* (De-)select ion chamber */
00717     stop_image  = 0;
00718     dc_stop             = 0;
00719     mar_number      = CMD_ION_CHAMBER;
00720     mar_par1    = mar_par2 = 0;
00721     /* Enable switching */
00722     if( val == 1.0 )
00723       mar_mode = ARG_ENABLE;
00724     /* Disable switching */
00725     else
00726       mar_mode = ARG_DISABLE;
00727     if( 0 == mar_command( )) return( 0 ); 
00728     break;
00729 
00730   case MDC_COM_DSET:                    /* Define new distance */
00731     mar_cmd     = (int)task;
00732     wanted              = (val+0.5*(1./cfg.dist_steps))*cfg.dist_steps;
00733     distance_steps      = wanted;
00734 
00735     mar_number          = CMD_SET;
00736     mar_mode    = ARG_WRITE;
00737     mar_par1    = 75;
00738     mar_par2    = wanted;
00739     stat_scanner_op     = CMD_MOVE_DISTANCE;
00740     motor_op    = stat_scanner_op;
00741  
00742     emit print_message(QString().sprintf( "scan345: Defining DISTANCE as %1.3f\n",val));
00743     if( 0 == mar_command( )) return( 0 ); 
00744 
00745     stat_dist      = val;
00746     break;
00747 
00748   case MDC_COM_PSET:                    /* Define new phi */
00749     mar_cmd     = (int)task;
00750     delta               = val;
00751     while(delta <    0.0) 
00752       delta += 360.;
00753     while(delta >= 360.0) 
00754       delta -= 360.;
00755     phi_steps           = (delta+0.5 *(1./cfg.phi_steps))*cfg.phi_steps;
00756 
00757     mar_number          = CMD_SET;
00758     mar_mode    = ARG_WRITE;
00759     mar_par1    = 80;
00760     mar_par2    = phi_steps;
00761 
00762     stat_scanner_op     = CMD_SET;
00763     motor_op    = stat_scanner_op;
00764 
00765     emit print_message(QString().sprintf( "scan345: Defining PHI as %1.3f\n",val));
00766     if( 0 == mar_command( )) return( 0 ); 
00767     stat_phi       = delta;
00768 
00769     break;
00770 
00771   case MDC_COM_OSET:                    /* Define new omega */
00772     mar_cmd     = (int)task;
00773     delta               = val;
00774     while(delta <    0.0) 
00775       delta += 360.;
00776     while(delta >= 360.0) 
00777       delta -= 360.;
00778     omega_steps         = (delta+0.5*(1./cfg.ome_steps))*cfg.ome_steps;
00779 
00780     mar_number          = CMD_SET;
00781     mar_mode    = ARG_WRITE;
00782     mar_par1    = 76;
00783     mar_par2    = omega_steps;
00784     stat_scanner_op     = CMD_MOVE_OMEGA;
00785     motor_op    = stat_scanner_op;
00786 
00787     emit print_message(QString().sprintf( "scan345: Defining OMEGA as %1.3f\n",val));
00788     if( 0 == mar_command( )) return( 0 ); 
00789     stat_omega     = delta;
00790 
00791     break;
00792 
00793   case MDC_COM_DISTANCE:                        /* Move distance */
00794     mar_cmd     = (int)task;
00795     /* Distance movement disabled... */
00796     if( ! cfg.use_dist ) {
00797       stat_dist = val;
00798       break;
00799     }
00800     /* Distance movement  enabled... */
00801     wanted              = (val+0.5*(1./cfg.dist_steps))*cfg.dist_steps;
00802     target_steps        = wanted;
00803     if(wanted < distance_steps) {
00804 #ifdef TRANS_BACK
00805       /* Use backlash during distance translation ... */
00806       wanted            -= 100;
00807       mar_par4  = wanted + 100;
00808       mar_par5          = cfg.dist_speed;
00809 #else
00810       mar_par4  = wanted;
00811 #endif
00812     }
00813     else {
00814       mar_par4  = wanted;
00815     }
00816 
00817     dist_retry          = 0;
00818     original_distance   = stat_dist;
00819     target_distance     = val;
00820     stat_scanner_op             = CMD_MOVE_DISTANCE;
00821     motor_op            = stat_scanner_op;
00822     mar_number                  = CMD_MOVE;
00823     mar_mode            = ARG_DISTANCE;
00824     mar_par1            = ARG_MOVE_ABS;
00825     mar_par2                    = wanted;
00826     mar_par3                    = cfg.dist_speed;
00827     mar_par5                    = cfg.dist_speed;
00828 
00829     emit print_message(QString().sprintf( "scan345: Moving DISTANCE from %1.3f to %1.3f\n",stat_dist,target_distance));
00830 
00831     if( 0 == mar_command( )) return( 0 ); 
00832 
00833     break;
00834 
00835   case MDC_COM_PHI:                     /* Move phi */
00836     mar_cmd     = (int)task;
00837     delta           = val;
00838     if(delta <    0.0 ) delta += 360.;
00839     if(delta >  360.0 ) delta -= 360.;
00840     /* Phi movement disabled... */
00841     if( ! cfg.use_phi ) {
00842       stat_phi = delta;
00843       break;
00844     }
00845 
00846     /* Phi movement enabled... */
00847     wanted              = (delta+0.5*(1./cfg.phi_steps))*cfg.phi_steps;
00848     nsteps_to_move      = wanted - phi_steps;
00849     while ( abs(nsteps_to_move) >  180 * cfg.phi_steps) {
00850       if(nsteps_to_move < 0)
00851         nsteps_to_move += 360 * cfg.phi_steps;
00852       else
00853         nsteps_to_move = nsteps_to_move - 360 * cfg.phi_steps;
00854     }
00855 
00856     /* Phi movement negative: drive 250 more steps than necessary */
00857     if ( nsteps_to_move < 0 ) {
00858       nsteps_to_move -= 125;
00859       mar_par4  = 125;
00860       mar_par5          = cfg.phi_speed/2;
00861     }
00862     else {
00863       mar_par4  = 0;
00864       mar_par5          = cfg.phi_speed;
00865     }
00866 
00867     target_phi  = delta;
00868     stat_scanner_op = CMD_MOVE_PHI;
00869     motor_op    = stat_scanner_op;
00870     mar_number          = CMD_MOVE;
00871     mar_mode    = ARG_PHI;
00872     mar_par1    = ARG_MOVE_REL;
00873     mar_par2            = nsteps_to_move;
00874     mar_par3            = cfg.phi_speed;
00875 
00876     emit print_message(QString().sprintf( "scan345: Moving PHI from %1.3f to %1.3f\n",stat_phi,target_phi));
00877     if( 0 == mar_command( )) return( 0 ); 
00878                 
00879     break;
00880 
00881   case MDC_COM_OMOVE:                   /* Move omega */
00882     mar_cmd     = (int)task;
00883     target_omega        = val;
00884     if( !cfg.use_ome ) {
00885       stat_omega = val;
00886       break;
00887     }
00888     /* This is for MPI-Hamburg only */
00889     nsteps_to_move      = val*cfg.ome_steps;
00890 
00891     if(nsteps_to_move == omega_steps && cfg.use_zaxis == 0 ) {
00892       break;
00893     }
00894     else if(nsteps_to_move < omega_steps ) {
00895       nsteps_to_move    -= 250;
00896       mar_par4  =  250;
00897       mar_par5          = cfg.ome_speed;
00898     }
00899     else {
00900       mar_par4  = 0;
00901       mar_par5          = 0;
00902     }
00903 
00904     stat_scanner_op = CMD_MOVE_OMEGA;
00905     motor_op    = stat_scanner_op;
00906     mar_number      = CMD_MOVE;
00907     mar_mode        = ARG_OMEGA;
00908     mar_par1        = ARG_MOVE_REL;
00909     mar_par2            = nsteps_to_move;
00910     mar_par3            = cfg.ome_speed;
00911 
00912     emit print_message(QString().sprintf( "scan345: Moving OMEGA from %1.3f to %1.3f\n",stat_omega,target_omega));
00913     if( 0 == mar_command( )) return( 0 );
00914                 
00915     break;
00916 
00917   case MDC_COM_ERASE:                   /* Erase plate */
00918     cur_mode    = com_scanmode;
00919     mar_cmd     = (int)task;
00920     erase_start = -1;
00921     erase_lamps_ok  = 0;
00922     erase_time  = cfg.erasetime[ stat_scanmode ];
00923 
00924     /* Change mode */
00925     change_mode         = 0;
00926     emit print_message("scan345: Erasing ...\n");
00927     i = mar_change_mode();
00928     break;
00929 
00930   case MDC_COM_SCAN:                    /* Do a scan */
00931 
00932     mar_cmd = (int)task;
00933 
00934     /* Decide if we want spiral op */
00935     if ( input_keep_spiral || com_use_spiral )
00936       keep_spiral = 1;
00937     else
00938       keep_spiral = 0;
00939 
00940     /* Decide if we want xform */
00941     if ( input_keep_image )
00942       keep_image  = 1;
00943     else {
00944       keep_image  = 0;
00945       keep_spiral = 1;
00946     }
00947 
00948     stat_xray_units = 0.0;
00949     skip_op             = 0;
00950     erase_start = -1;
00951 
00952     stat_scan_add       = 0;
00953     stat_scanner_op = CMD_SCAN;
00954     mar_number      = CMD_SCAN;
00955     current_pixel   = 0;
00956     cur_mode    = com_scanmode;
00957     cur_pixelsize   = cfg.pixelsize     [cur_mode];
00958     cur_diameter    = cfg.diameter      [cur_mode];
00959     erase_lamps_ok  = 0;
00960     /* Change mode */
00961     change_mode         = 1;
00962     i           = mar_change_mode();
00963     break;
00964 
00965   case MDC_COM_COLL:            /* Collect */
00966     mar_cmd     = (int)task;
00967 
00968     /* Store starting time */
00969     time(&tick);
00970     strcpy( start_time, (char *)ctime(&tick) );
00971 
00972     /* Initialize DOSE counters */
00973     expo_doseavg    = expo_dosesig = 0.0;
00974     expo_dosemin    = expo_dosebeg = 99999.0;
00975     expo_dosemax    = expo_doseend = 0.0;
00976     expo_dosen      = 0;
00977     memset( (char *)expo_dose, 0, sizeof(int)*MAX_DOSE );
00978 
00979     /* Initialize progress         */
00980     exposure_start         = 0;
00981 
00982     /* Initialize status variables */
00983     stat_time       = com_time;
00984     stat_phibeg     = com_phibeg;
00985     stat_dphi       = com_dphi;
00986     stat_n_passes   = com_phiosc;
00987     stat_mode       = com_mode;
00988     stat_scanner_op = CMD_MOVE;
00989     totpass         = stat_n_passes;
00990     stat_phiend         = stat_phibeg + stat_dphi;
00991     stat_start_phi      = stat_phi;
00992 
00993     /* Avoid rounding errors when driving PHI */
00994     com_phi_steps       = (int)( cfg.phi_steps * (stat_dphi * 100000. + 1 )/100000.);
00995 
00996     /* Time mode */
00997     if(stat_mode == ARG_TIME ) {
00998       if ( com_phi_steps == 0 || cfg.use_phi == 0 ) 
00999         stat_units = (cfg.units_time * stat_time);
01000       else
01001         stat_units = (cfg.units_time * stat_time)/(com_phi_steps*stat_n_passes);
01002     }
01003         
01004     /* Dose mode */
01005     else {
01006       stat_units = stat_time;
01007     }
01008 
01009     /* Send command to scanner */
01010     if ( stat_units >  0 ) {
01011       if ( com_phibeg != stat_phi )
01012         i = mar_move_phi( -9999. );
01013       else
01014         i = mar_start_expo();
01015     }
01016 
01017     break;
01018 
01019   case MDC_COM_MODE:                    /* New scanning mode */
01020     mar_cmd = (int)task;
01021     cur_mode    = com_scanmode; 
01022     stat_scanner_op = CMD_CHANGE;
01023     change_mode         = 1;
01024     i           = mar_change_mode();
01025     break;
01026 
01027   default:
01028     return( 0 );
01029   }
01030 
01031 #ifdef DEBUG
01032   if ( debug & 0x02 )
01033     emit print_message(QString().sprintf("debug (marhw:marTask): MAR  %d, %d, %d, %d, %d, %d %d\n",
01034                                          mar_number,mar_mode,mar_par1,mar_par2,mar_par3,mar_par4,mar_par5));
01035 #endif
01036 
01037   return( 1 );
01038 }
01039 
01040 /******************************************************************
01041  * Function: get_status
01042  ******************************************************************/
01043 int
01044 MarHW::get_status()
01045 {
01046   int           i,status=0;
01047   static  time_t  before2=0;
01048   extern int    status_interval;
01049 
01050   //   /* Is there a new command ? */
01051   //   get_command();
01052 
01053   /* Get current time */
01054   now = time( NULL );
01055         
01056 #ifdef SIMUL
01057   goto UPDATE;
01058 #endif
01059 
01060   /* Return if scanner is not available */
01061   if ( netcontrol==0 ) goto UPDATE;
01062 
01063   i = net_data();
01064 
01065   /* Reading network status */
01066   while ( 1 ) {
01067     status = net_stat();
01068     if ( status < 200 ) break;
01069   }
01070         
01071 
01072 #ifdef DEBUG
01073   if ( debug & 0x04 )
01074     printf("debug (marhw:get_status) read=%d\n",status);
01075 #endif
01076 
01077   i = net_msg ( );
01078 
01079  UPDATE:
01080   /* Update status window */
01081   if ( (now-before2)> 1 ) {
01082     /* Set new time */
01083     before2 = time(NULL);
01084   }
01085 
01086   if ( !scan_in_progress ) {
01087     sleep( 1 );
01088   }
01089 
01090   return( status );
01091 }
01092 
01093 /******************************************************************
01094  * Function: process_status 
01095  ******************************************************************/
01096 
01097 int
01098 MarHW::process_status( char *buf )
01099 {
01100   int           i,j,k;
01101   static int    p_active        [MAX_CMD];
01102   static int    p_error         [MAX_CMD];
01103   static int    p_task          [MAX_CMD] = {1234,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
01104   static char   first_time      = 1;
01105   static int    p_gap           = 999;
01106 //   static int         p_counter       = -1;
01107   /* The following gives the sequence of tasks to be handled by mar_process */
01108   static int    idx[8] = { CMD_SCAN,    CMD_COLLECT,    CMD_MOVE,
01109                            CMD_ERASE,   CMD_SHUTTER,    CMD_CHANGE,
01110                            CMD_LOCK,    CMD_ION_CHAMBER};
01111 
01112 
01113   memcpy( (char *)&esd_stb, buf, sizeof( ESD_STB ) );
01114 
01115   if ( esd_stb.counter <= p_counter ) {
01116     sprintf( str, "scan345: ERROR at STATUS block # %d (last was %d)\n",
01117              esd_stb.counter,p_counter);
01118     emit print_message( str );
01119     p_counter = esd_stb.counter;
01120     return 0;
01121   }
01122 
01123   p_counter = esd_stb.counter;
01124 
01125   stat_pixels   = esd_stb.valid_data;
01126   stat_scanmode         = esd_stb.scanmode - 1;
01127 
01128   if ( stat_scanmode < 0 || stat_scanmode > 7 ) {
01129     stat_scanmode = 0;
01130   }
01131 
01132   /* Read status first time: set defaults for p_task to avoid action */
01133   if ( p_task[0] == 1234 ) {
01134     for ( i=0; i<MAX_CMD; i++ ) p_task[i] = esd_stb.task[i];
01135   }
01136 
01137         
01138   /*
01139    * Resolve bits in hw_status1 
01140    */
01141   stat_xray_shutter     = esd_stb.hw_status1 & two32[ 11 ]; /* 20 */
01142   stat_reference_status         = esd_stb.hw_status1 & two32[  9 ]; /* 22 */
01143 
01144   stat_erase_T          = esd_stb.hw_status1 & two32[ 21 ]; /* 10 */
01145   stat_erase_R          = esd_stb.hw_status1 & two32[ 20 ]; /* 11 */
01146   stat_erase_L          = esd_stb.hw_status1 & two32[ 19 ]; /* 12 */
01147 
01148   stat_erase_T_temp     = esd_stb.hw_status1 & two32[ 31 ]; /*  0 */
01149   stat_erase_R_temp     = esd_stb.hw_status1 & two32[ 25 ]; /*  6 */
01150   stat_erase_L_temp     = esd_stb.hw_status1 & two32[ 24 ]; /*  7 */
01151 
01152   stat_servo_warning    = esd_stb.hw_status1 & two32[ 23 ]; /*  8 */
01153   stat_laser_status     = esd_stb.hw_status1 & two32[ 22 ]; /*  9 */
01154   stat_lock_permit      = esd_stb.hw_status1 & two32[ 18 ]; /* 15 */
01155 
01156   /* Is the plate locked ? */
01157   if ( (esd_stb.hw_status1 & two32[16]) == 0)
01158     stat_plate_locked = 1;
01159   else
01160     stat_plate_locked = 0;
01161 
01162   /* Is the scanning head moving ? */
01163   if (  esd_stb.task[CMD_RADIAL] & 0x01 ) 
01164     stat_home = 1;
01165   else
01166     stat_home = 0;
01167 
01168   if (  esd_stb.task[CMD_SCAN] & 0x02  ) 
01169     stat_scan_active = 1;
01170   else
01171     stat_scan_active = 0;
01172 
01173   distance_steps  = esd_stb.stepper[0][STEPPER_IST];
01174   omega_steps     = esd_stb.stepper[1][STEPPER_IST];
01175   phi_steps       = esd_stb.stepper[5][STEPPER_IST];
01176 
01177   for ( i=0; i<6; i++ ) {
01178     if ( esd_stb.stepper[i][STEPPER_IST] != 
01179          esd_stb.stepper[i][STEPPER_SOLL] ) 
01180       motor_moving[i] = 1;
01181     else
01182       motor_moving[i] = 0;
01183   }
01184                         
01185   stat_intensity        = esd_stb.intensity / 1000.;
01186 
01187   if ( cfg.use_phi ) {
01188     stat_phi   = (float)((float)phi_steps         /cfg.phi_steps);
01189     while( stat_phi < 0.0 ) {
01190       stat_phi  += 360.;
01191     }
01192     while( stat_phi > 359.999 ) {
01193       stat_phi  -= 360.;
01194     }
01195   }
01196   if ( cfg.use_dist && distance_steps > 0 )
01197     stat_dist  = (float)((float)distance_steps/cfg.dist_steps);
01198   if ( cfg.use_ome )
01199     stat_omega = (float)((float) omega_steps  /cfg.ome_steps);
01200 
01201   erase_lamps_ok = 1;
01202 
01203   if ( stat_xray_shutter ) 
01204     stat_xray_shutter = SHUTTER_IS_CLOSED;
01205   else
01206     stat_xray_shutter = SHUTTER_IS_OPEN;
01207 
01208   /* Go through all tasks that we want to handle ( in array idx ) */
01209   for ( k=0; k<8; k++ ) {
01210     i  = idx[k];
01211 
01212     task_done   [i]     = esd_stb.task[i] &  two32[  0 ];
01213     task_active [i]     = esd_stb.task[i] &  two32[  1 ];
01214     task_queued [i]     = esd_stb.task[i] &  two32[  4 ];
01215     task_started        [i]     = esd_stb.task[i] &  two32[  2 ];
01216     task_error  [i]     = esd_stb.task[i] &  two32[  8 ];
01217 
01218     /*
01219       if ( stat_scan_active && i != CMD_SCAN ) goto SKIP1;
01220     */
01221     /* Do not process queued tasks */
01222     if ( !(esd_stb.task[i] & 0x10)  ) {
01223 
01224       if ( ( (esd_stb.task[i] & 0x02 ) || esd_stb.task[i] != p_task[i] ) && i != CMD_ABORT ) {
01225         stat_task_number        = i;
01226         stat_task_active        = task_active   [i];
01227         stat_task_done          = task_done     [i];
01228         stat_task_error         = task_error    [i];
01229 
01230         if ( stat_task_error ) {
01231           if ( first_time ) {
01232             stat_task_number = 0;
01233             goto SKIP1;
01234             continue;
01235                                 
01236           }
01237           emit print_message(QString().sprintf("scan345: ERROR ending of task %d\n",i));
01238           //      fprintf( fpout,"scan345: ERROR ending of task %d\n",i);
01239         }
01240 
01241         j = mar_progress( stat_task_number, stat_task_active, stat_task_error );
01242       }
01243       else
01244         stat_task_number        = 0;
01245     }
01246   SKIP1:
01247     p_active[i] = task_active[i];
01248     p_error [i] = task_error[i]; 
01249     p_task      [i] = esd_stb.task[i];
01250   }
01251 
01252   first_time = 0;
01253 
01254 #ifdef OLDGAPS
01255   if ( p_gap == 0 && esd_stb.gaps[0] != 0 ) {
01256     stat_gap = esd_stb.gaps[0];
01257   }
01258   p_gap = esd_stb.gaps[0];
01259 #endif
01260 
01261   /* Always keep non-zero values for GAPs: Reset only at start of scan */
01262   for (i=0;i<8;i++) {
01263     if ( esd_stb.gaps[i] != 0 )
01264       stat_gap[i] = esd_stb.gaps[i];
01265   }
01266 
01267   return 1;
01268 }
01269 
01270 /******************************************************************
01271  * Function: mar_progress = keeps track of progress of data col
01272  ******************************************************************/
01273 int     
01274 MarHW::mar_progress(int task, int active, int error)
01275 {
01276   char                  done=0;
01277   int                   fehler = 0;
01278   float                 ftmp;
01279   static int            last_xray_shutter;
01280   static int            ntry=0;
01281   static int                    pdone;
01282   static char           p_move = 0;
01283   static char           expo_first = 1;
01284 
01285   //   emit print_message("marhw:mar_progress");
01286 
01287   /* Reset "done" */
01288   done = 0;
01289 
01290   /*
01291    * Are we in error recovery mode ?
01292    */
01293 
01294   //   printf("debug (marhw:mar_progress): task=%d   act=%d  err=%d\n",task,active,error);
01295 
01296   /* Task is the most recent in the controllers task list */
01297   switch( task ) {
01298 
01299   case CMD_SHELL:
01300 
01301     if ( active ) break;
01302 
01303     done = 1;
01304     /* Get error number */
01305     if ( error ) {
01306       fehler = get_error( 0 );
01307       if ( fehler < 0 ) error = 0;
01308     }
01309     break;
01310 
01311   case CMD_MOVE:
01312 
01313     /* Note: I have seen that this has been called twice after
01314      * activity with active = 0. This prevents going on, especially
01315      * when doing multiple oscillations. Therefore: react only once
01316      * to: task done!!!
01317      */
01318 
01319     if ( active == 0 && p_move == 0 ) break;
01320     p_move = active;
01321 
01322     /* Completeness */
01323     if( active ) {
01324       stat_scanner_msg = 0; 
01325       if ( mar_mode == ARG_DISTANCE || mar_mode == ARG_THETA ) {
01326         if ( target_distance != original_distance )
01327           ftmp = 100 * (stat_dist-original_distance)/(original_distance - target_distance );
01328         else
01329           ftmp = 100.0;
01330 
01331         stat_scanner_msg = (int)(ftmp+0.5);
01332         if ( stat_scanner_msg < 0 ) stat_scanner_msg *= -1;
01333       }
01334       else if ( mar_mode == ARG_PHI || mar_mode == ARG_CHI ) {
01335         i = esd_stb.stepper[mar_mode-1][STEPPER_SOLL] - esd_stb.stepper[mar_mode-1][STEPPER_IST];
01336         if ( mar_par2 != 0 )
01337           ftmp = 100. * i/ (float)mar_par2; 
01338         stat_scanner_msg = 100-(int)(ftmp+0.5);
01339         if ( stat_scanner_msg <  0 ) stat_scanner_msg *= -1;
01340       }
01341       break;
01342     }
01343 
01344     /* Get error number */
01345     if ( error ) {
01346       fehler = get_error( 0 );
01347       if ( fehler < 0 ) error = 0;
01348     }
01349 
01350     /* Distance movement */
01351     if ( mar_mode == ARG_DISTANCE ) {
01352       if( cfg.use_dist == 0 ) {
01353         done = 1;
01354         break;
01355       }
01356 
01357       /* Task error */
01358       if ( error ) {
01359 
01360         stat_scanner_op = CMD_MOVE_DISTANCE;
01361 
01362         /* Cannot leave reference switch */
01363         if ( fehler == 225 && 
01364              (distance_steps == (int)(cfg.dist_min *cfg.dist_steps) || distance_steps == (int)(cfg.dist_max *cfg.dist_steps) ) ) {
01365           marError(225, 0 );
01366           done = 1;
01367           mar_number    = CMD_MOVE;
01368           mar_mode      = ARG_DISTANCE;
01369           mar_par3      = cfg.dist_speed;
01370           mar_par1      = 2*(( cfg.dist_max - cfg.dist_min )*cfg.dist_steps/cfg.dist_speed);
01371           if ( distance_steps <= (int)(cfg.dist_min *cfg.dist_steps )) {
01372             if ( dist_retry < 2 ) {
01373               mar_par1          = ARG_INIT_NEAR;
01374               mar_par2          = cfg.dist_min*cfg.dist_steps;
01375             }
01376             else {
01377               mar_par1          = ARG_INIT_FAR;
01378               mar_par2          = cfg.dist_max*cfg.dist_steps;
01379             }
01380           }
01381           else {
01382             if ( dist_retry < 2 ) {
01383               mar_par1          = ARG_INIT_FAR;
01384               mar_par2          = cfg.dist_max*cfg.dist_steps;
01385             }
01386             else {
01387               mar_par1          = ARG_INIT_NEAR;
01388               mar_par2          = cfg.dist_min*cfg.dist_steps;
01389             }
01390           }
01391 
01392         }
01393 
01394         /* Reference switch touched */
01395         else if ( fehler == 225 ) {
01396           marError( 225, 1);
01397           done = 1;
01398           break;
01399         }
01400 
01401         /* Cannot FIND reference switch */
01402         else if ( fehler == 217 ) {
01403           marError( 217, 0);
01404           done = 1;
01405           break;
01406         }
01407 
01408         dist_retry++;
01409 
01410         done = 1;
01411         if ( dist_retry < 4 ) { 
01412           i = mar_command( );
01413         }
01414         else {
01415           done = 1;
01416         }
01417 
01418         break;
01419       }
01420 
01421       /* End of task */
01422       else {
01423         dist_retry = 0;
01424         done = 1;
01425         break;
01426       }
01427     }
01428 
01429 
01430     /* OMEGA movement */
01431     else if ( mar_mode == ARG_OMEGA ) {
01432 
01433       /* OMEGA movement disabled... */
01434       if( cfg.use_ome == 0 ) {
01435         done = 1;
01436         break;
01437       }
01438 
01439       if ( active ) break;
01440 
01441       /* Task ended. */
01442       done = 1;
01443       break;
01444     }
01445 
01446     /* PHI movement */
01447     else if ( mar_mode == ARG_PHI ) {
01448 
01449       /* Phi movement disabled... */
01450       if( cfg.use_phi == 0 ) {
01451         done = 1;
01452         break;
01453       }
01454 
01455       /* Task in progress */
01456       if ( active ) break;
01457 
01458       /* Task ended.
01459        */
01460       stat_start_phi    = stat_phi;
01461 
01462       /* In data collection mode, start next exposure */
01463       if ( mar_cmd == MDC_COM_COLL ) {
01464         done = 0;
01465         i=mar_start_expo( );
01466       }
01467       else {
01468         done = 1;
01469         /* Adjust PHI to modulo 360.0 deg */
01470         i = Modulo360();
01471       }
01472     }
01473 
01474     break;
01475 
01476   case CMD_ABORT:
01477     if ( active ) break;
01478     if ( active == 0 && p_task_active == 0 ) break;
01479 
01480     if ( error ) {
01481       fehler = get_error(1);
01482       if ( fehler < 0 ) error = 0;
01483     }
01484 
01485     if ( scan_in_progress ) {
01486       done=0;
01487       break;
01488     }
01489     else {
01490       marTask( MDC_COM_CHAMBER, 1.0 );
01491 
01492       /* Adjust PHI to modulo 360.0 deg */
01493       i = Modulo360();
01494 
01495       sleep( 1 );
01496       done = 1;
01497     }
01498     break;
01499 
01500   case CMD_SHUTTER:
01501 
01502     /* Task in progress */
01503     if ( active ) break;
01504 
01505     /* Task done */
01506     if ( error ) {
01507 
01508       fehler = get_error(0);
01509       if ( fehler < 0 ) 
01510         error = 0;
01511       else {
01512 #ifdef SKIP_RECOVER
01513         printf("scan345: Shutter error\n");
01514         done = 1;
01515         break;
01516 #endif
01517 
01518         ntry =0;
01519         if ( fehler == 205 ) {
01520           /* Cannot open shutter, close it !*/
01521           marError( 205, ntry ); 
01522           stat_scanner_op = CMD_SHUTTER;
01523           mar_number            = CMD_SHUTTER;
01524           mar_mode              = ARG_CLOSE;
01525           mar_par1      = mar_par2 = 0;
01526           mar_par3      = mar_par4 = mar_par5 = 0;
01527           if( 0 == mar_command( )) return( 0 ); 
01528         }
01529         else if ( fehler == 210 ) {
01530           /* Cannot close shutter */
01531           marError( 210, ntry ); 
01532         }
01533       }
01534     }
01535     else {
01536       if ( mar_cmd == MDC_COM_SHUT ) {
01537         done = 1;
01538         ntry = 0;
01539       }
01540       else 
01541         done = 0;
01542     }
01543 
01544     /* Initialize of startup: move distance */
01545     if( mar_cmd == MDC_COM_INIT && cfg.use_dist ) {
01546       mar_number        = CMD_MOVE;
01547       mar_mode  = ARG_DISTANCE;
01548       if (target_distance == cfg.dist_max) {
01549         mar_par1  = ARG_INIT_FAR;
01550         mar_par2  = (cfg.dist_max + 0.5 * (1. / cfg.dist_steps)) * cfg.dist_steps;
01551       }
01552       else {
01553         mar_par1  = ARG_INIT_NEAR;
01554         mar_par2  = (cfg.dist_min + 0.5 * (1. / cfg.dist_steps)) * cfg.dist_steps;
01555       }
01556       mar_par3 = cfg.dist_speed;
01557       mar_par4 = 0;
01558       mar_par5 = cfg.dist_speed/10;     /* CHECK !!! */
01559       if( 0 == mar_command( )) return( 0 ); 
01560 
01561       done              = 0;
01562       stat_scanner_op = CMD_MOVE_DISTANCE;
01563       motor_op  = stat_scanner_op;
01564     }
01565 
01566     break;
01567 
01568   case CMD_ERASE:               /* Erase plate */
01569 
01570     if ( erase_start > 0 && erase_time > 0.00 )
01571       stat_scanner_msg = 100 * ( time(NULL) - erase_start)/erase_time;
01572     else
01573       stat_scanner_msg = 0;
01574 
01575     /* Task still in progress */
01576     if ( active ) break;
01577 
01578     /* 
01579      * While IP is erasing, the erase_status bit tells us
01580      * if the lamps are on
01581      */
01582 
01583     /* Erase finished... */
01584     if( error ) {
01585       fehler = get_error(1);
01586       if ( fehler < 0 ) 
01587         error = 0;
01588       else {
01589         done = 1;
01590 #ifdef SKIP_RECOVER
01591         printf("scan345: ERASE error\n");
01592         break;
01593 #endif
01594 
01595         break;
01596       }
01597     }
01598 
01599     pdone= 0;
01600     done = 1;
01601     break;
01602 
01603   case CMD_LOCK:
01604 
01605     if( active ) break;
01606                 
01607     if( error ) {
01608 
01609       fehler = get_error(1);
01610       if ( fehler < 0 ) 
01611         error = 0;
01612       else {
01613 #ifdef SKIP_RECOVER
01614         /* SKIP RECOVERY */
01615         printf("scan345: LOCK error\n");
01616         done = 1;
01617         break;
01618 #endif
01619         /* Cannot lock */
01620         if ( fehler == 60 ) {
01621           done = 1;
01622           break;
01623         }
01624       }
01625     }
01626     if ( mar_cmd == MDC_COM_STARTUP ) {
01627       done = 1;
01628     }
01629     break;
01630 
01631   case CMD_CHANGE:
01632     done = 0;
01633     if ( active ) break;
01634 
01635     /* Simple mode change ... */
01636     if ( mar_cmd == MDC_COM_MODE || mar_cmd == MDC_COM_STARTUP ) {
01637 
01638       /* Adjust PHI to modulo 360.0 deg */
01639       i = Modulo360();
01640 
01641       done = 1;
01642     }
01643 
01644     if ( error ) { 
01645       fehler = get_error( 1 );
01646       if ( fehler < 0 ) 
01647         error = 0;
01648       else {
01649         done = 1;
01650         scan_in_progress = 0;
01651         break;
01652       }
01653     }
01654 
01655     /* Single scan: start scan ... */
01656     if ( mar_cmd == MDC_COM_SCAN ) {
01657       /* Send command to controller */
01658       i = StartScan();
01659       done = 0;
01660     }
01661     /* COLLECT or ERASE: erase plate  ... */
01662     else if ( mar_cmd == MDC_COM_COLL ) {
01663       i = mar_erase();
01664       break;
01665     }
01666     break;
01667 
01668   case CMD_COLLECT:
01669     if ( exposure_start == 0 && totpass == stat_n_passes ) {
01670       exposure_start = time(NULL);
01671     }
01672 
01673     /* Task in progress */
01674     if ( active ) {
01675       /* Keep first xray_intensity */
01676       if ( expo_first ) {
01677         xray_start = stat_intensity;
01678         expo_first = 0;
01679       }
01680 
01681       done      = 0;
01682 
01683       /* 
01684        * Delta phi = 0.0 in TIME mode: 
01685        * follow progress using the elapsed time.
01686        */
01687       if ( com_phi_steps <  1 || cfg.use_phi == 0 ) {
01688         if ( exposure_start > 0 )
01689           pdone = 100 * ( time(NULL) - exposure_start )/stat_time;
01690         else
01691           pdone = 0;
01692       }
01693       /* 
01694        * Delta phi > 0.0 and TIME or DOSE mode:
01695        * follow progress using the phi movement.
01696        */
01697       else {
01698         if ( stat_phi >= stat_start_phi )
01699           ftmp = stat_dphi * ( stat_n_passes - totpass ) + stat_phi - stat_start_phi;
01700         else
01701           ftmp = stat_dphi * ( stat_n_passes - totpass );
01702         pdone = 100 * ftmp / ( stat_dphi * stat_n_passes );
01703                                         
01704       }
01705       stat_scanner_msg  = pdone;
01706                 
01707       if ( stat_n_passes > 1 ) {
01708         stat_oscil_msg = stat_scanner_msg;
01709       }
01710                    
01711       /* 
01712        * Abort data collection if X-rays drop below
01713        * minimum intensity level  
01714        */
01715       if ( stat_intensity < cur_intensmin &&
01716            cfg.use_xray == 0 ) {
01717         if ( dc_stop == 0 )
01718           marError( 1060, 0 );
01719         dc_stop = 1;
01720       }
01721                         
01722       /* Sum up current intensity */
01723       if ( expo_dosen < MAX_DOSE )
01724         expo_dose[expo_dosen]= stat_intensity;
01725       expo_dosen++;
01726       expo_doseavg      += stat_intensity;
01727       stat_xray_units   += stat_intensity;
01728       expo_doseend      =  stat_intensity;
01729       if ( expo_dosebeg > 99990 ) 
01730         expo_dosebeg    =  stat_intensity;
01731       max0( expo_dosemax, stat_intensity);
01732       min0( expo_dosemin, stat_intensity);
01733       intensity_counter++;
01734       break;
01735     }
01736 
01737     expo_first = 1;
01738 
01739     /* Task ended with an error */
01740     if ( error ) {
01741 
01742       fehler = get_error( 0 );
01743 
01744       if ( fehler < 0 ) 
01745         error = 0;
01746       else {
01747 
01748         /* Cannot CLOSE shutter... */
01749         if ( fehler == 238 ) {
01750           marError( fehler, 0);
01751         }
01752         /* Cannot OPEN shutter... */
01753         else if ( fehler == 215 || fehler == 241 ) {
01754           marError( fehler, 0);
01755         }
01756         /* Shutter is already OPEN... */
01757         else if ( fehler == 234 ) {
01758           marError( fehler, 0);
01759         }
01760         /* Stepper error */
01761         else if ( fehler == 239 ) {
01762           marError( fehler, 0);
01763         }
01764 
01765         done = 1;
01766         break;
01767       } /* End of fehler */
01768     }
01769 
01770     /*
01771      * Exposure finished... 
01772      */
01773     totpass--;
01774 
01775     /* This was not the last oscillation */
01776     if ( totpass > 0 && cfg.use_phi ) {
01777       /* Drive PHI back to start and redo exposure */
01778       if ( stop_image > 1 ) {
01779         done = 1;
01780         break;
01781       }
01782 
01783       stat_scanner_op = CMD_MOVE_PHI;
01784       i = mar_move_phi( (double)-stat_dphi );
01785       done = 0;
01786       break;
01787     }
01788 
01789     done = 1;
01790     break;
01791 
01792   case CMD_SCAN:                                /* Do a scan */
01793     
01794     //       printf("task=%x active=%d err=%d\n",esd_stb.task[CMD_SCAN],active,stat_task_error);
01795 
01796     /* Task in progress */
01797     if ( active ) {
01798       if ( maximum_pixels > 0 && stat_pixels < maximum_pixels ) {
01799         pdone = (int)(100*stat_pixels/(float)maximum_pixels);
01800       }
01801       else if ( stat_pixels >= maximum_pixels && pdone > 50 )
01802         pdone = 100;
01803       else
01804         pdone = 0;
01805 
01806       stat_scanner_msg = pdone;
01807       break;
01808     }
01809 
01810     /* SCAN finished ... */
01811 
01812     scan_started                = 0;
01813 
01814     /* ERROR ending ... */      
01815     if ( error ) {
01816       fehler = get_error( 0 );
01817                         
01818       if ( fehler < 0 ) {
01819         error = 0;
01820       }
01821       else {
01822 
01823         /* Terminate data collection! */
01824         marError( fehler, 0 );
01825         scan_in_progress= 0;
01826         done            = 1;
01827         if ( mar_cmd == MDC_COM_SCAN )  break;
01828         /* Abort queued or active exposure */
01829         mar_number      = CMD_ABORT;
01830         mar_mode        = CMD_COLLECT;
01831         mar_par1        = mar_par2 = 0;
01832         if( 0 == mar_command( )) return( 0 );
01833         break;
01834       } /* End of fehler */
01835     }
01836 
01837     done                = 1;
01838     pdone               = 0;
01839     stat_scanner_msg= 100;
01840 
01841     break;
01842 
01843   case CMD_SET:                         /* Commands without actions */
01844   case CMD_ION_CHAMBER:
01845     done = 1;
01846     break;
01847 
01848   default:
01849     marError( 999, task );
01850     done = 1;
01851     break;
01852   }
01853 
01854   /*
01855    * End of cases
01856    */
01857 
01858   last_xray_shutter = stat_xray_shutter;
01859                                 
01860   time( &now ); 
01861   if ( done ) {
01862     stat_scanner_msg     = MAR_CONTROL_IDLE;
01863     stat_scanner_op      = MAR_CONTROL_IDLE;
01864     stat_scanner_control = MAR_CONTROL_IDLE;
01865 
01866     emit print_message(QString("scan345: Task %1 ENDED   at %2\n").arg(cmdstr[ stat_task_number ]).arg((char *)ctime( &now )));
01867     
01868     if ( stat_task_number == CMD_SCAN ) {
01869       emit scan_finished();
01870     } else if (stat_task_number == CMD_ERASE) {
01871       emit erase_finished();
01872     } else {
01873       emit task_finished();
01874     }
01875 
01876     if ( verbose )
01877       emit print_message(QString("scan345: Task %1 ENDED   at %2\n").arg(cmdstr[ stat_task_number ]).arg((char *)ctime( &now )));
01878   } else {
01879     stat_scanner_control = MAR_CONTROL_ACTIVE;
01880     if ( time(NULL) - last > 1 ) {
01881       //       printf("%3d%% complete\n", stat_scanner_msg);
01882 
01883       emit print_message(QString("scan345: Task %1 %2 % complete\n").arg(cmdstr[ stat_task_number ]).arg(stat_scanner_msg));
01884       
01885       if ( verbose > 1 )
01886         emit print_message(QString().sprintf("scan345: Task %s %3d %% complete\n",
01887                                              cmdstr[ stat_task_number ], stat_scanner_msg));
01888       last = time( NULL );
01889     }
01890   }
01891 
01892   /* 
01893    * Version 2.2: Are there some more erase cycles?
01894    */
01895   if ( done && com_scan_add && task == CMD_SCAN ) {
01896     if ( stdout != NULL ) {
01897       emit print_message(QString().sprintf("scan345: %d more SCAN%s to add ...\n", com_scan_add, com_scan_add > 1 ? "S":""));
01898       fflush( stdout );
01899     }
01900     if ( verbose )
01901       emit print_message(QString().sprintf("scan345: %d more SCAN%s to add ...\n", com_scan_add, com_scan_add > 1 ? "S":""));
01902     com_scan_add--;
01903     mar_cmd = MDC_COM_SCAN;
01904     done = 0;
01905     /* Start next erase command */
01906     i = mar_erase();
01907   }
01908   if ( done && com_scan_erase && ( task == CMD_SCAN || task == CMD_ERASE ) ) {
01909     if ( stdout != NULL ) {
01910       emit print_message(QString().sprintf("scan345: %d more ERASE cycle%s to go ...\n", 
01911                                            com_scan_erase, com_scan_erase > 1 ? "s":"" ));
01912       fflush( stdout );
01913     }
01914     if ( verbose )
01915       emit print_message(QString().sprintf("scan345: %d more ERASE cycle%s to go ...\n", 
01916                                            com_scan_erase, com_scan_erase > 1 ? "s":"" ));
01917     com_scan_erase--;
01918     mar_cmd = MDC_COM_ERASE;
01919     done = 0;
01920     /* Start next erase command */
01921     i = mar_erase();
01922   }
01923 
01924   return ( (int)done); 
01925 }
01926  
01927 /******************************************************************
01928  * Function: mar_lock
01929  ******************************************************************/
01930 int
01931 MarHW::mar_lock()
01932 {
01933   int           i;
01934 
01935   if ( stat_plate_locked ) return 1;
01936 
01937   /* Try SERVO_SPEED 0 */
01938   if ( stat_lock_permit != 0 ) {
01939     sprintf( str, "scan345: IP still spinning. Halting plate ...\n" );
01940     //     fprintf( fpout, str );
01941     emit print_message( str );
01942     sprintf ( mar_str, "servo_speed 0\r");
01943     if( 0 == mar_command( )) return( 0 ); 
01944     for ( i=0; i<2; i++ ) {
01945       sleep ( 1 );
01946       get_status();
01947     }
01948   }
01949 
01950   if ( stat_lock_permit != 0 ) {
01951     sprintf( str, "scan345: IP still spinning. Cannot lock plate ...\n" );
01952     return 0;
01953   }
01954 
01955   sprintf( str, "scan345: Locking plate...\n" );
01956   //   fprintf( fpout, str );
01957   emit print_message( str );
01958 
01959   mar_number            = CMD_LOCK;
01960   mar_mode      = 1;
01961   mar_par1      = cfg.prelock_speed;
01962   mar_par2      = cfg.lock_speed;
01963   mar_par3      = 0;
01964   mar_par4      = 0;
01965   mar_par5      = 0;
01966   mar_str[0]    = '\0';
01967   if( 0 == mar_command( )) return( 0 ); 
01968 
01969   sleep( 1 );
01970 
01971   return 1;
01972 }
01973 
01974 /******************************************************************
01975  * Function: mar_servo
01976  ******************************************************************/
01977 int
01978 MarHW::mar_servo()
01979 {
01980   int           i;
01981   static int    ntimes = 0;
01982 
01983   /* Servo system is not yet ready, keep looking ... */
01984   if ( esd_stb.servo_state != 0 && ntimes < 30 ) {
01985     ntimes++;
01986     if ( ntimes < 30 ) {
01987       sprintf( str, "scan345: Waiting for SERVO system ...\n");
01988       emit print_message( str);
01989       sleep( 1 );
01990       i=mar_servo();
01991       return 0;
01992     }
01993     /* After 30 seconds not READY: here we have a problem */
01994     ntimes = 0;
01995 
01996     marError( 1001, esd_stb.servo_state);
01997 
01998     /* Close socket */
01999     for ( i=0; i<4; i++ ) {
02000       if ( net_close( i ) ) {
02001         sprintf( str, "scan345: socket %d closed ...\n",i+1);
02002         emit print_message( str );
02003       }
02004     }
02005     netcontrol = 0;
02006     return 0;
02007   }
02008 
02009   sprintf( str, "scan345: SERVO system READY ...\n");
02010   emit print_message(str);
02011 
02012   /* SERVO system was successfully initialized, proceed to:
02013    * a) LOCK IP
02014    * b) Change mode to default
02015    */
02016 
02017   /* Lock plate */
02018   i=mar_lock();
02019 
02020   /* Are we done ? */
02021   if ( esd_stb.scanmode > 0 && esd_stb.scanmode < 9 ) {
02022 
02023     /* Adjust PHI to modulo 360.0 */
02024     i = Modulo360();
02025     return 1;
02026   }
02027 
02028   /* ... not yet: go to defined scan mode */
02029   sprintf( str, "scan345: Initializing default scanmode ...\n" );
02030   emit print_message(str );
02031 
02032   return 1;
02033 }
02034 
02035 /******************************************************************
02036  * Function: mar_initial_status
02037  ******************************************************************/
02038 void
02039 MarHW::mar_initial_status()
02040 {
02041   stat_scanmode         = 0;
02042   stat_omega                    = 0.0;
02043   stat_phibeg           = 0.0;
02044   stat_dphi             = 1.0;
02045   stat_n_images                 = 1;
02046   stat_n_passes                 = 1;
02047   stat_time                     = 60;
02048   stat_scanner_op       = MAR_CONTROL_IDLE;
02049   stat_scanner_msg      = MAR_CONTROL_IDLE;
02050   stat_scanner_control  = MAR_CONTROL_IDLE;
02051   stat_xray_shutter     = SHUTTER_IS_CLOSED;
02052   stat_fname[0]         = '\0';
02053   strcpy( stat_dir,       working_dir );
02054   memset( (char *)stat_gap, 0, 8*sizeof(int) );
02055 
02056 }
02057 
02058 /******************************************************************
02059  * Function: marError = prints error numbers of errors
02060  ******************************************************************/
02061 void
02062 MarHW::marError( int err_no, int idata ) 
02063 {
02064   char    s1[128],s2[128], s3[64], s4[128];
02065   char    *cptr;
02066   char    timestr[26];
02067   int     nl=1;
02068   int     status = 0;
02069 
02070   time(&tick);
02071   cptr = (char *) ctime(&tick);
02072 
02073   /* Clear s1, s2 ...*/
02074   strcpy( s1, "" );
02075   strcpy( timestr, "" );
02076 
02077   /* Write error number... */
02078   sprintf( s1, "scan345: Error no. %d",err_no );
02079   emit print_message(QString().sprintf( "%s\n", s1 ));
02080 
02081   /* Write current time ... */
02082   strncpy( timestr, cptr, 24);
02083   timestr[24]='\0';
02084   timestr[3]='-';
02085   timestr[7]='-';
02086   sprintf( s1, "scan345: Current time  is: %s", timestr );
02087   emit print_message(QString().sprintf( "%s\n", s1 ));
02088 
02089   /* Write current image (during data collection only) ... */
02090   if ( mar_cmd == MDC_COM_COLL || 
02091        mar_cmd == MDC_COM_SCAN ) {
02092     sprintf( s4, "%s", stat_fname );
02093     sprintf( s1, "scan345: Current image is: %s", s4 );
02094     emit print_message(QString().sprintf( "%s\n", s1 ));
02095   }
02096   else
02097     strcpy( s4, "" );
02098 
02099   /* Reset strings ... */
02100   strcpy( s1, "" );
02101   strcpy( s2, "" );
02102   strcpy( s3, "" );
02103 
02104   /* Write error message ... */
02105   if ( err_no > 998 ) goto OTHER_ERRORS;
02106 
02107   /*
02108    * ESD errors ...
02109    */
02110 
02111   if ( err_no == 225 ) {
02112     if ( idata == 0 )
02113       sprintf(s1, "Cannot LEAVE distance reference position !!!");
02114     else
02115       sprintf(s1, "Distance reference position touched ...");
02116   }
02117   else {
02118     sprintf(s1, "%s", err_msg[fehler_index].msg);
02119   }
02120   nl    = 1;
02121   status        = 1;
02122 
02123   goto END_ERRORS;
02124 
02125   /*
02126    * Miscellaneous other errors 
02127    */
02128 
02129  OTHER_ERRORS:
02130 
02131   switch( err_no ) {
02132 
02133     /* 
02134      *  Fatal errors...
02135      */
02136   case 1000:
02137     sprintf(s1,"Error sending command to mar controller.");
02138     sprintf(s2,"Command number: %d", idata );
02139     status = 1;
02140     nl     = 2;
02141     break;
02142 
02143   case 1001:
02144     sprintf(s1, "SERVO system cannot be INITIALIZED");
02145     sprintf(s2 ,"Giving up. NO more scanner CONTROL"); 
02146     sprintf(s3 ,"Please retry by switching off the scanner ..."); 
02147     status = 1;
02148     nl     = 3;
02149     break;
02150 
02151   case 1112:
02152     sprintf(s1 ,"Error writing image array");
02153     status = 1;
02154     break;
02155 
02156   case 1115:
02157     sprintf(s1 ,"Cannot write image header");
02158     status = 1;
02159     break;
02160 
02161   case 1050:
02162     sprintf(s1,"SHUTTER did not work properly.");
02163     sprintf(s2,"Abandoning data collection...");
02164     status = 1;
02165     nl     = 2;
02166     break;
02167 
02168   case 1070:
02169     sprintf(s1,"Could not recover from previous errors");
02170     sprintf(s2,"after 5 trials.");
02171     status = 1;
02172     nl     = 2;
02173     break;
02174 
02175   case 1020:
02176     sprintf(s1, "Not enough disk space left in %s!", stat_dir);
02177     sprintf(s2, "Aborting data collection ...");
02178     status = 1;
02179     nl     = 2;
02180     break;
02181 
02182     /* 
02183      *  WARNINGS ...
02184      */
02185 
02186   case 1080:
02187     if (idata==0)
02188       sprintf(s1,"Shutter did not open during exposure");
02189     else
02190       sprintf(s1,"Shutter did not close at end of exposure");
02191     sprintf(s2, "Trying to fix shutter by doing 5 x open/close");
02192     nl     = 2;
02193     status = 0;
02194     break;
02195 
02196   case 1120:
02197     sprintf(s1 ,"Cannot open spiral file %s",spiral_file);
02198     status = 0;
02199     break;
02200 
02201   case 1121:
02202     sprintf(s1 ,"Cannot write spiral header");
02203     status = 0;
02204     break;
02205 
02206     /* 
02207      *  Informations...
02208      */
02209   case 1030:
02210     sprintf(s1, "The Image Plate has been exposed to X-rays!");
02211     sprintf(s2, "Please, ERASE plate before next exposure...");
02212     status = 2;
02213     nl     = 2;
02214     break;
02215 
02216   case 1010:
02217     sprintf(s1, "Waiting for X-rays...");
02218     status = 2;
02219     nl     = 1;
02220     break;
02221 
02222   case 1060:
02223     sprintf(s1 ,"X-ray reading too low (%1.2f). ", stat_intensity);
02224     sprintf(s2 ,"Check generator or beam shutter!!!");
02225     sprintf(s3 ,"Data collection will end after current image...");
02226     status = 2;
02227     nl     = 3;
02228     break;
02229 
02230   case 1100:
02231     sprintf(s1, "Cannot open nb_code!");
02232     status = 1;
02233     nl     = 1;
02234     break;
02235 
02236   case 1101:
02237     sprintf(s1, "No scan modes found in nb_cde...");
02238     status = 1;
02239     nl     = 1;
02240     break;
02241 
02242   case 1102:
02243     sprintf(s1, "Something wrong with byteorder in nb_code");
02244     status = 1;
02245     nl     = 1;
02246     break;
02247 
02248   case 1103:
02249     sprintf(s1, "Scanner serial number in nb_code differs from config");
02250     status = 2;
02251     nl     = 1;
02252     break;
02253 
02254   case 1105:
02255     sprintf(s1, "No suitable scanning mode found in nb_code");
02256     status = 1;
02257     nl     = 1;
02258     break;
02259 
02260   case 1110:
02261     sprintf(s1 ,"Cannot create image file %s",image_file);
02262     status = 2;
02263     break;
02264 
02265   case 1111:
02266     sprintf(s1 ,"Cannot open image file %s",image_file);
02267     status = 2;
02268     break;
02269     /* 
02270      *  Error sending commands to controller ... 
02271      */
02272   case 999:
02273     sprintf(s1 ,"Task %d NOT implemented !!!",idata);
02274     break;
02275   default:
02276     break;
02277   }
02278 
02279  END_ERRORS:
02280 
02281   /* Write to output ... */
02282   emit print_message(QString().sprintf( "scan345: %s\n", s1 ));
02283 
02284   if (nl>1) {
02285     emit print_message(QString().sprintf( "        %s\n", s2 ));
02286   }
02287   if (nl>2) {
02288     emit print_message(QString().sprintf( "        %s\n", s3 ));
02289   }
02290 
02291   mar_error = err_no;
02292 }
02293                                   
02294 /******************************************************************
02295  * Function: StartScan
02296  ******************************************************************/
02297 int
02298 MarHW::StartScan()
02299 {
02300   int   i;
02301 
02302   /* Is there enough disk space ? */
02303   if ( NotEnoughDiskSpace() ) {
02304     return 0;
02305   }
02306 
02307   if ( intensity_counter > 0 )
02308     sum_xray_units = stat_xray_units/intensity_counter;
02309 
02310   /* Set to 0 only in last scan after adding previous ones */
02311   if ( com_scan_add == 0 ) {
02312     stat_xray_units   = 0.0;
02313     intensity_counter =   0;
02314 
02315     if ( expo_dosen > 0 ) {
02316       expo_doseavg /= expo_dosen;
02317 
02318       expo_dosesig = 0.0;
02319       /* Get sigma for DOSE */
02320       for ( i=0; i<expo_dosen; i++ ) {
02321         ftmp =  expo_dose[i]/1000. - expo_doseavg;
02322         expo_dosesig += ( ftmp*ftmp ); 
02323       }
02324       expo_dosesig = sqrt( expo_dosesig / expo_dosen );
02325     }
02326 
02327     /* Keep last X-ray reading */
02328     if ( stat_intensity > 0.0 && xray_start > -999. && cfg.use_xray == 0) {
02329       ftmp = xray_start/stat_intensity;
02330 
02331       /* TIME mode: reset exposure time to used time */
02332       if ( stat_mode == ARG_TIME )
02333         exposure_time = (int)stat_time;
02334       else {
02335         exposure_time = time(NULL)-exposure_start;
02336       }
02337     }
02338   }
02339 
02340   memset( (char *)stat_gap, 0, sizeof(int)*8);
02341 
02342   totpass       = stat_n_passes;
02343   stat_phiend   = stat_phi;
02344   stat_start_phi        = stat_phi;
02345   scan_error    = 0;
02346   current_pixel = 0;
02347   stat_scanner_msg= 100;
02348   stat_scanner_msg= 0;
02349   exposure_start  = 0;
02350 
02351 
02352   /* Add final slash to directory path */
02353   if ( stat_dir[ strlen(com_dir) - 1] != '/' )
02354     strcat( com_dir, "/" );
02355 
02356   sprintf(str,"%s%s",com_dir,com_root);
02357 
02358   /* When summing up scans, append a,b,c... to image number */
02359   if ( com_scan_add || stat_scan_add ) {
02360     sprintf(spiral_file,"%s.%c.s"  , str, (char)(stat_scan_add+97));
02361   }
02362   else
02363     sprintf(spiral_file,"%s.s"  , str);
02364 
02365   if ( com_format == OUT_MAR )
02366     sprintf(image_file, "%s.mar", str );
02367   else if ( com_format == OUT_CBF )
02368     sprintf(image_file, "%s.cbf", str );
02369   else if ( com_format == OUT_CIF )
02370     sprintf(image_file, "%s.cif", str );
02371   else if ( com_format == OUT_PCK )
02372     sprintf(image_file, "%s.pck", str );
02373   else if ( com_format == OUT_IMAGE )
02374     sprintf(image_file, "%s.image", str );
02375 
02376   sprintf( str, "%1.0f", (float)(cur_diameter/cur_pixelsize));
02377   if ( com_format == OUT_MAR || com_format == OUT_CIF || com_format == OUT_CBF )
02378     strcat( image_file, str );
02379   strcat(spiral_file, str );
02380 
02381   if ( expo_dosen < 1  ) {
02382     sum_xray_units      = stat_intensity;
02383     expo_doseavg        = stat_intensity;
02384     expo_dosemin        = expo_doseavg;
02385     expo_dosemax        = expo_doseavg;
02386     expo_dosesig        = 0.0;
02387     expo_dosen          = 1;
02388   }
02389 
02390   erase_lamps_ok        = 0;
02391   stat_scanner_msg= 0;
02392   scan_started  = 1;
02393 
02394   /* Send command to controller */
02395   com_scanmode  = stat_scanmode;
02396   stat_scanner_op = CMD_SCAN;
02397   mar_number    = CMD_SCAN;
02398   mar_mode      = cfg.roff[ stat_scanmode ];
02399   mar_par1      = (int)cfg.flags;
02400   mar_par2      = (int)cfg.adcoff[ stat_scanmode ];/* ADC offset */
02401   mar_par3      = 0;
02402 
02403   i = mar_command( );
02404 
02405   /* Start data readout */   
02406   if ( mar_start_scan_readout(stat_scan_add) == 0 ) {
02407     printf("scan345: ERROR: SCAN could not be started\n");
02408     marTask( MDC_COM_ABORT, 0.0 );
02409   }
02410 
02411   op_doseavg    = expo_doseavg;
02412   op_dosemin    = expo_dosemin;
02413   op_dosemax    = expo_dosemax;
02414   op_dosesig    = expo_dosesig;
02415   op_dosebeg    = expo_dosebeg;
02416   op_doseend    = expo_doseend;
02417   op_dosen      = expo_dosen;
02418 
02419   stat_scan_add++;
02420 
02421   /* Reset DOSE counters for exposure */
02422   if ( com_scan_add == 0 ) {
02423     expo_doseavg    = expo_dosesig = 0.0;
02424     expo_dosemin    = expo_dosebeg = 99999.0;
02425     expo_dosemax    = expo_doseend = 0.0;
02426     expo_dosen      = 0;
02427     memset( (char *)expo_dose, 0, sizeof(int)*MAX_DOSE );
02428   }
02429 
02430   ict1          = ict2 = 0;
02431 
02432   return i;
02433 }
02434 
02435 /******************************************************************
02436  * Function: Modulo360
02437  ******************************************************************/
02438 int 
02439 MarHW::Modulo360()
02440 {
02441   int   i;
02442   int   steps;
02443   float ftmp, real_phi;
02444 
02445   real_phi   = (float)((float)esd_stb.stepper[5][STEPPER_IST]/ cfg.phi_steps);
02446 
02447   /* Adjust PHI to modulo 360.0 deg */
02448   if ( real_phi < 0.0 || real_phi >= 360.0 ) {
02449     ftmp                = real_phi;
02450     while( ftmp <    0.0) 
02451       ftmp += 360.;
02452     while( ftmp >= 360.0) 
02453       ftmp -= 360.;
02454 
02455     sprintf(str, "scan345: Adjusting PHI (%1.3f -> %1.3f)\n",real_phi,ftmp);
02456     emit print_message( str );
02457 
02458     steps       = (ftmp+0.5 *(1./cfg.phi_steps))*cfg.phi_steps;
02459 
02460     mar_number          = CMD_SET;
02461     mar_mode    = ARG_WRITE;
02462     mar_par1    = 80;
02463     mar_par2    = steps;
02464     i = mar_command( );
02465 
02466     stat_phi = ftmp;
02467 
02468     /* Waste some time */
02469     i = 0;
02470     sleep(1);
02471     return 1;
02472   }
02473 
02474   return 0;
02475 }
02476 
02477 /******************************************************************
02478  * Function: print_msg = prints output on MESSAGE port
02479  ******************************************************************/
02480 void MarHW::print_msg(char *s)
02481 {
02482   int             i,j,ival,jval;
02483   char            b[8],op[128];
02484   char            *sp;
02485   static char     erledigt[4] = { 0, 0, 0, 0 };
02486 
02487 
02488   /* Return if scanner is not available */
02489   //   if ( fpspy == NULL ) return;
02490 
02491   op[0] = '\0';
02492 
02493   sp = strstr( s, "MESS" );
02494   if ( sp == NULL )
02495     strcpy( op, s );
02496   else {
02497     j = strlen( s ) - strlen( sp );
02498     /* There was text before string MESS: print it first */
02499     if ( j > 0 ) {
02500       strcpy( op, s);
02501       op[ j ] = '\n';
02502       op[ j+1 ] = '\0';
02503       emit spy_message(op);
02504     }
02505     /* Chop of MESS of remaining part of the string */
02506     strcpy( op, sp+4);
02507   }
02508 
02509   /* Chop off blanks at end */
02510   j = strlen( op )-1;
02511   for ( i=j; i>0; i-- ) {
02512     if ( op[i] != '\n' && op[i] != ' ' ) break;
02513     op[i] = '\0';
02514   } 
02515   op[i+1] = '\n';
02516   op[i+2] = '\0';
02517 
02518   emit spy_message(op);
02519 
02520   /* Check for SETPARAMETER */
02521   if (  ( sp = strstr( op, "SETPARAM" ) ) == NULL ) return;
02522   if ( strlen( sp ) < 44 ) return;
02523 
02524   sscanf( sp+17, "%d", &ival ); 
02525   sscanf( sp+34, "%d", &jval ); 
02526 
02527   op[0] = '\0';
02528   if ( ival == 95 && !erledigt[0]) {
02529     sprintf( op, "scan345: ESD Controller no.\t\t%d\n",jval);
02530     erledigt[0] = 1;
02531   }
02532   else if ( ival == 97 && !erledigt[1]) {
02533     sprintf( op, "scan345: ESD Firmware version\t\t%d\n",jval);
02534     erledigt[1] = 1;
02535   }
02536   else if ( ival == 278 && !erledigt[2]) {
02537     sprintf( op, "scan345: ESD RT-OS    version\t\t%d\n",jval);
02538     erledigt[2] = 1;
02539   }
02540   else if ( ival == 279 && !erledigt[3]) {
02541     memcpy( b, (char *)&jval, 4);
02542 #if ( __linux__ || __osf__ )
02543     swaplong( b, 4 );
02544 #endif
02545     b[4] = '\0'; 
02546     sprintf( op, "scan345: ESD Servo    version\t\t%s\n",b);
02547     erledigt[3] = 1;
02548   }
02549   if ( strlen( op ) ) {
02550     emit print_message(op); 
02551   }
02552 }
02553 
02554 /******************************************************************
02555  * Function: get_error = prints error numbers from status block
02556  ******************************************************************/
02557 int 
02558 MarHW::get_error(int mode)
02559 {
02560   int           j,i,k,e;
02561   int           result=0;
02562   STB_MSG               msg;
02563 
02564   fehler_index = 0;
02565 
02566   for ( i=0; i<10; i++ ) {
02567     if ( esd_stb.errors[i] == 0 ) break;
02568 
02569     e = esd_stb.errors[i];
02570     memcpy ( (char *)&msg, (char *)&e, 4 );
02571     if ( msg.mclass == 3 ) continue;
02572 
02573     j = 1;
02574     while ( err_msg[j].task < 99  ) { 
02575       if ( msg.number == err_msg[j].number ) break;
02576       j++;
02577     }
02578     if ( err_msg[j].task == 99 ) {
02579       sprintf( str, "scan345: ERROR %4d %4d %4d\n",
02580                msg.task,msg.mclass,msg.number );
02581       emit print_message(str);
02582     }
02583     else {
02584       fehler_index = j;
02585       sprintf( str, "scan345: ERROR %4d %4d %4d: %s\n",
02586                msg.task,msg.mclass,msg.number,err_msg[j].msg );
02587       emit print_message(str);
02588     }
02589 
02590     /* Get any errors excluded ? */
02591     if ( cfg.use_error[0] > 0 ) {
02592       for ( k=1; k<cfg.use_error[0]; k++ ) {
02593         if ( msg.number == cfg.use_error[k] ) {
02594           sprintf( str, "scan345: Ignoring error # %d ...\n",msg.number);
02595           emit print_message(str);
02596           result = -1;
02597           break;
02598         }
02599       }
02600     }
02601 
02602     if ( result != -1 ) {
02603       if ( msg.mclass == 1 ) 
02604         result = msg.number;
02605       if ( result == 0 && msg.mclass == 3 ) 
02606         result = msg.number;
02607     }
02608   }
02609 
02610   if ( result > 0 && mode ) {
02611     marError( result, 0 );
02612   }
02613 
02614   return result;
02615 }
02616 
02617 /******************************************************************
02618  * Function: mar_start_expo = starts EXPOSURE
02619  ******************************************************************/
02620 int     
02621 MarHW::mar_start_expo() 
02622 {
02623   time( &now );
02624 
02625   /* Exposure is already active: do not go on */
02626   if ( esd_stb.task[CMD_COLLECT] & 0x02 ) {
02627     emit print_message("scan345: Exposure is still active. Igoring command ...\n");
02628     return 1;
02629   }
02630 
02631   /* One exposure is already queued: do not go on */
02632   if ( esd_stb.task[CMD_COLLECT] & 0x10 ) {
02633     emit print_message("scan345: Exposure is already queued. Igoring command ...\n");
02634     return 1;
02635   }
02636 
02637   /* Start with an exposure */
02638   mar_cmd               = MDC_COM_COLL;
02639 
02640   /* Compose IPS command */
02641   mar_number    = CMD_COLLECT;
02642   mar_mode      = com_mode;
02643   mar_par1      = com_phi_steps;
02644   mar_par2      = stat_units;
02645   mar_par3      = cfg.shutter_delay;    
02646   if ( mar_mode == ARG_DOSE ) mar_par3 = 0;
02647   mar_par4      = 0;
02648   mar_par5      = 0;
02649   mar_str[0]    = '\0';
02650   if ( cfg.use_phi == 0 )
02651     mar_par2 = 1;
02652 
02653   open_shutter_counter  = 0;
02654   close_shutter_counter         = 0;
02655   erase_start           = -1;
02656   stat_xray_units       = 0.0;
02657 
02658   if ( totpass == stat_n_passes ) {
02659     /* Set exposure time to stat_time*/
02660     exposure_time = (int)stat_time;
02661     if ( stat_mode == ARG_TIME )
02662       emit print_message(QString().sprintf( "scan345: EXPOSE: %d * PHI = %1.3f -> %1.3f @ %1.0f sec.\n",
02663                                             com_phiosc,stat_phi,stat_phi+com_dphi,com_time));
02664     else
02665       emit print_message(QString().sprintf( "scan345: EXPOSE: %d * PHI = %1.3f -> %1.3f @ %1.0f counts\n",
02666                                             com_phiosc,stat_phi,stat_phi+com_dphi,stat_units));
02667     if ( stat_n_passes > 1 )
02668       emit print_message(QString().sprintf( "scan345:  1. oscillation\n"));
02669   }
02670   else
02671     emit print_message(QString().sprintf( "scan345: %2d. oscillation\n",stat_n_passes - totpass+1));
02672 
02673   stat_scanner_op = CMD_COLLECT;
02674 
02675   /* Send command to scanner */
02676   if ( stat_units >  0 ) {
02677     if( 0 == mar_command( )) return( -1 ); 
02678   }
02679 
02680   return(1);
02681 }