The VisAO Camera
FocusMotorCtrl.cpp
Go to the documentation of this file.
1 /************************************************************
2 * FocusMotorCtrl.cpp
3 *
4 * Author: Jared R. Males (jrmales@email.arizona.edu)
5 *
6 * Definitions for the VisAO focus stage stepper motor controller.
7 *
8 * Developed as part of the Magellan Adaptive Optics system.
9 ************************************************************/
10 
11 /** \file FocusMotorCtrl.cpp
12  * \author Jared R. Males
13  * \brief Definitions for the focus stage stepper motor controller.
14  *
15 */
16 
17 #include "FocusMotorCtrl.h"
18 
19 namespace VisAO
20 {
21 
22 FocusMotorCtrl::FocusMotorCtrl( std::string name, const std::string& conffile) throw (AOException) : VisAOApp_standalone(name, conffile)
23 {
24  initapp();
25 }
26 
27 FocusMotorCtrl::FocusMotorCtrl( int argc, char**argv) throw (AOException) : VisAOApp_standalone(argc, argv)
28 {
29  //std::cout << "constructed\n";
30  initapp();
31 }
32 
33 
34 
36 {
37  //std::cout << "initing\n";
38 
39  std::string pathtmp;
40  std::string visao_root = getenv("VISAO_ROOT");
41 
42  setup_fifo_list(10);
43  setup_baseApp(1, 1, 1, 0, false);
44 
45  //Set up the dioserver channel numbers
46  try
47  {
48  dioch_enable = (int)(ConfigDictionary())["dioch_enable"];
49  _logger->log(Logger::LOG_LEV_INFO, "dioserver channel for setting enable (dioch_enable) set to %i.", dioch_enable);
50  }
51  catch(Config_File_Exception)
52  {
53  _logger->log(Logger::LOG_LEV_FATAL, "dioserver channel for setting enable (dioch_enable) not set in config file.");
54  throw;
55  }
56  try
57  {
58  dioch_dir = (int)(ConfigDictionary())["dioch_dir"];
59  _logger->log(Logger::LOG_LEV_INFO, "dioserver channel for setting direction (dioch_dir) set to %i.", dioch_dir);
60  }
61  catch(Config_File_Exception)
62  {
63  _logger->log(Logger::LOG_LEV_FATAL, "dioserver channel for setting direction (dioch_dir) not set in config file.");
64  throw;
65  }
66  try
67  {
68  dioch_step = (int)(ConfigDictionary())["dioch_step"];
69  _logger->log(Logger::LOG_LEV_INFO, "dioserver channel for stepping (dioch_step) set to %i.", dioch_step);
70  }
71  catch(Config_File_Exception)
72  {
73  _logger->log(Logger::LOG_LEV_FATAL, "dioserver channel for stepping (dioch_step) not set in config file.");
74  throw;
75  }
76 
77  try
78  {
79  dioch_pwr = (int)(ConfigDictionary())["dioch_pwr"];
80  _logger->log(Logger::LOG_LEV_INFO, "dioserver channel for controller power (dioch_pwr) set to %i.", dioch_pwr);
81  }
82  catch(Config_File_Exception)
83  {
84  _logger->log(Logger::LOG_LEV_FATAL, "dioserver channel for controller power (dioch_pwr) not set in config file.");
85  throw;
86  }
87 
88  try
89  {
90  dioch_limpos = (int)(ConfigDictionary())["dioch_limpos"];
91  _logger->log(Logger::LOG_LEV_INFO, "dioserver channel for positive limit switch (dioch_limpos) set to %i.", dioch_limpos);
92  }
93  catch(Config_File_Exception)
94  {
95  _logger->log(Logger::LOG_LEV_FATAL, "dioserver channel for positive limit switch (dioch_limpos) not set in config file.");
96  throw;
97  }
98 
99  try
100  {
101  dioch_limhome = (int)(ConfigDictionary())["dioch_limhome"];
102  _logger->log(Logger::LOG_LEV_INFO, "dioserver channel for home limit switch (dioch_limhome) set to %i.", dioch_limhome);
103  }
104  catch(Config_File_Exception)
105  {
106  _logger->log(Logger::LOG_LEV_FATAL, "dioserver channel for home limit switch (dioch_limhome) not set in config file.");
107  throw;
108  }
109 
110  try
111  {
112  dioch_limneg = (int)(ConfigDictionary())["dioch_limneg"];
113  _logger->log(Logger::LOG_LEV_INFO, "dioserver channel for negative limit switch (dioch_limneg) set to %i.", dioch_limneg);
114  }
115  catch(Config_File_Exception)
116  {
117  _logger->log(Logger::LOG_LEV_FATAL, "dioserver channel for negative limit switch (dioch_limneg) not set in config file.");
118  throw;
119  }
120 
121 
122  //Set up the dio server paths
123  char fin[MAX_FNAME_SZ], fout[MAX_FNAME_SZ];
124  try
125  {
126  pathtmp = (std::string)(ConfigDictionary())["diofifo_path"];
127  }
128  catch(Config_File_Exception)
129  {
130  pathtmp = "fifos";
131  }
132  diofifo_path = visao_root + "/" + pathtmp + "/diofifo";
133  _logger->log(Logger::LOG_LEV_INFO, "Set diofifo_path: %s", diofifo_path.c_str());
134 
135  //Trying these without handlers
136  /**/
137  get_dio_fnames(fin, fout, (char *)diofifo_path.c_str(), dioch_enable);
138  set_fifo_list_channel(&fl, FIFOCH_ENABLE, 100,fin, fout, 0, 0);
139 
140  get_dio_fnames(fin, fout, (char *)diofifo_path.c_str(), dioch_dir);
141  set_fifo_list_channel(&fl, FIFOCH_DIR, 100,fin, fout, 0, 0);
142 
143  get_dio_fnames(fin, fout, (char *)diofifo_path.c_str(), dioch_step);
144  set_fifo_list_channel(&fl, FIFOCH_STEP, 100,fin, fout, 0, 0);
145 
146  get_dio_fnames(fin, fout, (char *)diofifo_path.c_str(), dioch_pwr);
147  set_fifo_list_channel(&fl, FIFOCH_PWR, 100,fin, fout, 0, 0);
148 
149  get_dio_fnames(fin, fout, (char *)diofifo_path.c_str(), dioch_limneg);
150  set_fifo_list_channel(&fl, FIFOCH_NEGL, 100,fin, fout, 0, 0);
151 
152  get_dio_fnames(fin, fout, (char *)diofifo_path.c_str(), dioch_limhome);
153  set_fifo_list_channel(&fl, FIFOCH_HOMESW, 100,fin, fout, 0, 0);
154 
155  get_dio_fnames(fin, fout, (char *)diofifo_path.c_str(), dioch_limpos);
156  set_fifo_list_channel(&fl, FIFOCH_POSL, 100,fin, fout, 0, 0);
157  /**/
158 
159  signal(SIGIO, SIG_IGN);
160 
161  try
162  {
163  step_ratio = (double)(ConfigDictionary())["step_ratio"];
164  _logger->log(Logger::LOG_LEV_INFO, "step ratio (step_ratio) set to %0.4f microns per step.", step_ratio);
165  }
166  catch(Config_File_Exception)
167  {
168  _logger->log(Logger::LOG_LEV_FATAL, "step ratio (step_ratio) not set in config file.");
169  throw;
170  }
171 
172  try
173  {
174  min_step_time = (double)(ConfigDictionary())["min_step_time"];
175  if(min_step_time < 1e-6) min_step_time = 1e-6;
176  _logger->log(Logger::LOG_LEV_INFO, "minimum step time (min_step_time) set to %0.3g seconds.", min_step_time);
177  }
178  catch(Config_File_Exception)
179  {
180  _logger->log(Logger::LOG_LEV_FATAL, "minimum step time (min_step_time) not set in config file.");
181  throw;
182  }
183  try
184  {
185  hw_dir = (int)(ConfigDictionary())["hw_dir"];
186  if(hw_dir > 0) hw_dir = 1;
187  else hw_dir = 0;
188  _logger->log(Logger::LOG_LEV_INFO, "hardware direction (hw_dir) set to %i.", hw_dir);
189  }
190  catch(Config_File_Exception)
191  {
192  hw_dir = 0;
193  _logger->log(Logger::LOG_LEV_INFO, "hardware direction (hw_dir) set to default %i.", hw_dir);
194  }
195 
196  try
197  {
198  sw_limits_only = (ConfigDictionary())["sw_limits_only"];
199  }
200  catch(Config_File_Exception)
201  {
202  sw_limits_only = 0;
203  }
204  _logger->log(Logger::LOG_LEV_INFO, "software limits only (sw_limits_only) set to %i.", sw_limits_only);
205 
206  #ifdef VISAO_SIMDEV
207  sw_limits_only = 1;
208  #endif
209 
210  try
211  {
212  sw_neg_limit = (ConfigDictionary())["sw_neg_limit"];
213  _logger->log(Logger::LOG_LEV_INFO, "software negative limit (sw_neg_limit) set to %f.", sw_neg_limit);
214  }
215  catch(Config_File_Exception)
216  {
217  _logger->log(Logger::LOG_LEV_FATAL, "Missing software negative limit (sw_neg_limit) in config file .");
218  throw;
219  }
220 
221  try
222  {
223  sw_pos_limit = (ConfigDictionary())["sw_pos_limit"];
224  _logger->log(Logger::LOG_LEV_INFO, "software positive limit (sw_pos_limit) set to %f.", sw_pos_limit);
225  }
226  catch(Config_File_Exception)
227  {
228  _logger->log(Logger::LOG_LEV_FATAL, "Missing software positive limit (sw_pos_limit) in config file .");
229  throw;
230  }
231 
232 
233  //Init the status board
234  statusboard_shmemkey = 6000;
236  {
238  _logger->log(Logger::LOG_LEV_ERROR, "Could not create status board.");
239  }
240  else
241  {
243  strncpy(bsb->appname, MyFullName().c_str(), 25);
244  bsb->max_update_interval = pause_time;
245  }
246 
247 
248  //Connect to other status boards for presets.
249  size_t sz;
250 
251  fw2sb = (VisAO::filterwheel_status_board*) attach_shm(&sz, STATUS_filterwheel2, 0);
252  fw3sb = (VisAO::filterwheel_status_board*) attach_shm(&sz, STATUS_filterwheel3, 0);
253  wsb = (VisAO::wollaston_status_board*) attach_shm(&sz, STATUS_wollaston, 0);
254  aosb = (VisAO::aosystem_status_board*) attach_shm(&sz, STATUS_aosystem, 0);
255 
256 
257  pthread_mutex_init(&dio_mutex, 0);
258 
259  std::string resp;
260 
261  pending_move = 0;
262  next_pos = 0;
263 
264  is_moving = false;
265  stop_moving = false;
266 
267  gettimeofday(&last_step_time, 0);
268 
269  if(init_vars)
270  {
271  try
272  {
273  cur_pos = (*init_vars)["cur_pos"];
274  }
275  catch(Config_File_Exception)
276  {
277  cur_pos = 0;
278  }
279  }
280 
281  homing = 0;
282  pos_limit_disabled = false;
283 
284 
285  try
286  {
287  home_pos = (double)(ConfigDictionary())["home_pos"];
288 
289  _logger->log(Logger::LOG_LEV_INFO, "home position (home_pos) set to %f.", home_pos);
290  }
291  catch(Config_File_Exception)
292  {
293  home_pos = 0.;
294  _logger->log(Logger::LOG_LEV_INFO, "home position (home_pos) set to %f.", home_pos);
295  }
296 
297 
298 }//void FocusMotorCtrl::initapp()
299 
300 FocusMotorCtrl::~FocusMotorCtrl()
301 {
302  save_init();
303 }
304 
306 {
307  std::string resp;
308  //int use_sw_limits = 0;
309  //Get limits here
310  //Check if 1 is forward, 0 is backward!!!!!!!!!!!!!!!!!
311 
312  if(!sw_limits_only)
313  {
314  pthread_mutex_lock(&dio_mutex);
315 
316  resp ="";
317  if(write_fifo_channel(FIFOCH_NEGL, "1", 2, &resp) < 0)
318  {
319  _logger->log(Logger::LOG_LEV_ERROR, "dioserver response error getting front limit ");
320  pthread_mutex_unlock(&dio_mutex);
321  neg_limit = 1;
322  return -1;
323  }
324 
325  neg_limit = (resp[0] == '0');
326 
327  resp = "";
328  if(write_fifo_channel(FIFOCH_HOMESW, "1", 2, &resp) < 0)
329  {
330  _logger->log(Logger::LOG_LEV_ERROR, "dioserver response error getting home switch");
331  pthread_mutex_unlock(&dio_mutex);
332  home_switch = 1;
333  return -1;
334  }
335 
336  home_switch = (resp[0] == '0');
337 
338  resp = "";
339  if(write_fifo_channel(FIFOCH_POSL, "1", 2, &resp) < 0)
340  {
341  _logger->log(Logger::LOG_LEV_ERROR, "dioserver response error in getting back limit");
342  pthread_mutex_unlock(&dio_mutex);
343  pos_limit = 1;
344  return -1;
345  }
346  pthread_mutex_unlock(&dio_mutex);
347  pos_limit = (resp[0] == '0');
348  }
349 
350  if(cur_pos <= sw_neg_limit)
351  {
352  neg_limit = true;
353  }
354  else
355  {
356  if(sw_limits_only) neg_limit = false;
357  }
358 
359 
360  if(cur_pos >= sw_pos_limit)
361  {
362  pos_limit = true;
363  }
364  else
365  {
366  if(sw_limits_only) pos_limit = false;
367  }
368 
369  if(sw_limits_only)
370  {
371  if(cur_pos > home_pos - 2. && cur_pos < home_pos + 2.) home_switch = 1;
372  else home_switch = 0;
373  }
374 
375  //Always stop at neg limit
376  //unless homing, then turn around
377  if(!cur_dir && neg_limit)
378  {
379  if(homing && homing !=4 ) //If we're homing, but not neg homing
380  {
381  return set_direction(1); //homing the wrong way, turn arround.
382  }
383 
384  homing = 0;
385  stop_moving = true;
386  return 0;
387  }
388 
389  //Moving positive and at pos limit
391  {
392  if(homing && homing!=5) //If we're homing, but not pos homing
393  {
394  return set_direction(0);//homing the wrong way, turn around
395  }
396 
397  homing = 0;
398  stop_moving = true;
399  return 0;
400  }
401 
402  //If instead the back limit is disabled and we're homing backwards for any reason, then stop.
403  if(pos_limit_disabled && homing && !cur_dir)
404  {
405  stop_moving = true;
406 
407  homing = 0;
408  }
409 
410  //O.K. to keep moving.
411  if(!homing) return 0;
412 
413  //Initial homing
414  if(homing == 1)
415  {
416  if(home_switch)
417  {
418  homing = 3; //Go directly to tertiary homing
419  return set_direction(0); //move backward, continue.
420  }
421  else
422  {
423  homing = 2;
424  return 0;
425  }
426  }
427 
428  //Main homing, moving forward, and at home switch
429  if(homing == 2 && cur_dir && home_switch)
430  {
431  homing = 0;
432  //Do any home state processing here. set_home()?
433  stop_moving = true;
434  return 0;
435  }
436 
437  //Main homing, moving backward, and at home switch
438  if(homing == 2 && !cur_dir && home_switch)
439  {
440  homing = 3; //keeping going back, but enter tertiary homing
441  return 0;
442  }
443 
444  //Secondary homing, moving backward, and home switch clear
445  if(homing == 3 && !cur_dir && !home_switch)
446  {
447  homing = 2; //re-enter secondary homing.
448  return set_direction(1); //and now move forward
449  }
450 
451  //if we're here, then keep homing
452  return 0;
453 }
454 
455 
457 {
458  std::ofstream of;
459 
460  of.open((std::string(getenv("VISAO_ROOT")) + "/" + init_file).c_str());
461 
462  of.precision(10);
463  of << "cur_pos float32 " << cur_pos << "\n";
464 
465  of.close();
466  return 0;
467 }
468 
470 {
471  remove((std::string(getenv("VISAO_ROOT")) + "/" + init_file).c_str());
472 
473  return 0;
474 }
475 
477 {
478  cur_pos = cp;
479  return 0;
480 }
481 
483 {
484  std::string resp;
485 
486  pthread_mutex_lock(&dio_mutex);
487  if(write_fifo_channel(FIFOCH_PWR, "1", 2, &resp) < 0)
488  {
489  _logger->log(Logger::LOG_LEV_ERROR, "dioserver response error in get_power_state");
490  power_state = 0;
491  pthread_mutex_unlock(&dio_mutex);
492  return -1;
493  }
494  pthread_mutex_unlock(&dio_mutex);
495 
496 #ifdef VISAO_SIMDEV
497  power_state = 1;
498  return 0;
499 #endif
500 
501  power_state = (resp[0] == '1');
502 
503 
504  return 0;
505 }
506 
508 {
509  cur_pos = 0;
510  return 0;
511 }
512 
513 
515 {
516  std::string resp;
517 
518  pthread_mutex_lock(&dio_mutex);
519  if(en)
520  {
521  if(write_fifo_channel(FIFOCH_ENABLE, "0", 1, &resp) < 0)
522  {
523  logss.str("");
524  logss << "Error writing to fifo channel " << FIFOCH_ENABLE << ". Attempting to set enable.";
525  log_msg(Logger::LOG_LEV_ERROR, logss.str());
526  std::cerr << logss.str() << " (logged) \n";
527  }
528  }
529  else
530  {
531  if(write_fifo_channel(FIFOCH_ENABLE, "1", 1, &resp) < 0)
532  {
533  logss.str("");
534  logss << "Error writing to fifo channel " << FIFOCH_ENABLE << ". Attempting to set disable.";
535  log_msg(Logger::LOG_LEV_ERROR, logss.str());
536  std::cerr << logss.str() << " (logged) \n";
537  }
538  }
539  pthread_mutex_unlock(&dio_mutex);
540  cur_enabled = en;
541  return 0;
542 }
543 
545 {
546  return set_enable(true);
547 }
548 
550 {
551  return set_enable(false);
552 }
553 
555 {
556  std::string resp;
557  pthread_mutex_lock(&dio_mutex);
558  if(hw_dir)
559  {
560  if(dir)
561  {
562  if(write_fifo_channel(FIFOCH_DIR, "1", 1, &resp) < 0)
563  {
564  logss.str("");
565  logss << "Error writing to fifo channel " << FIFOCH_DIR << ". Attempting to set direction high.";
566  log_msg(Logger::LOG_LEV_ERROR, logss.str());
567  std::cerr << logss.str() << " (logged) \n";
568  }
569  }
570  else
571  {
572  if(write_fifo_channel(FIFOCH_DIR, "0", 1, &resp) < 0)
573  {
574  logss.str("");
575  logss << "Error writing to fifo channel " << FIFOCH_DIR << ". Attempting to set direction low.";
576  log_msg(Logger::LOG_LEV_ERROR, logss.str());
577  std::cerr << logss.str() << " (logged) \n";
578  }
579  }
580  }
581  else
582  {
583  if(dir)
584  {
585  if(write_fifo_channel(FIFOCH_DIR, "0", 1, &resp) < 0)
586  {
587  logss.str("");
588  logss << "Error writing to fifo channel " << FIFOCH_DIR << ". Attempting to set direction low.";
589  log_msg(Logger::LOG_LEV_ERROR, logss.str());
590  std::cerr << logss.str() << " (logged) \n";
591  }
592  }
593  else
594  {
595  if(write_fifo_channel(FIFOCH_DIR, "1", 1, &resp) < 0)
596  {
597  logss.str("");
598  logss << "Error writing to fifo channel " << FIFOCH_DIR << ". Attempting to set direction high.";
599  log_msg(Logger::LOG_LEV_ERROR, logss.str());
600  std::cerr << logss.str() << " (logged) \n";
601  }
602  }
603  }
604  pthread_mutex_unlock(&dio_mutex);
605  cur_dir = dir;
606  return 0;
607 }
608 
610 {
611  return set_direction(true);
612 }
613 
615 {
616  return set_direction(false);
617 }
618 
619 int FocusMotorCtrl::step(int nsteps)
620 {
621  int i;
622  timeval currtime, tv;
623  double stepdt;
624  double avstepdt = 0;
625  std::string resp;
626 
627  #ifdef _debug
628  std::cout << "In Step\nnsteps = " << nsteps << "\nhoming = " << homing << "\n";
629  std::cout << "stop_moving = " << stop_moving << "\n" << "cur_dir = " << cur_dir << "\n\n";
630  #endif
631 
632  if(!homing) _logger->log(Logger::LOG_LEV_TRACE, "Starting move of %i steps.", nsteps);
633  else _logger->log(Logger::LOG_LEV_TRACE, "Starting homing of type %i.", homing);
634 
635  gettimeofday(&tv,0);
636  dataLogger(tv);
637 
638  enable();
639 
640  delete_init();
641 
642  is_moving = true;
643 
644  //actually step here.
645  //with wait times
646  i = 0;
647  if(check_limits() != 0)
648  {
649  logss.str("");
650  logss << "Error checking limit switch status. Stopping move.";
651  log_msg(Logger::LOG_LEV_ERROR, logss.str());
652  //std::cerr << logss.str() << " (logged)\n";
653  stop_moving = true;
654  }
655 
656  if(get_power_state() != 0)
657  {
658  logss.str("");
659  logss << "Error checking power status. Stopping move.";
660  log_msg(Logger::LOG_LEV_ERROR, logss.str());
661  //std::cerr << logss.str() << " (logged)\n";
662  stop_moving = true;
663  }
664 
665 #ifdef _debug
666 std::cout << "Beginning loop\nnsteps = " << nsteps << "\nhoming = " << homing << "\n";
667 std::cout << "stop_moving = " << stop_moving << "\n" << "cur_dir = " << cur_dir << "\n\n";
668 #endif
669 
670  while((i < nsteps || homing) && !stop_moving && !TimeToDie && power_state)
671  {
672  gettimeofday(&currtime,0);
673  stepdt = ((double)currtime.tv_sec+((double)currtime.tv_usec)/1e6) - ((double)last_step_time.tv_sec+((double)last_step_time.tv_usec)/1e6);
674 
675  while(stepdt < min_step_time) //Need to recheck in case the sleep is interrupted by a signal
676  {
677  gettimeofday(&currtime,0);
678  stepdt = ((double)currtime.tv_sec+((double)currtime.tv_usec)/1e6) - ((double)last_step_time.tv_sec+((double)last_step_time.tv_usec)/1e6);
679  }
680  if(!stop_moving && !TimeToDie && power_state) //Check in case it was set during the min_step_time wait.
681  {
682  pthread_mutex_lock(&dio_mutex);
683  if(write_fifo_channel(FIFOCH_STEP, "1", 1, &resp) < 0)
684  {
685  logss.str("");
686  logss << "Error writing to fifo channel " << FIFOCH_STEP << ". Attempting to set step high.";
687  log_msg(Logger::LOG_LEV_ERROR, logss.str());
688  //std::cerr << logss.str() << " (logged) \n";
689  }
690  pthread_mutex_unlock(&dio_mutex);
691 
692  if(resp[0] != '1')
693  {
694  logss.str("");
695  logss << "Step failed on setting step to high. Response from dioserver: " << resp << " Position not updated. Stopping move.";
696  log_msg(Logger::LOG_LEV_ERROR, logss.str());
697  //std::cerr << logss.str() << " (logged)\n";
698  break;
699  }
700  if(i > 0) avstepdt += stepdt;
701  set_cur_pos(cur_pos + (-1 + 2*cur_dir) * step_ratio);
702  usleep(1); //Minimum high time
703 
704  pthread_mutex_lock(&dio_mutex);
705  if(write_fifo_channel(FIFOCH_STEP, "0", 1, &resp) < 0)
706  {
707  logss.str("");
708  logss << "Error writing to fifo channel " << FIFOCH_STEP << ". Attempting to set step low.";
709  log_msg(Logger::LOG_LEV_ERROR, logss.str());
710  //std::cerr << logss.str() << " (logged) \n";
711  }
712  pthread_mutex_unlock(&dio_mutex);
713 
714  gettimeofday(&last_step_time,0);
715  if(resp[0] != '0')
716  {
717  logss.str("");
718  logss << "Step failed (bad return from dioserver) on setting step to low. Stopping move.";
719  log_msg(Logger::LOG_LEV_ERROR, logss.str());
720  //std::cerr << logss.str() << " (logged)\n";
721  break;
722  }
723 
724  if (check_limits() != 0)
725  {
726  logss.str("");
727  logss << "Error checking limit switch status. Stopping move.";
728  log_msg(Logger::LOG_LEV_ERROR, logss.str());
729  //std::cerr << logss.str() << " (logged)\n";
730  break;
731  }
732 
733  if(get_power_state() != 0)
734  {
735  logss.str("");
736  logss << "Error checking power status. Stopping move.";
737  log_msg(Logger::LOG_LEV_ERROR, logss.str());
738  //std::cerr << logss.str() << " (logged)\n";
739  stop_moving = true;
740  }
741 
743  i++;
744  }
745  }
746 
747  gettimeofday(&tv,0);
748  dataLogger(tv);
749 
750  double itmp;
751  if(i > 0 ) itmp = i;
752  else itmp = 1e34;
753  logss.str("");
754  logss << "Completed move. " << i << " steps, ave time: " << avstepdt/itmp << " secs/step";
755  //std::cerr << logss.str() << "\n";
756  log_msg(Logger::LOG_LEV_INFO, logss.str());
757 
758  //std::cerr << "Setting low (cleanup)\n";
759  //Cleanup and prepare for next move.
760  pthread_mutex_lock(&dio_mutex);
761  if(write_fifo_channel(FIFOCH_STEP, "0", 1, &resp) < 0) //Unecessary and redundant, but just to make sure we can't leave with step high
762  { // due an asynchronous event. Would cause missing steps.
763  logss.str("");
764  logss << "Error writing to fifo channel " << FIFOCH_STEP << ". Attempting to set direction low during move cleanup.";
765  log_msg(Logger::LOG_LEV_ERROR, logss.str());
766  //std::cerr << logss.str() << " (logged)\n";
767  }
768  pthread_mutex_unlock(&dio_mutex);
769  //need to check steps
770  is_moving = false;
771  stop_moving = false;
772  homing = 0;
773  disable();
774  pending_move = 0;
775 
776  save_init();
777  #ifdef _debug
778  std::cout << "Leaving by the back\nnsteps = " << nsteps << "\nhoming = " << homing << "\n";
779  std::cout << "stop_moving = " << stop_moving << "\n" << "cur_dir = " << cur_dir << "\n\n";
780  #endif
781  _logger->log(Logger::LOG_LEV_TRACE, "Completed %i steps.", i);
782 
783  return 0;
784 }//step(int)
785 
787 {
788  return step(1);
789 }
790 
792 {
793  set_forward();
794  stop_moving = 0; //Check limits may have set this if at a limit switch moving the other way
795  return step(nsteps);
796 }
797 
799 {
800  return step_forward(1);
801 }
802 
804 {
805  set_backward();
806  stop_moving = 0; //Check limits may have set this if at a limit switch moving the other way
807  return step(nsteps);
808 }
809 
811 {
812  return step_backward(1);
813 }
814 
816 {
817  double dsteps = dpos / step_ratio;
818  next_pos = cur_pos + dpos;
819  if(dsteps > 0)
820  {
821  return step_forward((int)(dsteps+.5));
822  }
823  if(dsteps < 0)
824  {
825  return step_backward((int)(-1*dsteps-.5));
826  }
827  is_moving = false;
829  return 0;
830 }
831 
833 {
834  double dpos = pos - cur_pos;
835  return offset_pos(dpos);
836 }
837 
839 {
841  if(pending_move == MOVE_ABS) return goto_pos(next_pos);
842  if(pending_move == MOVE_HOME)
843  {
844  if(cur_pos < home_pos) set_forward();
845  else set_backward();
846  stop_moving = 0;
847  homing = 1;
848  return step(0);
849  }
850  if(pending_move == MOVE_NEGHOME)
851  {
852  set_backward();
853  stop_moving = 0;
854  homing = 4;
855  return step(0);
856  }
857  if(pending_move == MOVE_POSHOME)
858  {
859  set_forward();
860  stop_moving = 0;
861  homing = 5;
862  return step(0);
863  }
864 
865  return 0;
866 }
867 
868 int FocusMotorCtrl::get_preset(double &fcal, std::vector<double> & preset, std::string & presetf)
869 {
870  size_t sz;
871 
872  if(!fw2sb) fw2sb = (VisAO::filterwheel_status_board*) attach_shm(&sz, STATUS_filterwheel2, 0);
873  if(!fw3sb) fw3sb = (VisAO::filterwheel_status_board*) attach_shm(&sz, STATUS_filterwheel3, 0);
874  if(!wsb) wsb = (VisAO::wollaston_status_board*) attach_shm(&sz, STATUS_wollaston, 0);
875  if(!aosb) aosb = (VisAO::aosystem_status_board*) attach_shm(&sz, STATUS_aosystem, 0);
876 
877  if(!aosb || !wsb || !fw2sb || !fw3sb)
878  {
879  logss.str("");
880  logss << "Not connected to status boards for preset.";
881  log_msg(Logger::LOG_LEV_ERROR, logss.str());
882  //ERROR_REPORT("Not connected to status boards for preset.");
883  return -1;
884  }
885 
886  if( get_focuscal(&fcal) < 0)
887  {
888  logss.str("");
889  logss << "Could not get focus cal.";
890  log_msg(Logger::LOG_LEV_ERROR, logss.str());
891  //ERROR_REPORT(logss.str().c_str());
892  return -1;
893  }
894 
895 
896  //std::string presetf;
897  if(::get_preset("focus", aosb->filter1_reqpos, (int) wsb->cur_pos, fw2sb->req_pos, fw3sb->req_pos, &preset, presetf) < 0)
898  {
899  logss.str("");
900  logss << "Could not get preset: " << presetf << ".";
901  log_msg(Logger::LOG_LEV_ERROR, logss.str());
902  //ERROR_REPORT(logss.str().c_str());
903  return -1;
904  }
905 
906  return 0;
907 }
908 
910 {
911  double fcal;
912  std::vector<double> preset(1);
913  std::string presetf;
914 
915  if(get_preset(fcal, preset, presetf) != 0)
916  {
917  return 0;
918  }
919 
920  if(fabs(fcal+preset[0] - cur_pos) < 2.) return 1;
921 
922 
923  return 0;
924 }
925 
927 {
928  double fcal;
929  std::vector<double> preset(1);
930  std::string presetf;
931 
932  if(get_preset(fcal, preset, presetf) != 0)
933  {
934  return -1;
935  }
936 
937  logss.str("");
938  logss << "Found focus cal: " << fcal;
939  LOG_INFO(logss.str().c_str());
940 
941 
942  logss.str("");
943  logss << "Found preset: " << presetf << " -> " << preset[0] << ".";
944  LOG_INFO(logss.str().c_str());
945 
946  logss.str("");
947  logss << "Presetting to: " << fcal + preset[0];
948  LOG_INFO(logss.str().c_str());
949 
951  next_pos = fcal + preset[0];
952 
953  return 0;
954 }
955 
956 
958 {
959  std::string resp;
960  std::cout.precision(20);
961  //Install the main thread handler
963  {
964  ERROR_REPORT("Error installing main thread catcher.");
965  return -1;
966  }
967 
968  //Startup the I/O signal handling thread
969  if(start_signal_catcher(true) != 0)
970  {
971  ERROR_REPORT("Error starting signal catching thread.");
972  return -1;
973  }
974 
975  //Now Block all I/O signals in this thread.
976  if(block_sigio() != 0)
977  {
978  ERROR_REPORT("Error blocking SIGIO in main thread.");
979  return -1;
980  }
981 
982  LOG_INFO("starting up . . .");
983 
984  sleep(1); //wait for signal thread to get going.
985 
986  pthread_mutex_lock(&dio_mutex);
987  if(write_fifo_channel(FIFOCH_STEP, "0", 1, &resp) < 0) //Set the step to low just in case.
988  {
989  logss.str("");
990  logss << "Error writing to fifo channel " << FIFOCH_STEP << ". Attempting to set step to low.";
991  log_msg(Logger::LOG_LEV_ERROR, logss.str());
992  //std::cerr << logss.str() << " (logged) \n";
993  }
994  pthread_mutex_unlock(&dio_mutex);
995 
996  get_power_state();
997  disable();
998  set_direction(1);
999  check_limits(); //Just get the true position.
1000 
1001  double last_update = get_curr_time();
1002 
1003  while(!TimeToDie)
1004  {
1005  pthread_mutex_lock(&signal_mutex);
1006  pthread_cond_wait(&signal_cond, &signal_mutex);
1007  pthread_mutex_unlock(&signal_mutex);
1008 
1010 
1011  else if(DO_ENABLE != 0)
1012  {
1013  if(DO_ENABLE > 0) enable();
1014  if(DO_ENABLE < 0) disable();
1015  DO_ENABLE = 0;
1016  }
1017 
1018  if(get_curr_time() - last_update > pause_time)
1019  {
1020  check_limits();
1021  get_power_state();
1022  last_update = get_curr_time();
1023  }
1024  }
1025 
1026  pthread_join(signal_thread, 0);
1027 
1028  return 0;
1029 
1030 }
1031 
1032 
1033 std::string FocusMotorCtrl::remote_command(std::string com)
1034 {
1035  std::string resp;
1036  _logger->log(Logger::LOG_LEV_TRACE, "Received remote command: %s.", com.c_str());
1037  resp = common_command(com, CMODE_REMOTE);
1038  _logger->log(Logger::LOG_LEV_TRACE, "Response to remote command: %s.", resp.c_str());
1039  return resp;
1040 }
1041 
1042 std::string FocusMotorCtrl::local_command(std::string com)
1043 {
1044  std::string resp;
1045  _logger->log(Logger::LOG_LEV_TRACE, "Received local command: %s.", com.c_str());
1046  resp = common_command(com, CMODE_LOCAL);
1047  _logger->log(Logger::LOG_LEV_TRACE, "Response to local command: %s.", resp.c_str());
1048  return resp;
1049 }
1050 
1051 std::string FocusMotorCtrl::script_command(std::string com)
1052 {
1053  std::string resp;
1054  _logger->log(Logger::LOG_LEV_TRACE, "Received script command: %s.", com.c_str());
1055  resp = common_command(com, CMODE_SCRIPT);
1056  _logger->log(Logger::LOG_LEV_TRACE, "Response to script command: %s.", resp.c_str());
1057  return resp;
1058 }
1059 
1060 std::string FocusMotorCtrl::common_command(std::string com, int cmode)
1061 {
1062  char rstr[50];
1063  double npos;
1064 
1065 
1066  if(com == "pos?")
1067  {
1068  snprintf(rstr, 50, "%0.4f\n", get_cur_pos());
1069  return rstr;
1070  }
1071 
1072  if(com == "ismoving?")
1073  {
1074  if(is_moving) return "1\n";
1075  else return "0\n";
1076  }
1077 
1078  if(com == "state?")
1079  {
1080  return get_state_str();
1081  }
1082 
1083  if(com == "enable?")
1084  {
1085  if(cur_enabled) return "1\n";
1086  else return "0\n";
1087  }
1088 
1089  if(com == "power?")
1090  {
1091  if(power_state) return "1\n";
1092  else return "0\n";
1093  }
1094 
1095  if(com == "abort")
1096  {
1097  //Everybody can always abort.
1098  stop_moving = true;
1099  pthread_kill(main_thread, SIG_MAINTHREAD);
1100  return "0\n";
1101  }
1102 
1103 
1104  //int pst = com.find("preset", 0);
1105  if(com == "preset")
1106  {
1107  if(control_mode == cmode)
1108  {
1109  if(is_moving || pending_move) return "-1\n";
1110 
1111  goto_preset();
1112  return "0\n";
1113  }
1114  else return control_mode_response();
1115  }
1116 
1117  if(com.substr(0,3) == "pos")
1118  {
1119  if(control_mode == cmode)
1120  {
1121  if(is_moving || pending_move) return "0\n";
1122 
1123  npos = strtod(com.substr(3,com.length()-3).c_str(),0);
1125  next_pos = npos;
1126  return "1\n";
1127  }
1128  else return control_mode_response();
1129  }
1130 
1131  if(com.substr(0,4) == "dpos")
1132  {
1133  if(control_mode == cmode)
1134  {
1135  if(is_moving || pending_move) return "0\n";
1136 
1137  npos = strtod(com.substr(4,com.length()-4).c_str(),0);
1139  next_pos = npos;
1140  return "1\n";
1141  }
1142  else return control_mode_response();
1143  }
1144 
1145  if(com == "home")
1146  {
1147  if(control_mode == cmode)
1148  {
1149  return "-1\n";
1150  }
1151  else return control_mode_response();
1152  }
1153 
1154  if(com == "homeneg")
1155  {
1156  if(control_mode == cmode)
1157  {
1158  if(is_moving || pending_move) return "0\n";
1159 
1160  pending_move = MOVE_NEGHOME;
1161  return "1\n";
1162  }
1163  else return control_mode_response();
1164  }
1165 
1166  if(com == "homepos")
1167  {
1168  if(control_mode == cmode)
1169  {
1170  if(is_moving || pending_move) return "0\n";
1171 
1172  pending_move = MOVE_POSHOME;
1173  return "1\n";
1174  }
1175  else return control_mode_response();
1176  }
1177 
1178  if(com == "enable")
1179  {
1180  if(control_mode == cmode)
1181  {
1182  if(is_moving || pending_move) return "0\n";
1183 
1184  DO_ENABLE = 1;
1185  return "1\n";
1186  }
1187  else return control_mode_response();
1188  }
1189 
1190  if(com == "disable")
1191  {
1192  if(control_mode == cmode)
1193  {
1194  if(is_moving || pending_move) return "0\n";
1195 
1196  DO_ENABLE = -1;
1197  return "1\n";
1198  }
1199  else return control_mode_response();
1200  }
1201 
1202  if(com == "disable_pos_limit")
1203  {
1204  if(control_mode == CMODE_LOCAL)
1205  {
1206  pos_limit_disabled = true;
1207  return "1\n";
1208  }
1209  else return control_mode_response();
1210  }
1211 
1212  /*re enabling the back limit requires a restart
1213  * if(com == "enable_back_limit")
1214  * {
1215  * back_limit_disabled = false;
1216  * return "1\n";
1217  *
1218  }*/
1219 
1220  return (std::string("UNKOWN COMMAND: ") + com + "\n");
1221 }
1222 
1224 {
1225  char statestr[100];
1226  std::string str = control_mode_response();
1227 
1228  snprintf(statestr, 100, "%c %012.4f %i %i %i %i %i %i %i %012.4f %i\n", str[0], cur_pos, cur_enabled, power_state, is_moving, homing, neg_limit, home_switch, pos_limit, next_pos-cur_pos, pos_limit_disabled);
1229 
1230  return statestr;
1231 }
1232 
1233 
1235 {
1236 
1238  {
1240 
1242 
1243  fsb->cur_pos = cur_pos;
1244  fsb->homing = homing;
1245  fsb->is_moving = is_moving;
1246  fsb->cur_dir = cur_dir;
1247  fsb->cur_enabled = cur_enabled;
1248  fsb->power_state = power_state;
1249  fsb->is_focused = check_preset();
1250  }
1251  return 0;
1252 }
1253 
1255 {
1256  checkDataFileOpen();
1257 
1258  dataof << tv.tv_sec << " " << tv.tv_usec << " " << cur_pos << std::endl;
1259 
1260  if(!dataof.good())
1261  {
1262  Logger::get()->log(Logger::LOG_LEV_ERROR, "Error in Focus motor data file. Focus data may not be logged correctly");
1263  }
1264 
1265 }
1266 
1267 } //namespace VisAO
#define MOVE_OFFSET
Pending offset move.
void log_msg(int LogLevel, std::string lmsg)
Report an error. Also calls log_msg. Overloaded from VisAOApp_base.
#define FIFOCH_NEGL
The fifo_list fifo channel for the front limit.
double min_step_time
Minimum time between steps, in seconds. Can't be < 1e-6.
int check_limits()
Gets the limit switch status from dioserver, and performs homing logic checks.
double get_curr_time(void)
Gets the current CLOCK_REALTIME time, returns it in seconds to double precision.
Definition: libvisaoc.c:40
int set_cur_pos(double)
Set the current position. This does not move the motor.
double home_pos
The position to set at the after homing to the home switch.
int start_pending_move()
Calls either offset_pos(next_pos) or goto_pos(next_pos) when the main loop detects a pending move...
int enable()
Call set_enable(true);.
virtual int start_signal_catcher(bool inherit_sched=true)
Starts the signal catching loop.
int delete_init()
Delete the initialization file.
virtual std::string script_command(std::string com)
Overridden from VisAOApp_base::script_command, here just calls common_command.
int dioch_pwr
The dioserver software channel connected to +5V terminal.
virtual std::string remote_command(std::string com)
Overridden from VisAOApp_base::remote_command, here just calls common_command.
int offset_pos(double dpos)
Offset current position (in microns).
int dioch_limhome
The dioserver software channel connected to the middle limit switch output.
pthread_mutex_t signal_mutex
Mutex for the condition signaling.
std::string get_state_str()
Get the state string.
int disable()
Call set_enable(false);.
The standalone VisAO application, does not interface with the AO Supervisor.
int hw_dir
Sets the polarity of the direction pin relative to the software direction, that is so forward is forw...
double step_ratio
Microns per step. For E35H4N-12-900 with BSD-02H in 1/8 step resolution this is 0.375.
std::ostringstream logss
Conveninence string stream for building log messages.
void initapp()
Initialization common to both constructors.
void * statusboard_shmemptr
The pointer to the shared memory block for the statusboard.
#define FIFOCH_HOMESW
The fifo_list fifo channel for the home switch.
#define MOVE_ABS
Pending move to absolute position.
int set_forward()
Call set_direction(true);.
virtual int update_statusboard()
Update the status board.
virtual int setup_baseApp(bool usethreads=false)
Install fifo channels.
int step()
Move by 1 step in current direction.
Declarations for the focus stage stepper motor controller.
#define FIFOCH_POSL
The fifo_list fifo channel for the back limit.
int dioch_dir
The dioserver software channel connected to the direction pin.
#define FIFOCH_DIR
The fifo_list fifo channel for direction.
int set_backward()
Call set_direction(false);.
virtual int Run()
The main loop.
virtual void dataLogger(timeval tv)
Write focus positions to the data log.
FocusMotorCtrl(std::string name, const std::string &conffile)
Standard constructor with a config file.
int set_home()
Set the current position as the home position.
int setup_fifo_list(int nfifos)
Allocate the fifo_list.
bool neg_limit
True if negative limit switch is active.
bool is_moving
True if currently processing a position change.
bool stop_moving
If true, the currently processing position change is terminated.
#define MOVE_NONE
No pending move.
pthread_cond_t signal_cond
Condition for telling main thread that something changed.
int goto_pos(double pos)
Move to an absolute position (in microns).
int DO_ENABLE
Flag for main loop. +1 calls enable, -1 calls disable.
int pending_move
If non zero, a move is pending. Can be MOVE_OFFSET or MOVE_ABS.
bool pos_limit
True if positive limit switch is active.
int save_init()
Save the initialization data to disk.
double cur_pos
The position, relative to home, in microns.
pthread_t signal_thread
Identifier for the separate signal handling thread.
int goto_preset()
Move the focus stage to the preset position for the current VisAO setup.
key_t statusboard_shmemkey
The key used to lookup the shared memory.
#define FIFOCH_PWR
The fifo_list fifo channel for power.
int dioch_limneg
The dioserver software channel connected to the negative limit switch output.
int set_enable(bool en)
Set the enable state of the controller.
virtual int block_sigio()
Sets the signal mask to block SIGIO and RTSIGIO.
int TimeToDie
Global set by SIGTERM.
virtual std::string local_command(std::string com)
Overridden from VisAOApp_base::local_command, here just calls common_command.
int step_forward()
Move by 1 step in forward direction.
double get_cur_pos()
Get the current position in microns.
std::string control_mode_response()
Convenience function to return the control type response string, e.g. "A\n".
void * attach_shm(size_t *sz, key_t mkey, int shmemid)
Attach to a shared memory buffer and get its size.
Definition: libvisaoc.c:90
int get_preset(double &fcal, std::vector< double > &preset, std::string &presetf)
Reads the preset file for the current setup as determined from the shared memory status boards...
fifo_list fl
The list of named-pipe fifos used for inter-process comms.
int cur_enabled
Power state of the controller.
int get_power_state()
Get the power state of the controller.
bool home_switch
True if home limit switch is active.
int check_preset()
Check if the focus stage is currently at the preset (focused) position (within 2 microns) ...
double pause_time
Time to pause during application main loop.
Definition: VisAOApp_base.h:84
#define FIFOCH_ENABLE
The fifo_list fifo channel for enable.
int cur_dir
Tracks the current setting of the direction pin TTL level.
bool pos_limit_disabled
True if back limit is disabled for dismounting.
int create_statusboard(size_t sz)
Creates and attaches to the statusboard shared memory.
#define FIFOCH_STEP
The fifo_list fifo channel for step.
timeval last_step_time
Time of the last step.
int dioch_step
The dioserver software channel connected to the step pin.
#define MAX_FNAME_SZ
The maximum allowed filename length.
Definition: fifoutils.h:37
static int control_mode
The current control mode.
virtual int install_sig_mainthread_catcher()
Install the SIG_MAINTHREAD signal catcher.
virtual int update_statusboard()
Update the status board.
int set_direction(bool dir)
Set the direction of the controller.
int dioch_enable
The dioserver software channel connected to the enable pin.
std::string common_command(std::string com, int cmode)
The common command processor for commands received by fifo.
The namespace of VisAO software.
std::string diofifo_path
The path of the dioserver fifos.
int dioch_limpos
The dioserver software channel connected to the positive limit switch output.
pthread_t main_thread
Identifier for the main thread.
double next_pos
Position of next move. Interpreted as either an offset or absolute position depending on pending_move...
int get_dio_fnames(char *fout, char *fin, char *fbase, int ch)
Fills in the properly formatted dioserver channel fifo names.
Definition: libvisaoc.c:23
int set_fifo_list_channel(fifo_list *fl, int nch, int buffsz, const char *fin, const char *fout, int(*inp_hand)(fifo_channel *), void *adata)
Set the details of one channel in the list.
Definition: fifoutils.c:373
int step_backward()
Move by 1 step in backward direction.
int write_fifo_channel(int ch, const char *com, int comlen, std::string *resp)
Write data to a fifo_channel, and get a response if desired.