 /*--------------------------------------------------------------------
  Part of the AMOR position calculation module.

  copyright: see file COPYRIGHT

  Mark Koennecke, October 2005
----------------------------------------------------------------------*/
#include "amorset.h"
#include "amordrive.h"

/*---------------------------------------------------------------*/
static void *AMODRIVGetInterface(void *data, int iD)
{
  pamorDrive self = NULL;

  self = (pamorDrive) data;

  if (iD == DRIVEID && self != NULL) {
    return self->pDriv;
  } else {
    return NULL;
  }
  return NULL;
}

/*----------------------------------------------------------------
 This routine can return either OKOK or HWFault when thing
 go wrong. However, the return value of Halt is usually ignored!
------------------------------------------------------------------*/
static int AMODRIVHalt(void *data)
{
  pamorDrive self = NULL;

  self = (pamorDrive) data;

  return self->mama->pDriv->Halt(self->mama);
}

/*----------------------------------------------------------------
 This routine can return either 1 or 0. 1 means the position can 
 be reached, 0 NOT
 If 0, error shall contain up to errlen characters of information
 about which limit was violated
 Due to the complex nauture of the calculation: no check here
------------------------------------------------------------------*/
static int AMODRIVCheckLimits(void *data, float val,
                              char *error, int errlen)
{
  pamorDrive self = NULL;

  self = (pamorDrive) data;

  return 1;
}

/*----------------------------------------------------------------
 This routine can return 0 when a limit problem occurred 
 OKOK when the motor was successfully started 
 HWFault when a problem occured starting the device
 Possible errors shall be printed to pCon
 For real motors, this is supposed to try at least three times
 to start the motor in question
 val is the value to drive the motor too
------------------------------------------------------------------*/
static long AMODRIVSetValue(void *data, SConnection * pCon, float val)
{
  pamorDrive self = NULL;

  self = (pamorDrive) data;

  amorSetMotor(self->mama, self->type, val);

  return 1;
}

/*----------------------------------------------------------------
 Checks the status of a running motor. Possible return values
   HWBusy The motor is still running
   OKOK or HWIdle when the motor finished driving
   HWFault when a hardware problem ocurred
   HWPosFault when the hardware cannot reach a position
 Errors are duly to be printed to pCon
 For real motors CheckStatus again shall try hard to fix any 
 issues with the motor 
------------------------------------------------------------------*/
static int AMODRIVCheckStatus(void *data, SConnection * pCon)
{
  pamorDrive self = NULL;

  self = (pamorDrive) data;

  return self->mama->pDriv->CheckStatus(self->mama, pCon);
}

/*----------------------------------------------------------------
 GetValue is supposed to read a motor position
 On errors, -99999999.99 is returned and messages printed to pCon
------------------------------------------------------------------*/
static float AMODRIVGetValue(void *data, SConnection * pCon)
{
  pamorDrive self = NULL;
  float val = -99999999.99;

  self = (pamorDrive) data;
  return amorGetMotor(self->mama, pCon, self->type);
}

/*----------------------------------------------------------------
 returns NULL on failure, a new datastrcuture else
------------------------------------------------------------------*/
static pamorDrive AMODRIVMakeObject()
{
  pamorDrive self = NULL;

  self = (pamorDrive) malloc(sizeof(amorDrive));
  if (self == NULL) {
    return NULL;
  }
  memset(self, 0, sizeof(amorDrive));
  self->pDes = CreateDescriptor("AmorDrive");
  self->pDriv = CreateDrivableInterface();
  if (self->pDes == NULL || self->pDriv == NULL) {
    free(self);
    return NULL;
  }

  self->pDes->GetInterface = AMODRIVGetInterface;
  self->pDriv->Halt = AMODRIVHalt;
  self->pDriv->CheckLimits = AMODRIVCheckLimits;
  self->pDriv->SetValue = AMODRIVSetValue;
  self->pDriv->CheckStatus = AMODRIVCheckStatus;
  self->pDriv->GetValue = AMODRIVGetValue;

  return self;
}

/*-----------------------------------------------------------------*/
void killAmorDrive(void *data)
{
  pamorDrive self = NULL;

  self = (pamorDrive) data;
  if (self == NULL) {
    return;
  }
  if (self->pDes != NULL) {
    DeleteDescriptor(self->pDes);
  }
  if (self->pDriv != NULL) {
    free(self->pDriv);
  }
  free(self);
}

/*-----------------------------------------------------------------*/
pamorDrive makeAmorDrive(pamorSet papa, int type)
{
  pamorDrive self = NULL;

  self = AMODRIVMakeObject();
  if (self == NULL) {
    return self;
  }
  self->mama = papa;
  self->type = type;
  return self;
}

/*----------------------------------------------------------------*/
int AmorDriveAction(SConnection * pCon, SicsInterp * pSics, void *pData,
                    int argc, char *argv[])
{
  pamorDrive self = NULL;
  float val;
  char pBueffel[132];

  self = (pamorDrive) pData;
  assert(self);
  val = amorGetMotor(self->mama, pCon, self->type);
  if (val > -999999) {
    snprintf(pBueffel, 131, " %s = %f", argv[0], val);
    SCWrite(pCon, pBueffel, eValue);
    return 1;
  } else {
    return 0;
  }
  return 0;
}
