/***************************************************************************
                          amcmotor.h  -  description
                             -------------------
    begin                : Sun Nov 24 2002
    copyright            : (C) 2002 by Martin Merck
    email                : merck@astro.uni-wuerzburg.de
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is part of the MAGIC control software for the AMC.       *
 *   The software is only intended for use in the MAGIC telescope project  *
 *   All rights remain with the author.					   *
 ***************************************************************************/

#ifndef AMCMOTOR_H
#define AMCMOTOR_H

class QCString;
class AMCSerialPort;

// Number of echo characters. In the actual RS 485 configuration
// we will normally get 2 echo characters. The first one comes
// from the line itself, as we use only one pair of cables and
// the write and read lines are connected. The second echo character
// comes from the AMC master itself.
#define NUM_ECHO	2

/**This class combines the functionalitz of the individual mirror panels
  *@author Martin Merck
  */

class AMCMotor {
public: 
  AMCMotor( AMCSerialPort* p_pPort );
  ~AMCMotor();

  /** Select the given AMC box */
  void selectBox( int p_iBox ) const;

  /** Select he given AMC driver in the box. If no box has been
   * selected we may get a communication error.
   */
  void selectDriver( int p_iDriver ) const;

  /** Reset the status of the current box. This will kill any current
   * motor movement, turn off the laser and power of the motors */
  void Reset() const;

  /** Kill the current motor movement */
  void killMovement() const;

  /** Return information from the AMC box */
  void getInfo( int* p_iTemp,
  				int* p_iHum,
  				int* p_iPowerI,
  				int* p_iPowerV,
  				int* p_iSecondV,
  				int* p_iLogicV ) const;
  				
  /** Set the frequency with which the current driver will drive the motors.  */
  void setFrequency( int p_iFreq ) const;
  				
  /** Return the frequency with which the motors are driven */
  int getFrequency() const;

  /** Set the working current with which the current driver will drive the motors. */
  void setWorkingCurrent( int p_iCurrent ) const;

  /** Return the working current set for the selected driver. */
  int getWorkingCurrent() const;

  /** Set the holding current with which the current driver will drive the motors. */
  void setHoldingCurrent( int p_iCurrent ) const;

  /** Return the holding current set for the selected driver. */
  int getHoldingCurrent() const;

  /** Switch the laser on or off. */
  void switchLaser( bool zOn ) const;

  /** Turn the power to the motors on or off. By default the motors are always powered on.
   * This is necesary to send the holding current through the motors. We can turn
   * the power off in case of a broken motor. However the power will remain turned off
   * only if we deselect the driver in the next command. Selecting the driver again
   * or sending a movement command, will automatically turn the motor power on again.
   */
  void powerMotors( bool zOn ) const;

  /** Move the motors by the given number of steps. If the number is positive we move
   * upwards, if negative downwards. Be aware that the directions can be changed with
   * the tuning commands. */
  void moveMotors( int p_iX, int p_iY ) const;

  /** Move the motors to the end switches and then find the central poosition. */
  void centerMotors() const;

  /** Calculate the time needed by the motors to complete the number of steps.
   * We add 200 ms for the communications overhead. The returned value
   * is the next high integer number of seconds.
   */
  int calcTimeout( int p_iSteps ) const;

  /** Wait for the motor movement to complete. */
  void waitForMotors( int p_iTimeout ) const;

  /** Unselect the currently selected box. */
  void unselectBox() const;

  /** Reset the currently selected box. */
  void resetBox() const;

  /** Reset the currently selected box. */
  void resetDriver() const;

  /** No descriptions */
  void setPort( AMCSerialPort* pPort ) { m_pPort = pPort; };

  /** No descriptions */
  void setPortNum( int p_iPort ) { m_iPort = p_iPort; };

private: // Private methods
  /** No descriptions */
  void sendCommand(const QCString& p_sCommand, QCString& p_sResponse ) const;

private: // Private attributes
  /** Pointer to the serial port to use */
  AMCSerialPort* m_pPort;
  int m_iPort;

  /** The currently selected driver */
  mutable int m_iCurrDriver;

  /** Holds the current frequency used to power theb motors. We need this value internally
   * to calculate the timeout.  */
  mutable int m_iCurrFreq;
};

#endif
