#include  "rc_def.h"
#include  "comhead.h"
#pragma hdrstop

// motors.cpp
// (C) 1993,95 by Heiko Damerow MPG AG "Roentgenbeugung"
/*******************************************************************************
Version  1.9
Datum  951122

*******************************************************************************/
static  long  Drive628c(BYTE,WORD,long,WORD,WORD);
#include  "m_motcom.h"
#include    "m_mothw.h"
#include  "m_layer.h"
#include  "ieee.h"

#define   DirectAccess
// #define WriteLog
// #define CheckCorrect
// #define  TESTLAUF

char szMsgFailure[] = "Failure";
char szMessage[]    = "Message";
char szMsgLine001[] = "Initializing of drive module %s";
char szMsgLine002[] = "Problems with drive module startup !\n\nAbbort ?";
char szMsgLine003[] = "Starting up the drive module";
char szMsgLine004[] = "Save settings of %s                                   ";
char szMsgLine005[] = "This operation shouldn't be used for this drive !";
char szMsgLine006[] = "No valid drive !";
char szMsgLine007[] = "Calibration isn't done !";
char szMsgLine008[] = "Absolute zero for drive %s";
char szMsgLine009[] = "Calibration ready !";
char szMsgLine010[] = "\n\nThe new calibration data was saved !";
char szMsgLine011[] = "Optimize DCM-Parameter for %s";
char szMsgLine012[] = "Can't initialize the drive %s!";

static const  int    MAXIT = 30;    // maximal number of iterations
       int    TMotor::nMaxId  = 0;
extern    LPMList  lpMList;

extern TModalDlg* TheDialog;

HINSTANCE     hGPIBModule = NULL;
TInitialize  gInitialize;
TSend     gSend;
TEnter     gEnter;
TTransmit   gTransmit;
TReceive    gReceive;
TSPoll     gSPoll;
TPPoll    gPPoll;
TSetPort   gSetPort;
TSetTimeout  gSetTimeout;
TSetOutputEOS gSetOutputEOS;
TSetInputEOS gSetInputEOS;
TEnable488Ex gEnable488Ex;
TEnable488SD gEnable488SD;
TListenerOk  gListenerOk;
TBoardPresent gBoardPresent;

//**** variables belonging C-832 ***********************************************
static TCSet CmdSet[] =
 {// LM628/629-commands exept RDSTAT
 {RESET, 0,0,0}, {PORT8, 0,0,0}, {PORT12,0,0,0}, {DFH,   0,0,0},
 {SIP,   0,0,0}, {LPEI,  0,1,0}, {LPES,  0,1,0}, {SBPA,  0,2,1},
 {SBPR,  0,2,1}, {MSKI,  0,1,0}, {RSTI,  0,1,0}, {LFIL,  0,4,0},
 {UDF,   0,0,0}, {LTRJ,  0,3,1}, {STT,   0,0,0}, {RDSTAT,1,1,0},
 {RDSIGS,1,1,0}, {RDIP,  1,1,1}, {RDDP,  1,1,1}, {RDRP,  1,1,1},
 {RDDV,  1,1,1}, {RDRV,  1,1,0}, {RDSUM, 1,1,0}  };

static  BYTE  config;
static  WORD  drive;
static WORD  baddr;
static BYTE  raddr;
static UINT  nEvent;
static int  GetWord(WORD,WORD);
static long GetDWord(WORD,WORD);
static void  PutWord(int,WORD,WORD);
static void  PutDWord(long,WORD,WORD);
static BOOL  LM628Ready(WORD);
    int  nC812 = -1;

//******************************************************************************
TMList::TMList(int maxn,HINSTANCE inst)
 {
 char   buf[] = "Start of Program\r";

 AD_X      = -1;
 AD_Y      = -1;
 AD_Z      = -1;
 AD_Rotation   = -1;
 AD_Tilt       = -1;
 AD_DC          = -1;
 AD_Collimator  = -1;
 AD_DF          = -1;
 AD_Encoder     = -1;
 AD_Absorber    = -1;
 AD_Psi        = -1;
 AD_Phi        = -1;
 AD_Theta       = -1;
 AD_Omega       = -1;
 nActiveDrive   = -1;
 nLastDrive    = -1;
 nMaxNumber    = maxn;
 hMInstance    = inst;
#ifdef WriteLog
 FILE  *LogFile;
 LogFile = fopen("motor.log","w");
 if(LogFile)
  {
  fseek(LogFile,0,2);
  fwrite(buf,strlen(buf),1,LogFile);
  fclose(LogFile);
  }
#endif
 aMotor = new TMotor* [nMaxNumber];
 };

TMList::~TMList(void)
 {
 delete[] aMotor;
 };

BOOL TMList::InitializeModule(void)
 {
 BOOL    bNoFailure = TRUE;
 int   id;
 char   Ident[MaxString],ctype[MaxString];
 char  buf[MaxString];

 //*** build of motor list
 nLastDrive = -1; id = 0;
 do
  {
  sprintf(Ident,"Motor%d",id);
  GetPrivateProfileString(Ident,"Type","",ctype,MaxString,GetCFile());
  if(strlen(ctype) < 2) break;
  nLastDrive = id;
  if(strstr(strupr(ctype),"C-812ISA"))
   {
   aMotor[id] = (TMotor*)(TC_812ISA*)new TC_812ISA();
   continue;
   }
  if(strstr(strupr(ctype),"C-812GPIB"))
   {
   aMotor[id] = (TMotor*)(TC_812GPIB*)new TC_812GPIB();
   continue;
   }
  if(strstr(strupr(ctype),"C-832"))
   {
   aMotor[id] = (TC_832 *)new TC_832();
   continue;
   }
  aMotor[id] = (TMotor*)new TMotor();
  }
 while(id++ < nMaxNumber);
 if(nLastDrive > -1)
  nActiveDrive = 0;
 //********** initializion of all motors **************************************
 for(id = 0;id <= LastId();id++)
  {
  sprintf(buf,szMsgLine001,MP(id)->pCharacteristic());
  SetInfo(buf);
  if(R_OK != MP(id)->Initialize())
   {
   bNoFailure = FALSE;
   if(IDYES == MessageBox(GetFocus(),szMsgLine001,szMsgFailure,MBASK))
    return bNoFailure;
   delete aMotor[id];
   aMotor[id] = (TMotor*)new TMotor();
   aMotor[id]->Initialize();
   }
  }
 SetInfo(szMsgLine003);
 // Keine relative Winkel setzen
 for(id = 0;id <= LastId();id++)
  MP(id)->dAngleBias = 0.0;
 // Die Positions-Register der Motor-Steuerung werden auf NULL gesetzt und
 // die abgespeicherten Positionen werden rechnerisch einbezogen
 // Die abgespeicherten Positionen werden nicht ber‚cksichtigt.
 // Es wird unterstellt, dai die Register der Motor-Steuerung noch
 // aktuell sind
 return bNoFailure;
 };

TAxisType TMList::ParsingAxis(LPSTR axisname)
 {
 if( !strcmp(axisname,"AzimutalRotation") ||
   !strcmp(axisname,"AZ") ||
   !strcmp(axisname,"Rotation") ||
   !strcmp(axisname,"Azimute"))
  return Rotation;

 if( !strcmp(axisname,"X") ||
   !strcmp(axisname,"x") ||
   !strcmp(axisname,"Horizontal") ||
   !strcmp(axisname,"x-Achse") ||
   !strcmp(axisname,"x-Axis") )
  return X;

 if( !strcmp(axisname,"Y") ||
   !strcmp(axisname,"y") ||
   !strcmp(axisname,"y-Achse") ||
   !strcmp(axisname,"y-Axis") )
  return Y;

 if( !strcmp(axisname,"Z") ||
   !strcmp(axisname,"z") ||
   !strcmp(axisname,"Vertical") ||
   !strcmp(axisname,"z-Achse") ||
   !strcmp(axisname,"z-Axis") )
  return Z;

 if(!strcmp(axisname,"Theta"))
  return Theta;

 if(!strcmp(axisname,"Omega"))
  return Omega;

 if( !strcmp(axisname,"Tilt") ||
   !strcmp(axisname,"TL"))
  return Tilt;

 if( !strcmp(axisname,"DC") ||
   !strcmp(axisname,"Diffraction coarse") ||
   !strcmp(axisname,"Beugung grob") )
  return DC;

 if( !strcmp(axisname,"DF") ||
   !strcmp(axisname,"Diffraction fine") ||
   !strcmp(axisname,"Beugung fein"))
  return DF;

 if( !strcmp(axisname,"Psi"))
  return Psi;

 if( !strcmp(axisname,"Phi"))
  return Phi;

 if( !strcmp(axisname,"CC") ||
   !strcmp(axisname,"Collimator") ||
   !strcmp(axisname,"Kollimator"))
  return Collimator;

 if( !strcmp(axisname,"Absorber"))
  return Absorber;

 if( !strcmp(axisname,"Monochromator"))
  return Monochromator;

 if( !strcmp(axisname,"Encoder"))
  return Encoder;

 return (TAxisType)0;
 };

BOOL TMList::SaveModuleSettings(void)
 {
 int  id;
 char buf[MaxString];

 for(id = 0;id <= LastId();id++)
  {
  sprintf(buf,szMsgLine004,(LPSTR)MP(id)->pCharacteristic());
  SetInfo(buf);
  MP(id)->SaveSettings(TRUE);
  MP(id)->StopDrive(FALSE);
  }
 return TRUE;
 };

void TMList::SetAngleDefault(void)
 {
 int   id;

 for(id = 0;id <= LastId();id++)
  {
  MP(id)->dAngleBias = 0.0;
  MP(id)->SetAngleRange();
  }
}
TMotor* TMList::MP(void)
 {
 return aMotor[nActiveDrive];
 };

TMotor* TMList::MP(int n)
 {
 if((n >= 0) && (n <= nLastDrive))
  return aMotor[n];
 return aMotor[nActiveDrive];
 };

void TMList::SetParametersDlg(void)
 {
 TMotorParam* dlg;

 dlg = new TMotorParam();
 TheDialog = (TMotorParam *)dlg;
 dlg->ExecuteDialog(GetFrameHandle());
 delete dlg;
 };

void TMList::InquireReferencePointDlg(int task)
 {
 TModalDlg* dlg;

 dlg = (TCalibrate *)new TCalibrate(task);
 dlg->ExecuteDialog(GetFrameHandle());
 delete dlg;
 };

BOOL TMList::SetAxis(int n)
 {
 if((n >= 0) && (n <= nLastDrive))
  {
  nActiveDrive = n;
  return TRUE;
  }
  else
  {
  nActiveDrive = 0;
  return FALSE;
  }
 };
//******************************************************************************
//**************************************************************************
// Anfahren der Nullstellung : Referenzpunktlauf
TCalibrate::TCalibrate(int task) : TModalDlg("CalibrateMotors")
 {
 bZeroShouldSet    = FALSE;
 nTask       = task;
 lOldPos           = new long [lpMList->LastId()+1];
 bZeroPosReached   = new BOOL [lpMList->LastId()+1];
 bIndexPosReached  = new BOOL [lpMList->LastId()+1];
 bTargetPosReached = new BOOL [lpMList->LastId()+1];
 switch(nTask) {
  case 99:
  bAllMotors          = TRUE;
  bHoldPosition       = FALSE;
  bValidCalibrationData = TRUE;
  break;

  default:
  bValidCalibrationData = TRUE;
  bAllMotors          = FALSE;
  bHoldPosition       = FALSE;
  }
 };

TCalibrate::~TCalibrate(void)
 {
 delete[] lOldPos;
 delete[] bZeroPosReached;
 delete[] bTargetPosReached;
 delete[] bIndexPosReached;
 };

BOOL TCalibrate::Dlg_OnInit(HWND hwnd,HWND hwndCtl,LPARAM)
 {
 int   i;

 // Initialisieren der Parameterfenster f‚r einen Motor
 Motor = lpMList->MP();
 SetDlgItemText(hwnd,id_Report,"");
 CheckDlgButton(hwnd,id_ValidCalibrationData,bValidCalibrationData);
 hMotorList = GetDlgItem(hwnd,id_ChooseMotor);
 i = 0;
 while(i <= lpMList->LastId())
  ComboBox_AddString(hMotorList,lpMList->MP(i++)->pCharacteristic());
 ComboBox_SelectString(hMotorList,0,Motor->pCharacteristic());
 switch(nTask) {
  case 99:
  FORWARD_WM_COMMAND(hwnd,cm_CarryOnZero,hwndCtl,0,PostMessage);
  break;
  default:;
  }
 return TRUE;
 };

void TCalibrate::Dlg_OnTimer(HWND hwnd,UINT id)
 {
 int  idx;
 BOOL  AnyToDo = FALSE;

 if(id != TimerIdInformation)
  return;
 KillTimer(hwnd,TimerIdInformation);
 for(idx = 0;idx <= lpMList->LastId();idx++)
  {
  if(!bIndexPosReached[idx])
   {
   AnyToDo = TRUE;
   if(lpMList->MP(idx)->IsIndexArrived())
    {
    // Indexposition
    // bei C-812 meist die linke Endlage plus RemoveLimit
    // bei C-832 meist genau die Index-Position plus RemoveLimit
    // Es wurde noch kein Home neu gesetzt
    FORWARD_WM_COMMAND(hwnd,cm_IndexArrived,0,idx,SendMessage);
    continue;
    }
   continue;
   }
  if(!bZeroPosReached[idx])
   {
   AnyToDo = TRUE;
   if(lpMList->MP(idx)->IsMoveFinish())
    {
    FORWARD_WM_COMMAND(hwnd,cm_DistanceSet,0,idx,SendMessage);
    continue;
    }
   }
  }
 if(AnyToDo)
  SetTimer(hwnd,TimerIdInformation,130,NULL);
 return;
 };

void TCalibrate::Dlg_OnCommand(HWND hwnd,int id,HWND hwndCtl,UINT codeNotify)
 {
 int      idx;
 char     buf[2*MaxString];
 int      NextMotor;

 switch(id)
  {
  case cm_CarryOnZero:
  if(bZeroShouldSet)
   {
   MessageBeep(0);
   break;
   }
  // Kalibrierungs-Bedarf festlegen
  bHoldPosition = IsDlgButtonChecked(GetHandle(),id_HoldPosition);
  bValidCalibrationData = IsDlgButtonChecked(GetHandle(),id_ValidCalibrationData);
  if(!bValidCalibrationData)
   {
   strcpy(buf,"Es wird davon ausgegangen, dai sich der Antrieb\r\n");
   strcat(buf,"in der Position der physikalischen Null befindet.\r\n");
   strcat(buf,"Es werden Kalibrierungsdaten ge*ndert !");
   if(IDYES != MessageBox(GetFocus(),buf,"Meldung",MBASK))
    return;
   }
  for(idx = 0;idx <= lpMList->LastId();idx++)
   bIndexPosReached[idx] = bZeroPosReached[idx] = TRUE;
  if(!bAllMotors)
   {
   if(lpMList->MP()->bInitialMoveReady)
    bIndexPosReached[Motor->GetId()] = bZeroPosReached[Motor->GetId()] = FALSE;
    else
    MessageBox(GetHandle(),szMsgLine005,szMessage,MBINFO);
   }
   else
   {
   for(idx = 0;idx <= lpMList->LastId();idx++)
    if(lpMList->MP(idx)->bInitialMoveReady)
     bIndexPosReached[idx] = bZeroPosReached[idx] = FALSE;
   }
  for(idx = 0;idx <= lpMList->LastId();idx++)
   {
   Motor = lpMList->MP(idx);
   if(Motor->GetId() != idx)
    MessageBox(GetHandle(),"Motor Id",szMsgFailure,MBINFO);
   if(!bIndexPosReached[idx])
    {
    Motor->PushSettings();
    Motor->StartToIndex(lOldPos[idx]);  // old position will be returned
    bZeroShouldSet = TRUE;
    }
   }
  if(bZeroShouldSet)
   {
   SetDlgItemText(GetHandle(),id_Report,"");
   EnableWindow(GetDlgItem(hwnd,id_ChooseMotor),FALSE);
   EnableWindow(GetDlgItem(hwnd,cm_SetHome),FALSE);
   EnableWindow(GetDlgItem(hwnd,cm_CarryOnZero),FALSE);
   goto ExitWithTimer;
   }
  switch(nTask) {
   case 99:
   FORWARD_WM_COMMAND(hwnd,IDCANCEL,hwndCtl,0,PostMessage);
   break;
   default:
   SetDlgItemText(hwnd,id_Report,szMsgLine007);
   }
  return;

  case cm_IndexArrived:
  if(!lpMList->SetAxis(codeNotify))
   {
   MessageBox(GetHandle(),szMsgLine006,szMessage,MBINFO);
   return;
   }
  Motor = lpMList->MP();
  // Alle fertigen Motoren nicht mehr behandeln
  if(bZeroPosReached[Motor->GetId()])
   goto ExitWithTimer;
  if(bIndexPosReached[Motor->GetId()])
   goto ExitWithTimer;
  // measure the difference between startpoint and index point
  if(!bValidCalibrationData || bHoldPosition)
   {
   Motor->GetPosition(TRUE);
   lOldPos[Motor->GetId()] -= Motor->lPosition;
   }
  if(!bValidCalibrationData)
   Motor->lDistanceToZero = lOldPos[Motor->GetId()];
  // compute and set up the zero point
  Motor->SetHome();
  Motor->lDeltaPosition = -Motor->lDistanceToZero;
  bIndexPosReached[Motor->GetId()] = TRUE;
  Motor->bIsCalibrated  = TRUE;
  sprintf(buf,"Index %s",Motor->pCharacteristic());
  SetDlgItemText(GetHandle(),id_Report,(LPSTR)buf);
  // start next motor to target position
  // if hold old position take the old position
  // in all other cases take the TargetAngle
  // notify old position
  if(bHoldPosition)
   Motor->MoveByPosition(lOldPos[Motor->GetId()]);
   else
   Motor->MoveToAngle(Motor->dInitialAngle);
  goto ExitWithTimer;

  case cm_DistanceSet:
  if(!lpMList->SetAxis(codeNotify))
   {
   MessageBox(GetHandle(),szMsgLine006,szMsgFailure,MBINFO);
   return;
   }
  Motor = lpMList->MP();
  if(bHoldPosition)
   sprintf(buf,"Alte Position %s",Motor->pCharacteristic());
   else
   sprintf(buf,"Target Pos %s",Motor->pCharacteristic());
  SetDlgItemText(GetHandle(),id_Report,(LPSTR)buf);
  bZeroPosReached[Motor->GetId()] = TRUE;
  Motor->GetAngle(1);
  Motor->PopSettings(ThisPosition);
  if(!bValidCalibrationData)
   Motor->SaveSettings(FALSE);
  // Ist ein Motor noch nicht am Zielpunkt?
  NextMotor = FALSE;
  for(idx = 0;idx <= lpMList->LastId();idx++)
   if(!bZeroPosReached[idx])
    NextMotor = TRUE;
  if(NextMotor)
   goto ExitWithTimer;
  //*** Calibration finished
  if(!bValidCalibrationData)
   {
   bValidCalibrationData = TRUE;
   CheckDlgButton(GetHandle(),id_ValidCalibrationData,TRUE);
   }
  MessageBeep(0);
  switch(nTask) {
   case 99:
   FORWARD_WM_COMMAND(hwnd,IDCANCEL,hwndCtl,0,PostMessage);
   break;

   default:
   if(!bValidCalibrationData)
    {
    strcpy(buf,szMsgLine009);
    strcat(buf,szMsgLine010);
    MessageBox(GetHandle(),buf,szMessage,MBINFO);
    }
    else
    MessageBox(GetHandle(),szMsgLine009,szMessage,MBINFO);
   bZeroShouldSet = FALSE;
   EnableWindow(GetDlgItem(GetHandle(),id_ChooseMotor),TRUE);
   EnableWindow(GetDlgItem(GetHandle(),cm_SetHome),TRUE);
   EnableWindow(GetDlgItem(GetHandle(),cm_CarryOnZero),TRUE);
   }
  return;

  case cm_SetHome:
  Motor->SetHome();
  Motor->GetAngle(1);
  sprintf(buf,szMsgLine008,Motor->pCharacteristic());
  SetDlgItemText(GetHandle(),id_Report,buf);
  return;

  case id_ChooseMotor:
  switch(codeNotify)
   {
   case CBN_SELCHANGE:
   idx = ComboBox_GetCurSel(hMotorList);
   if((Motor != lpMList->MP(idx)) && (idx != CB_ERR))
    {
    lpMList->SetAxis(idx);
    Motor = lpMList->MP();
    }
   return;
   }
  return;

  case cm_RotateMotor:
  lpMList->SetAxis(Motor->GetId()+1);
  Motor = lpMList->MP();
  ComboBox_SelectString(hMotorList,0,Motor->pCharacteristic());
  return;

  case id_ValidCalibrationData:
  if(bZeroShouldSet)
   break;
  bValidCalibrationData = IsDlgButtonChecked(GetHandle(),id_ValidCalibrationData);
  if(bValidCalibrationData)
   {
   EnableWindow(GetDlgItem(GetHandle(),id_HoldPosition),TRUE);
   EnableWindow(GetDlgItem(GetHandle(),id_AllMotorsReset),TRUE);
   }
   else
   {
   bHoldPosition = FALSE;
   EnableWindow(GetDlgItem(GetHandle(),id_HoldPosition),FALSE);
   EnableWindow(GetDlgItem(GetHandle(),id_AllMotorsReset),FALSE);
   }
  return;

  case id_AllMotorsReset:
  if(bZeroShouldSet)
   break;
  bAllMotors = IsDlgButtonChecked(GetHandle(),id_AllMotorsReset);
  if(bAllMotors)
   {
   // Motor-Button deaktivieren
   EnableWindow(GetDlgItem(GetHandle(),id_ChooseMotor),FALSE);
   EnableWindow(GetDlgItem(GetHandle(),cm_SetHome),FALSE);
   }
   else
   {
   // Motor-Button aktivieren
   EnableWindow(GetDlgItem(GetHandle(),id_ChooseMotor),TRUE);
   EnableWindow(GetDlgItem(GetHandle(),cm_SetHome),TRUE);
   }
  return;

  default:
  TModalDlg::Dlg_OnCommand(hwnd,id,hwndCtl,codeNotify);
  }
 return;

ExitWithTimer:
 SetTimer(GetHandle(),TimerIdInformation,200,NULL);
 return;
 };

BOOL TCalibrate::CanClose(void)
 {
 if(bZeroShouldSet) return FALSE;
 // LimitWatch disable
 return TRUE;
 };

BOOL TCalibrate::LeaveDialog(void)
 {
 int id;
 KillTimer(GetHandle(),TimerIdInformation);
 for(id = 0;id <= lpMList->LastId();id++)
   {
   Motor = lpMList->MP(id);
   Motor->StopDrive(TRUE);
   }
 return TRUE;
 };
//**************************************************************************
// Steuerung des Probentellers ‚ber die Position
void TMList::PositionControlDlg(void)
 {
 TModalDlg* dlg;

 dlg = (TPosControl*)new TPosControl();
 dlg->ExecuteDialog(GetFrameHandle());
 delete dlg;
 };

TPosControl::TPosControl() : TModalDlg("PositionControl")
 {
 bMoveActive = FALSE;
 };

BOOL TPosControl::Dlg_OnInit(HWND hwnd,HWND hwndCtl,LPARAM)
 {
 int  cnt;

 Motor = lpMList->MP();
 BarHandle = GetDlgItem(hwnd,id_Bar);
 hMotorList = GetDlgItem(hwnd,id_ChooseMotor);
 cnt = 0;
 while(cnt <= lpMList->LastId())
  ComboBox_AddString(hMotorList,lpMList->MP(cnt++)->pCharacteristic());
 FORWARD_WM_COMMAND(hwnd,cm_ParamSet,hwndCtl,0,SendMessage);
 SetFocus(BarHandle);
 return TRUE;
 };

void TPosControl::Dlg_OnTimer(HWND hwnd,UINT id)
 {
 char    buf[MaxString];

 switch(id) {
  case TimerIdInformation:
  while(!Motor->GetPosition(TRUE));
  sprintf(buf,"%ld",Motor->lPosition);
  SetDlgItemText(hwnd,id_Position,buf);
  if(Motor->IsMoveFinish() && bMoveActive)
   {
   KillTimer(hwnd,TimerIdInformation);
   bMoveActive = FALSE;
   }
  FORWARD_WM_COMMAND(hwnd,cm_SetupDlgItem,0,0,SendMessage);
  }
 return;
 };

void TPosControl::Dlg_OnCommand(HWND hwnd,int id,HWND hwndCtl,UINT codeNotify)
 {
 char   buf[20];
 int   idx;

 switch(id)
  {
  case cm_SetupDlgItem:
  SetScrollPos(BarHandle,SB_CTL,GetBarPos(Motor),TRUE);
  sprintf(buf,"%ld",Motor->lPosition);
  SetDlgItemText(GetHandle(),id_NewPosition,buf);
  return;

  case cm_ParamSet:
  // Initialisieren des Motor-Scroll-Bar“s
  sprintf(buf,"%ld",Motor->lPosition);
  SetDlgItemText(GetHandle(),id_Position,buf);
  ComboBox_SelectString(hMotorList,0,Motor->pCharacteristic());
  BarHandle = GetDlgItem(GetHandle(),id_Bar);
  SetScrollRange(BarHandle,SB_CTL,-GetBarRange(Motor)/2,GetBarRange(Motor)/2,FALSE);
  // Initialisieren aller Positionsfenster
  FORWARD_WM_COMMAND(hwnd,cm_SetupDlgItem,hwndCtl,0,SendMessage);
  return;

  case id_ChooseMotor:
  switch(codeNotify)
   {
   case CBN_SELCHANGE:
   idx = ComboBox_GetCurSel(hMotorList);
   if((Motor != lpMList->MP(idx)) && (idx != CB_ERR))
    {
    Motor = lpMList->MP(idx);
    lpMList->SetAxis(Motor->GetId());
    FORWARD_WM_COMMAND(hwnd,cm_ParamSet,hwndCtl,0,SendMessage);
    FORWARD_WM_COMMAND(hwnd,cm_MotorInit,hwndCtl,0,PostMessage);
    }
   }
  return;

  case cm_RotateMotor:
  if(bMoveActive) break;
  lpMList->SetAxis(Motor->GetId()+1);
  Motor = lpMList->MP();
  FORWARD_WM_COMMAND(hwnd,cm_ParamSet,hwndCtl,0,SendMessage);
  return;

  case IDOK:
  // Der Nutzer hat mit Return eine neue Position eingegeben
  GetDlgItemText(GetHandle(),id_NewPosition,(LPSTR)buf,10);
  NewPosition = atol(buf);
  if(NewPosition < Motor->lPositionMin)
    NewPosition = Motor->lPositionMin;
    else
    if(NewPosition > Motor->lPositionMax)
     NewPosition = Motor->lPositionMax;
  FORWARD_WM_COMMAND(hwnd,cm_MoveButton,hwndCtl,0,PostMessage);
  SetFocus(GetDlgItem(GetHandle(),id_Bar));
  return;

  case cm_MoveButton:
  Motor->MoveToPosition(NewPosition);
  SetTimer(GetHandle(),TimerIdInformation,80,NULL);
  bMoveActive = TRUE;
  FORWARD_WM_COMMAND(hwnd,cm_SetupDlgItem,hwndCtl,0,PostMessage);
  return;

  default:
  TModalDlg::Dlg_OnCommand(hwnd,id,hwndCtl,codeNotify);
  }
 };

BOOL TPosControl::HScrollBar(WPARAM wParam,LPARAM)
 {
 switch(wParam)
  {
  case SB_LINEUP:
  NewPosition = Motor->lPosition - Motor->wPositionWidth;
  NewPosition = max(Motor->lPositionMin,NewPosition);
  break;
  case SB_LINEDOWN:
  NewPosition = Motor->lPosition + Motor->wPositionWidth;
  NewPosition = min(Motor->lPositionMax,NewPosition);
  break;
  case SB_PAGEUP:
  NewPosition = Motor->lPosition - 5 * Motor->wPositionWidth;
  NewPosition = max(Motor->lPositionMin,NewPosition);
  break;
  case SB_PAGEDOWN:
  NewPosition = Motor->lPosition + 5 * Motor->wPositionWidth;
  NewPosition = min(Motor->lPositionMax,NewPosition);
  break;
  case SB_ENDSCROLL:
  // Bewegung ausl÷sen
  FORWARD_WM_COMMAND(GetHandle(),cm_MoveButton,0,0,PostMessage);
  break;
  }
 return TRUE;
 };

int TPosControl::GetBarRange(const TMotor *act)
 {
 return (int)((act->lPositionMax - act->lPositionMin)/act->wPositionWidth);
 };

int TPosControl::GetBarPos(const TMotor *act)
 {
 return (int)(act->lPosition / act->wPositionWidth);
 };

BOOL TPosControl::LeaveDialog(void)
 {
 Motor->StopDrive(1);
 KillTimer(GetHandle(),TimerIdInformation);
 return TRUE;
 };

//******************************************************************************
//*** Allgemeine Einstellungen f‚r Motoren
TMotorParam::TMotorParam(void) : TModalDlg("DriveSettings")
 {
 };

#pragma argsused
BOOL TMotorParam::Dlg_OnInit(HWND hwnd,HWND hwndCtl,LPARAM lParam)
 {
 int   i;
 // Initialisieren der Parameterfenster f‚r einen Motor
 Motor = lpMList->MP();
 hMotorList = GetDlgItem(GetHandle(),id_ChooseMotor);
 i = 0;
 while(i <= lpMList->LastId())
  ComboBox_AddString(hMotorList, lpMList->MP(i++)->pCharacteristic());
 FORWARD_WM_COMMAND(hwnd,cm_ParamSet,hwndCtl,0,SendMessage);
 SetFocus(GetDlgItem(GetHandle(),id_Velocity));
 return TRUE;
 };

void TMotorParam::Dlg_OnCommand(HWND hwnd,int id,HWND hwndCtl,UINT codeNotify)
 {
 int     idx;
 char    buf[MaxString];

 switch(id)
  {
  case cm_ParamSet:
  // Initialisieren der Parameterfenster f‚r einen Motor
  ComboBox_SelectString(hMotorList, 0, Motor->pCharacteristic());
  sprintf(buf,Motor->pSF(),Motor->GetSpeed());
  SetDlgItemText(GetHandle(),id_Velocity,(LPSTR)buf);
  SetDlgItemText(GetHandle(),id_Limit,(LPSTR)ltoa(Motor->GetLimit(),(LPSTR)buf,10));
  SetDlgItemText(GetHandle(),id_PositionMax,(LPSTR)ltoa(Motor->lPositionMax,(LPSTR)buf,10));
  SetDlgItemText(GetHandle(),id_PositionMin,(LPSTR)ltoa(Motor->lPositionMin,(LPSTR)buf,10));
  SetDlgItemText(GetHandle(),id_PositionWidth,(LPSTR)ltoa(Motor->wPositionWidth,(LPSTR)buf,10));
  SetDlgItemText(GetHandle(),id_Unit,(LPSTR)Motor->szUnit);
  sprintf(buf,Motor->pSF(),Motor->GetAngleWidth());
  SetDlgItemText(GetHandle(),id_AngleWidth,(LPSTR)buf);
  sprintf(buf,Motor->pDF(),Motor->dAngleMin);
  SetDlgItemText(GetHandle(),id_AngleMin,(LPSTR)buf);
  sprintf(buf,Motor->pDF(),Motor->dAngleMax);
  SetDlgItemText(GetHandle(),id_AngleMax,(LPSTR)buf);
  return;

  case cm_SwitchLimitWatch:
  if(!Motor->StartLimitWatch())
   Motor->StopLimitWatch();
  return;

  case id_ChooseMotor:
  switch(codeNotify)
   {
   case CBN_EDITCHANGE:
   SetWindowText(hMotorList,Motor->pCharacteristic());
   return;

   case CBN_SELCHANGE:
   idx = ComboBox_GetCurSel(hMotorList);
   if((Motor != lpMList->MP(idx)) && (idx != CB_ERR))
    {
    if(CanClose())
     {
     Motor = lpMList->MP(idx);
     lpMList->SetAxis(Motor->GetId());
     }
    FORWARD_WM_COMMAND(hwnd,cm_ParamSet,0,0,SendMessage);
    }
   return;
   }
  return;

  case cm_RotateMotor:
  // Erst die Einstellungen f‚r den aktuellen Motor sichern
  if(CanClose())
   {
   lpMList->SetAxis(Motor->GetId()+1);
   Motor = lpMList->MP();
   }
  FORWARD_WM_COMMAND(hwnd,cm_ParamSet,0,0,SendMessage);
  return;

  default:
  TModalDlg::Dlg_OnCommand(hwnd,id,hwndCtl,codeNotify);
  }
 };

BOOL TMotorParam::LeaveDialog(void)
 {
 return TRUE;
 };

BOOL TMotorParam::CanClose(void)
 {
 char    buf[MaxString];
 BOOL    FActivate = FALSE;
 BOOL    FFail = FALSE;
 WORD    valueW;
 DWORD   valueDW;
 double  valueF;

 for(;;)
  {
  GetDlgItemText(GetHandle(),id_Velocity,(LPSTR)buf,10);
  if(!buf) { FFail = TRUE;break;}
  valueF = atof(buf);
  if(valueF == 0.0) { FFail = TRUE;break;}
  if(Motor->SetSpeed(valueF))
   FActivate = TRUE;
  GetDlgItemText(GetHandle(),id_Limit,(LPSTR)buf,10);
  if(!buf)
   {
   FFail = TRUE;
   break;
   }
  valueDW = (DWORD)atol(buf);
  if(Motor->GetLimit() != valueDW)
   Motor->SetLimit(valueDW);
  break;
  }
 if(FActivate) Motor->ActivateDrive();
 if(FFail) return FALSE;
 GetDlgItemText(GetHandle(),id_PositionWidth,(LPSTR)buf,10);
 valueW = (WORD)atoi(buf);
 if(0 != valueW)
  Motor->wPositionWidth = valueW;
  else
  return FALSE;

 GetDlgItemText(GetHandle(),id_PositionMax,(LPSTR)buf,10);
 Motor->lPositionMax = atol(buf);
 GetDlgItemText(GetHandle(),id_PositionMin,(LPSTR)buf,10);
 Motor->lPositionMin = atol(buf);
 GetDlgItemText(GetHandle(),id_AngleMax,(LPSTR)buf,10);
 valueF = atof(buf);
 if((0.0 != valueF))
  {
  Motor->dAngleMax = valueF;
  }
  else return FALSE;
 GetDlgItemText(GetHandle(),id_AngleMin,(LPSTR)buf,10);
 valueF = atof(buf);
 if((0.0 != valueF))
  {
  Motor->dAngleMin = valueF;
  }
  else return FALSE;
 GetDlgItemText(GetHandle(),id_AngleWidth,(LPSTR)buf,10);
 valueF = atof(buf);
 if(0.0 != valueF)
  {
  Motor->SetAngleWidth(valueF);
  }
  else return FALSE;
 return TRUE;
 };

//******************************************************************************
TOptimizeDC_832::TOptimizeDC_832(void) : TModalDlg("OptimizeDC_832")
 {
 Drive = (TC_832*)lpMList->MP();
 bCancel = TRUE;
 };

BOOL TOptimizeDC_832::Dlg_OnInit(HWND hwnd,HWND hwndCtl,LPARAM)
 {
 old_vel    = Drive->dwMaxVelocity;
 old_accel  = Drive->dwAcceleration;
 old_kp     = Drive->wKP;
 old_kd     = Drive->wKD;
 old_ki     = Drive->wKI;
 old_kl     = Drive->wKL;
 old_poswidth= Drive->wPositionWidth;
 FORWARD_WM_COMMAND(hwnd,cm_ParamSet,hwndCtl,0,SendMessage);
 return TRUE;
 };

void TOptimizeDC_832::Dlg_OnCommand(HWND hwnd,int id,HWND hwndCtl,UINT codeNotify)
 {
 char buf[MaxString];

 switch(id){
  case cm_ParamSet:
  sprintf(buf,"Optimize DCM-Parameter for %s",Drive->pCharacteristic());
  SetWindowText(GetHandle(),buf);
  sprintf(buf,"%ld",Drive->dwMaxVelocity);
  SetDlgItemText(GetHandle(),id_Velocity,(LPSTR)buf);
  sprintf(buf,"%ld",Drive->dwAcceleration);
  SetDlgItemText(GetHandle(),id_Acceleration,(LPSTR)buf);
  sprintf(buf,"%d",Drive->wKD);
  SetDlgItemText(GetHandle(),id_kd,(LPSTR)buf);
  sprintf(buf,"%d",Drive->wKP);
  SetDlgItemText(GetHandle(),id_kp,(LPSTR)buf);
  sprintf(buf,"%d",Drive->wKI);
  SetDlgItemText(GetHandle(),id_ki,(LPSTR)buf);
  sprintf(buf,"%d",Drive->wKL);
  SetDlgItemText(GetHandle(),id_kl,(LPSTR)buf);
  sprintf(buf,"%d",Drive->wPositionWidth);
  SetDlgItemText(GetHandle(),id_PositionWidth,(LPSTR)buf);
  break;

  case cm_StartMoveScan:
  GetDlgItemText(GetHandle(),id_Velocity,buf,MaxString);
  Drive->dwMaxVelocity = atol(buf);
  GetDlgItemText(GetHandle(),id_Acceleration,buf,MaxString);
  Drive->dwAcceleration = atol(buf);
  GetDlgItemText(GetHandle(),id_kd,buf,MaxString);
  Drive->wKD = (WORD)atoi(buf);
  GetDlgItemText(GetHandle(),id_kp,buf,MaxString);
  Drive->wKP = (WORD)atoi(buf);
  GetDlgItemText(GetHandle(),id_ki,buf,MaxString);
  Drive->wKI = (WORD)atoi(buf);
  GetDlgItemText(GetHandle(),id_kl,buf,MaxString);
  Drive->wKL = (WORD)atoi(buf);
  GetDlgItemText(GetHandle(),id_PositionWidth,buf,MaxString);
  Drive->wPositionWidth = (WORD)atoi(buf);
  Drive->ActivateFilterParameters();
  mStartMoveScan(10,0);
  return;

  default:
  TModalDlg::Dlg_OnCommand(hwnd,id,hwndCtl,codeNotify);
  }
 return;
 };

BOOL TOptimizeDC_832::CanClose(void)
 {
 bCancel = FALSE;
 Drive->SaveSettings(0);
 return TRUE;
 };

BOOL TOptimizeDC_832::LeaveDialog(void)
 {
 if(bCancel)
  {
  Drive->dwMaxVelocity  = old_vel;
  Drive->dwAcceleration = old_accel;
  Drive->wKP            = old_kp;
  Drive->wKD            = old_kd;
  Drive->wKI            = old_ki;
  Drive->wKL            = old_kl;
  Drive->wPositionWidth = old_poswidth;
  }
 Drive->ActivateFilterParameters();
 return TRUE;
 };
//******************************************************************************
//******************************************************************************
void TC_812::OptimizingDlg(void)
 {
 TModalDlg* dlg;

 dlg = (TOptimizeDC_812 *)new TOptimizeDC_812();
 dlg->ExecuteDialog(GetFrameHandle());
 delete dlg;
 };

TOptimizeDC_812::TOptimizeDC_812(void) : TModalDlg("OptimizeDC_812")
 {
 Drive = (TC_812*)lpMList->MP();
 bCancel = TRUE;
 };

#pragma argsused
BOOL TOptimizeDC_812::Dlg_OnInit(HWND hwnd,HWND hwndCtl,LPARAM lParam)
 {
 old_vel     = Drive->dwMaxVelocity;
 old_accel   = Drive->dwAcceleration;
 old_gain    = Drive->wStaticGain;
 old_dgain   = Drive->wDynamicGain;
 old_torque  = Drive->wTorque;
 old_poswidth= Drive->wPositionWidth;
 FORWARD_WM_COMMAND(hwnd,cm_ParamSet,hwndCtl,0,SendMessage);
 return TRUE;
 };

void TOptimizeDC_812::Dlg_OnCommand(HWND hwnd,int id,HWND hwndCtl,UINT codeNotify)
 {
 char buf[MaxString];

 switch(id){
  case cm_ParamSet:
  sprintf(buf,szMsgLine011,Drive->pCharacteristic());
  SetWindowText(hwnd,buf);
  sprintf(buf,"%ld",Drive->dwMaxVelocity);
  SetDlgItemText(hwnd,id_Velocity,(LPSTR)buf);
  sprintf(buf,"%ld",Drive->dwAcceleration);
  SetDlgItemText(hwnd,id_Acceleration,(LPSTR)buf);
  sprintf(buf,"%d",Drive->wTorque);
  SetDlgItemText(hwnd,id_Torque,(LPSTR)buf);
  sprintf(buf,"%d",Drive->wStaticGain);
  SetDlgItemText(hwnd,id_Gain,(LPSTR)buf);
  sprintf(buf,"%d",Drive->wDynamicGain);
  SetDlgItemText(hwnd,id_DynamicGain,(LPSTR)buf);
  sprintf(buf,"%d",Drive->wPositionWidth);
  SetDlgItemText(hwnd,id_PositionWidth,(LPSTR)buf);
  break;

  case cm_StartMoveScan:
  GetDlgItemText(hwnd,id_Velocity,buf,MaxString);
  Drive->dwMaxVelocity = atol(buf);
  GetDlgItemText(hwnd,id_Acceleration,buf,MaxString);
  Drive->dwAcceleration = atol(buf);
  GetDlgItemText(hwnd,id_Gain,buf,MaxString);
  Drive->wStaticGain = (WORD)atoi(buf);
  GetDlgItemText(hwnd,id_DynamicGain,buf,MaxString);
  Drive->wDynamicGain = (WORD)atoi(buf);
  GetDlgItemText(hwnd,id_Torque,buf,MaxString);
  Drive->wTorque = (WORD)atoi(buf);
  GetDlgItemText(GetHandle(),id_PositionWidth,buf,MaxString);
  Drive->wPositionWidth = (WORD)atoi(buf);
  Drive->ActivateFilterParameters();
  mStartMoveScan(15,0);
  break;

  default:
  TModalDlg::Dlg_OnCommand(hwnd,id,hwndCtl,codeNotify);
  }
 };

BOOL TOptimizeDC_812::CanClose(void)
 {
 char buf[MaxString];

 bCancel = FALSE;
 GetDlgItemText(GetHandle(),id_Velocity,buf,MaxString);
 Drive->dwMaxVelocity = atol(buf);
 GetDlgItemText(GetHandle(),id_Acceleration,buf,MaxString);
 Drive->dwAcceleration = atol(buf);
 GetDlgItemText(GetHandle(),id_Gain,buf,MaxString);
 Drive->wStaticGain = (WORD)atoi(buf);
 GetDlgItemText(GetHandle(),id_DynamicGain,buf,MaxString);
 Drive->wDynamicGain = (WORD)atoi(buf);
 GetDlgItemText(GetHandle(),id_Torque,buf,MaxString);
 Drive->wTorque = (WORD)atoi(buf);
 Drive->ActivateFilterParameters();
 Drive->SaveSettings(0);
 return TRUE;
 };

BOOL TOptimizeDC_812::LeaveDialog(void)
 {
 if(bCancel)
  {
  Drive->dwMaxVelocity  = old_vel;
  Drive->dwAcceleration = old_accel;
  Drive->wTorque        = old_torque;
  Drive->wStaticGain    = old_gain;
  Drive->wDynamicGain   = old_dgain;
  Drive->wPositionWidth = old_poswidth;
  Drive->ActivateFilterParameters();
  }
 return TRUE;
 };
//******************************************************************************
//******************************************************************************
TMotor::TMotor()
 {
 char       Ident[MaxString];
 char     ifile[MaxString];
 char     buf[MaxString];

 nId                 = nMaxId++;
 dAngleBias          = 0.0;
 dAngle       = 0.0;
 lCorrPos      = 0;
 fCorrBias      = 0.0;
 bIndexLine     = FALSE;
 bIndexDetected     = FALSE;
 bControlBoardOk   = FALSE;
 bLimitWatchActive  = FALSE;
 eCorrStatus     = CorrLinear;
 bIsCalibrated      = FALSE;
 bInquireStatus     = FALSE;
 bRangeHit          = FALSE;
 bUpwards           = TRUE;
 lDeltaPosition      = 0;
 lPosition          = 0;
 lPreviousPosition  = 0;
 strcpy(ifile,GetCFile());
 sprintf(Ident,"motor%d",nId);
 GetPrivateProfileString(Ident,"Name","Motor",szCharacteristic,MaxString,GetCFile());
 WritePrivateProfileString(Ident,"Name",szCharacteristic,GetCFile());
 dwHysteresis = (DWORD)GetPrivateProfileInt(Ident,"Hysteresis",0,GetCFile());
 WritePrivateProfileString(Ident,"Hysteresis",ltoa(dwHysteresis,buf,10),GetCFile());
 strcpy(buf,szCharacteristic);
 switch(lpMList->ParsingAxis(buf)) {
  case Rotation: case Phi:
  lpMList->AD_Phi = nId;
  lpMList->AD_Rotation = nId;
  break;

  case X:
  lpMList->AD_X = nId;
  break;

  case Y:
  lpMList->AD_Y = nId;
  break;

  case Z:
  lpMList->AD_Z = nId;
  break;

  case Theta:
  lpMList->AD_Theta = nId;
  break;

  case Omega: case DF:
  lpMList->AD_Omega = nId;
  lpMList->AD_DF = nId;
  break;

  case Tilt: case Psi:
  lpMList->AD_Psi = nId;
  lpMList->AD_Tilt = nId;
  break;

  case DC:
  lpMList->AD_DC = nId;
  break;

  case Collimator:
  lpMList->AD_Collimator = nId;
  break;

  case Absorber:
  lpMList->AD_Absorber = nId;
  break;

  case Monochromator:
  lpMList->AD_Monochromator = nId;
  break;

  case Encoder:
  lpMList->AD_Encoder = nId;
  break;
  }
 };

TMotor::Initialize(void)
 {
 HCURSOR       hCursorOld;
 float     MaxFailure;
 char       Ident[MaxString+1];
 char     buf[MaxString+1];

 hCursorOld = SetCursor(LoadCursor(NULL,IDC_WAIT));
 // Motor identifizieren
 sprintf(Ident,"motor%d",nId);
 GetPrivateProfileString(Ident,"MaxVelocity","8000",buf,MaxString,GetCFile());
 if(CreateDefaults())
  WritePrivateProfileString(Ident,"MaxVelocity",buf,GetCFile());
 dwMaxVelocity = atol(buf);
 GetPrivateProfileString(Ident,"Velocity","8000",buf,MaxString,GetCFile());
 if(CreateDefaults())
  WritePrivateProfileString(Ident,"Velocity",buf,GetCFile());
 dwVelocity = atol(buf);
 if(dwVelocity == 0)
  dwVelocity = dwMaxVelocity / 2;
 GetPrivateProfileString(Ident,"Unit","Unit",szUnit,20,GetCFile());
 if(CreateDefaults())
  WritePrivateProfileString(Ident,"Unit",szUnit,GetCFile());
 eUnit = UnitEnum(szUnit);
 strcpy(DFmt,"%.2lf");
 strcpy(SFmt,"%.2lf");
 GetPrivateProfileString(Ident,"Digits","2",buf,MaxString,GetCFile());
 DFmt[2] = (char)('0' + atoi(buf));
 SFmt[2] = (char)('1' + atoi(buf));
 if(CreateDefaults())
  WritePrivateProfileString(Ident,"Digits",buf,GetCFile());
 GetPrivateProfileString(Ident,"MinimalWidth","10",buf,MaxString,GetCFile());
 if(CreateDefaults())
  WritePrivateProfileString(Ident,"MinimalWidth",buf,GetCFile());
 wPositionMinWidth = (WORD)atoi(buf);
 GetPrivateProfileString(Ident,"MaximalWidth","510",buf,MaxString,GetCFile());
 if(CreateDefaults())
  WritePrivateProfileString(Ident,"MaximalWidth",buf,GetCFile());
 wPositionMaxWidth = (WORD)atoi(buf);
 GetPrivateProfileString(Ident,"PositionMin","-100",buf,MaxString,GetCFile());
 if(CreateDefaults())
  WritePrivateProfileString(Ident,"PositionMin",buf,GetCFile());
 lPositionMin = atol(buf);
 GetPrivateProfileString(Ident,"PositionMax","100",buf,MaxString,GetCFile());
 if(CreateDefaults())
  WritePrivateProfileString(Ident,"PositionMax",buf,GetCFile());
 lPositionMax = atol(buf);
 if(lPositionMax <= lPositionMin)
  lPositionMax = lPositionMin + 100;
 GetPrivateProfileString(Ident,"PositionWidth","10",buf,MaxString,GetCFile());
 if(CreateDefaults())
  WritePrivateProfileString(Ident,"PositionWidth",buf,GetCFile());
 wPositionWidth = (WORD)atoi(buf);
 if(wPositionWidth == 0)
  wPositionWidth = 0.2;
 GetPrivateProfileString(Ident,"InitialMove","0",buf,MaxString,GetCFile());
 if(CreateDefaults())
  WritePrivateProfileString(Ident,"InitialMove",buf,GetCFile());
 bInitialMoveReady = atoi(buf);

 GetPrivateProfileString(Ident,"RestartPosible","0",buf,MaxString,GetCFile());
 WritePrivateProfileString(Ident,"RestartPosible","0",GetCFile());
 if(bInitialMoveReady)
  SetCalibrationState(atoi(buf));
  else
  SetCalibrationState(TRUE);

 GetPrivateProfileString(Ident,"DeltaPosition","0",buf,MaxString,GetCFile());
 lDeltaPosition = atol(buf);
 if(IsCalibrated())
  {
  if(!bUpwards)
   lDeltaPosition += dwHysteresis;
  }
 dAngleBias = 0.0;
 lCorrPos = 0;

 GetPrivateProfileString(Ident,"DistanceToZero","0",buf,MaxString,GetCFile());
 if(CreateDefaults())
  WritePrivateProfileString(Ident,"DistanceToZero",buf,GetCFile());
 lDistanceToZero = atol(buf);

 GetPrivateProfileString(Ident,"RemoveLimit","4000",buf,MaxString,GetCFile());
 if(CreateDefaults())
  WritePrivateProfileString(Ident,"RemoveLimit",buf,GetCFile());
 dwRemoveLimit = (DWORD)atol(buf);
 GetPrivateProfileString(Ident,"MoveFirstToLimit","0",buf,MaxString,GetCFile());
 bMoveFirstToLimit = atoi(buf);
 GetPrivateProfileString(Ident,"IndexLine","0",buf,MaxString,GetCFile());
 bIndexLine = atoi(buf);
 GetPrivateProfileString(Ident,"InitialAngle","0.0",buf,MaxString,GetCFile());
 if(CreateDefaults())
  WritePrivateProfileString(Ident,"InitialAngle",buf,GetCFile());
 dInitialAngle = atof(buf);
 GetPrivateProfileString(Ident,"Acceleration","10",buf,MaxString,GetCFile());
 if(CreateDefaults())
  WritePrivateProfileString(Ident,"Acceleration",buf,GetCFile());
 dwAcceleration = atol(buf);
 GetPrivateProfileString(Ident,"AngleMin","-1.0",buf,MaxString,GetCFile());
 if(CreateDefaults())
  WritePrivateProfileString(Ident,"AngleMin",buf,GetCFile());
 dAngleMin = atof(buf);
 GetPrivateProfileString(Ident,"AngleMax","1.0",buf,MaxString,GetCFile());
 if(CreateDefaults())
  WritePrivateProfileString(Ident,"AngleMax",buf,GetCFile());
 dAngleMax = atof(buf);
 GetPrivateProfileString(Ident,"AngleWidth","0.1",buf,MaxString,GetCFile());
 if(CreateDefaults())
  WritePrivateProfileString(Ident,"AngleWidth",buf,GetCFile());
 dAngleWidth = atof(buf);
 GetPrivateProfileString(Ident,"Koeff_3","0.0",buf,MaxString,GetCFile());
 if(CreateDefaults())
  WritePrivateProfileString(Ident,"Koeff_3",buf,GetCFile());
 dKoeff_3 = atof(buf);
 GetPrivateProfileString(Ident,"Koeff_2","0.0",buf,MaxString,GetCFile());
 if(CreateDefaults())
  WritePrivateProfileString(Ident,"Koeff_2",buf,GetCFile());
 dKoeff_2 = atof(buf);
 GetPrivateProfileString(Ident,"Koeff_1","1.0",buf,MaxString,GetCFile());
 if(CreateDefaults())
  WritePrivateProfileString(Ident,"Koeff_1",buf,GetCFile());
 dKoeff_1 = atof(buf);
 GetPrivateProfileString(Ident,"SpeedScale","10.0",buf,MaxString,GetCFile());
 if(CreateDefaults())
  WritePrivateProfileString(Ident,"SpeedScale",buf,GetCFile());
 fSpeedScale = atof(buf);
 SetCursor(hCursorOld);
 GetPrivateProfileString(Ident,"MaxFailure","30.0",buf,MaxString,GetCFile());
 if(CreateDefaults())
  WritePrivateProfileString(Ident,"MaxFailure",buf,GetCFile());
 MaxFailure = atof(buf);
 dwInterval  = (DWORD)(3.0 * MaxFailure / dKoeff_1);
 switch(eUnit) {
  case Grad:   dwInterval  *= 3600;  break;
  case Minuten: dwInterval  *= 60;   break;
  }
 GetPrivateProfileString(Ident,"Correction","0",buf,MaxString,GetCFile());
 if(CreateDefaults())
  WritePrivateProfileString(Ident,"Correction",buf,GetCFile());
 bCorrection = atoi(buf);
 SetCorrectionState(TRUE);
 return R_OK;
 };

//*************** Element-Funktionen ******************************************
BOOL TMotor::SetAngleRange(void)
 {
 double   a1,a2;

 Translate(a1,lPositionMin);
 Translate(a2,lPositionMax);
 dAngleMax = max(a1,a2);
 dAngleMin = min(a1,a2);
 return TRUE;
 };

BOOL  TMotor::PushSettings(void)
 {
 Settings.dAngle       = dAngle;
 Settings.dAngleMin    = dAngleMin;
 Settings.dAngleMax    = dAngleMax;
 Settings.dAngleWidth  = dAngleWidth;
 Settings.dSpeed       = dSpeed;
 return TRUE;
 };

BOOL  TMotor::PopSettings(TMParameter param)
 {
 if(dAngle != Settings.dAngle)
  if(param == OldPosition)
   MoveToAngle(Settings.dAngle);
 dAngleMin    = Settings.dAngleMin;
 dAngleMax    = Settings.dAngleMax;
 SetAngleWidth(Settings.dAngleWidth);
 SetSpeed(Settings.dSpeed);
 return TRUE;
 };

// Umrechnung von Position in Winkel mit einem Polynom
// Umkehrfunktion mit Newton-Verfahren
void TMotor::funcd(double arg,double offset,double *f,double *df)
 {
 *f  = arg * (dKoeff_1 + arg * (dKoeff_2 + arg * dKoeff_3)) - offset;
 *df = dKoeff_1 + arg * (2*dKoeff_2 + arg * 3*dKoeff_3);
 };

int  TMotor::rtsave(double offset,double x1,double x2,double xacc,double *ret)
 /*  Using a combination of Newton-Raphson and bisection, find the  */
 /*  root of a function bracketed between x1 and x2. The root, re-  */
 /*  turned as the function value rtsafe, will be refined until its  */
 /*  accuracy is known within +-xacc. funcd is a user-supplied rou-  */
 /*  tine that provides both the function value and the first deriv-  */
 /*  ative of the function.                      */
 {
 int      j;
 double  df,dx,dxold,f,fh,fl,xh,xl,rts;

 funcd(x1,offset,&fl,&df);
 funcd(x2,offset,&fh,&df);
 if((fl)*(fh)>=0.0)
   return -1; // "Root must be bracketed in RTSAFE"
 if((fl)<0.0) // Orient the search so that f(xl)<0.
  {
  xl=x1; xh=x2;
  }
  else
  {
  xh=x1; xl=(fl); fl=fh; fh=xl; xl=x2;
  }
 rts = 0.5*(x1+x2);
 // Initialize the guess for root,
 dx=dxold=fabs(x2-x1);
 //  the "step-size before last" and the last step.
 funcd(rts,offset,&f,&df);
 for(j=1;j<=MAXIT;j++)
 //  Loop over allowed iterations.
  {
  if((((rts-xh)*df-f)*((rts-xl)*df-f)>=0.0)
  // Bisect if Newton out of range,
   ||(fabs(2.0*f)>fabs(dxold*df)))
  // or not decreasing fast enough.
   {
   dxold = dx;
   dx = 0.5*(xh-xl);
   rts = xl+dx;
   if(xl==rts)
    {
    //  Change in root is negligible.
    *ret = rts;
    return 0;
    }
   }
   else
   // Newton step acceptable. Take it.
   {
   dxold = dx;
   dx = f/df;
   df = rts;
   rts -= dx;
   if(df==rts)
    {
    *ret = rts;
    return 0;
    }
   }
  if(fabs(dx)<xacc)
  // Convergence criterion.
   {
    *ret = rts;
   return 0;
   }
  funcd(rts,offset,&f,&df);
  // The one new function evaluation per iteration.
  if(f<0.0)
   // Maintain the bracket on the root.
   {
   xl = rts; fl = f;
   }
   else
   {
   xh = rts; fh = f;
   }
  }
 return -2; // "Maximum number of iterations exceeded in RTSAFE"
 };

BOOL TMotor::Translate(long &pos,double ang)
 {
 // translate angle to position
 char      buffer[MaxString];
 double    l_ang;
 double  l_pos;
 double    xleft,xright;
 int       ret;

 // Liegt Winkel im Bereich ?
 bRangeHit = FALSE;
 l_ang = ang - dAngleBias + fCorrBias;
 if(l_ang > dAngleMax)
  {
  bRangeHit = TRUE; l_ang = dAngleMax;
  }
 if(ang < dAngleMin)
  {
  bRangeHit = TRUE; l_ang = dAngleMin;
  }
 // *bersetzen des Winkels in eine Position
 switch(eUnit) {
  case Grad:   l_ang = l_ang * 3600.0; break;
  case Minuten: l_ang = l_ang * 60.0;   break;
  }
 switch(eCorrStatus) {
  case CorrPolynom:
  xleft = xright = l_ang / dKoeff_1;
  xright += dwInterval;
  xleft  -= dwInterval;
  ret = rtsave(l_ang,xleft,xright,1,&l_pos);
  if(ret)
   {
   sprintf(buffer,"Newton %d !\n",ret);
   MessageBox(GetFocus(),buffer,szMsgFailure,MBINFO);
   return FALSE;
   }
  break;

  default:
  l_pos = l_ang / dKoeff_1;
  }
 pos = max(min((long)ceil(l_pos),lPositionMax),lPositionMin);
 return TRUE;
 };

BOOL TMotor::Translate(double&ang,long pos)
 {
 // translate position to angle
 double    l_ang;

 // Positions-Offset ber‚cksichtigen
 switch(eCorrStatus) {
  case CorrPolynom:
  l_ang = pos * (dKoeff_1 + pos * (dKoeff_2 + pos * dKoeff_3));
  break;

  default:
  l_ang = pos * dKoeff_1;
  }

 switch(eUnit) {
  case Grad:
  l_ang = l_ang / 3600.0;
  break;
  case Minuten:
  l_ang = l_ang / 60.0;
  }
 ang = l_ang + dAngleBias - fCorrBias;
 return TRUE;
 };

void TMotor::SetCorrectionState(BOOL onoff)
 {
 long  dcpos;
 float  ang1,ang2;

 lCorrPos  = 0;
 fCorrBias = 0.0;
 if(!bCorrection || !bIsCalibrated)
  {
  eCorrStatus = CorrLinear;
  return;
  }
 if(onoff)
  {
  if(nId != lpMList->AD_DF)
   {
   eCorrStatus = CorrPolynom;
   return;
   }
  lpMList->MP(lpMList->AD_DC)->GetPosition(1);
  dcpos = lpMList->MP(lpMList->AD_DC)->lPosition;
  if(dcpos == lCorrPos)
   {
   eCorrStatus = CorrPolynom;
   return;
   }
  GetAngle(1);
  ang1 = dAngle;
  lCorrPos = dcpos;
  fCorrBias = 0.0;
  eCorrStatus = CorrPolynom;
  GetAngle(1); // MS-Pos
  ang2 = dAngle;
  fCorrBias = ang2 - ang1;
  }
  else
  {
  eCorrStatus = CorrLinear;
  lCorrPos   = 0;
  fCorrBias   = 0.0;
  }
 };

BOOL TMotor::SetHome(void)
 {
 bIsCalibrated  = FALSE;
 SetCorrectionState(0);
 lPreviousPosition = GetPosition(1);
 lDeltaPosition  = 0;
 lPosition    = 0;
 dAngle     = 0.0;
 dAngleBias   = 0.0;
 return TRUE;
 };

BOOL TMotor::MoveByPosition(long pos)
 {
 lPosition += pos;
 return TRUE;
 };

BOOL TMotor::MoveToPosition(long pos)
 {
 lPosition = pos;
 return TRUE;
 };

BOOL TMotor::MoveToAngle(double ang)
 {
 long lpos;

 if(Translate(lpos,ang))
  if(MoveToPosition(lpos))
   return TRUE;
 return FALSE;
 };

BOOL TMotor::MoveByAngle(double ang)
 {
 long lpos;

 if(!GetAngle(1))
  return FALSE;
 if(Translate(lpos,(ang+dAngle)))
  if(MoveToPosition(lpos))
   return TRUE;
 return FALSE;
 };

BOOL TMotor::SetAngleWidth(double dang)
 {
 double dposcmp,dpos;

 switch(eUnit) {
  case Grad:   dposcmp = dpos = 3600.0 * fabs(dang / dKoeff_1);  break;
  case Minuten: dposcmp = dpos = 60.0 * fabs(dang / dKoeff_1);  break;
  default:    dposcmp = dpos = fabs(dang / dKoeff_1);  break;
  }
 dpos = max(min(dpos,(double)wPositionMaxWidth),(double)wPositionMinWidth);
 switch(eUnit) {
  case Grad:
  dAngleWidth = fabs(dKoeff_1 * dpos / 3600.0);
  break;
  case Minuten:
  dAngleWidth = fabs(dKoeff_1 * dpos / 60.0);
  break;
  default:
  dAngleWidth = fabs(dKoeff_1 * dpos);
  }
 if(dpos != dposcmp)
  return FALSE;
 return TRUE;
 };

BOOL TMotor::GetAngle(BOOL saveyesno)
 {
 double ang;

 if(!GetPosition(saveyesno))
  return FALSE;
 if(!Translate(ang,lPosition))
  return FALSE;
 dAngle = ang;
#ifdef CheckCorrect
 if(saveyesno)
  {
  char buf[MaxString];
  sprintf(buf,"P:%ld dP:%ld dW:%.2f",lPosition,lCorrPos,fCorrBias);
  SetInfo(buf);
  }
#endif
 return TRUE;
 };

int TMotor::SaveSettings(BOOL LastSave)
 {
 //*** Abspeichern der Motoreinstellungen in den Parameter-File.
 HCURSOR     hCursorOld;
 char        buf[MaxString];
 char      Ident[MaxString];

 if(!bControlBoardOk) return R_Failure;
 sprintf(Ident,"motor%d",nId);
 hCursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
 sprintf(buf,"%ld",lDistanceToZero);
 WritePrivateProfileString(Ident,"DistanceToZero",buf,GetCFile());
 if(LastSave)
  {
  SetCorrectionState(OFF);
  sprintf(buf,"%ld",dwVelocity);
  WritePrivateProfileString(Ident,"Velocity",buf,GetCFile());
  sprintf(buf,"%u",wPositionWidth);
  WritePrivateProfileString(Ident,"PositionWidth",buf,GetCFile());
  sprintf(buf,"%d",bUpwards);
  WritePrivateProfileString(Ident,"Upwards",buf,GetCFile());
  GetPosition(TRUE);
  sprintf(buf,"%ld",lPosition);
  WritePrivateProfileString(Ident,"DeltaPosition",buf,GetCFile());
  sprintf(buf,pDF(),dAngleMin);
  WritePrivateProfileString(Ident,"AngleMin",buf,GetCFile());
  sprintf(buf,pSF(),dAngleWidth);
  WritePrivateProfileString(Ident,"AngleWidth",buf,GetCFile());
  sprintf(buf,pDF(),dAngleBias);
  WritePrivateProfileString(Ident,"AngleBias",buf,GetCFile());
  sprintf(buf,pDF(),dAngleMax);
  WritePrivateProfileString(Ident,"AngleMax",buf,GetCFile());
  if(bIsCalibrated)
   WritePrivateProfileString(Ident,"RestartPosible","1",GetCFile());
  }
 SetCursor(hCursorOld);
 return R_OK;
 };

//******************************************************************************
TDC_Drive::TDC_Drive(void) : TMotor()
 {
 char    Ident[MaxString];

 nMaxError    = 2;
 sprintf(Ident,"motor%d",nId);
 wDeathBand = (WORD)GetPrivateProfileInt(Ident,"DeathBand",1,GetCFile());
 wDeccelerationPoint = (WORD)GetPrivateProfileInt(Ident,"DeccelerationPoint",20,GetCFile());
 };

int TDC_Drive::SaveSettings(BOOL onlythis)
 {
 return TMotor::SaveSettings(onlythis);
 }

int TDC_Drive::Initialize(void)
 {
 char      buf[MaxString];

 if(R_OK != TMotor::Initialize())
  goto Exit;
 if(CheckBoardOk())
  {
  if(!Reset())
   goto Exit;
  if(!ActivateFilterParameters())
   goto Exit;
  if(!ActivateDrive())
   goto Exit;
  }
  else
  {
  sprintf(buf,szMsgLine012,pCharacteristic());
  MessageBox(GetFocus(),buf,szMsgFailure,MBSTOP);
#ifdef TESTLAUF
  return R_NoCommunication;
#endif
  }
 return R_OK;
Exit:
#ifdef TESTLAUF
 return FALSE;
#else
 return R_OK;
#endif
 };

BOOL TDC_Drive::PushSettings(void)
 {
 return TRUE;
 };

BOOL TDC_Drive::PopSettings(void)
 {
 return TRUE;
 };

BOOL TDC_Drive::MoveToPosition(long position)
 {
 // Ber‚cksichtigen des Spiels
 if(bUpwards && (position < lPosition))
  {
  lDeltaPosition += dwHysteresis;
  bUpwards = FALSE;
  }
  else
  if(!bUpwards && (position > lPosition))
   {
   lDeltaPosition -= dwHysteresis;
   bUpwards = TRUE;
   };
 // Ber‚cksichtigen der relativen Position nach Programm-Start und Richtungswechsel
 position -= lDeltaPosition + lCorrPos;
 return MoveAbsolute(position);
 };

BOOL TDC_Drive::MoveByPosition(long distance)
 {
 return MoveRelative(distance);
 };

BOOL TDC_Drive::SetSpeed(double speed)
 {
 DWORD  velocity;

 velocity = fSpeedScale * speed;
 SetVelocity(velocity);
 dSpeed = (double)GetVelocity() / fSpeedScale;
 return TRUE;
 };

double TDC_Drive::GetSpeed(void)
 {
 DWORD    vel;

 vel = GetVelocity();
 if(vel == 0) return 0.0;
 dSpeed = (double)vel / fSpeedScale;
 return dSpeed;
 };

BOOL TDC_Drive::GetPosition(BOOL bSave)
 {
 long  pos1,pos2;

 if(_GetPosition(&pos1))
  {
  if(bSave)
   {
   if(!_GetPosition(&pos2)) return FALSE;
   if(pos1 != pos2) return FALSE;
   }
  // Ber‚cksichtigen der relativen Karten-Position
  lPosition = pos1 + lDeltaPosition + lCorrPos;
  return TRUE;
  }
 return FALSE;
 };

long TDC_Drive::GetFailure(void)
 {
 long  failure;
 int   check = 3;

 while(!_GetFailure(&failure))
  {
  if(0 == check--)
   return 100;
  }
 return failure;
 };

//*************************************************************************
TC_812::TC_812(void) : TDC_Drive()
 {
 char    Ident[MaxString];

 sprintf(Ident,"motor%d",nId);
 nOnBoardId = GetPrivateProfileInt(Ident,"BoardId",1,GetCFile());
 wStaticGain = (WORD)GetPrivateProfileInt(Ident,"Gain",100,GetCFile());
 wDynamicGain = (WORD)GetPrivateProfileInt(Ident,"DynamicGain",37,GetCFile());
 wMaxTorque = 127;
 nWaitTicks = 5;
 wTorque = (WORD)GetPrivateProfileInt(Ident,"Torque",110,GetCFile());
 };

int TC_812::SaveSettings(BOOL bLastSave)
 {
 char  buf[MaxString];
 char Ident[MaxString];

 if(!bControlBoardOk) return R_Failure;
 sprintf(Ident,"motor%d",nId);
 sprintf(buf,"%u",wDynamicGain);
 WritePrivateProfileString(Ident,"DynamicGain",buf,GetCFile());
 sprintf(buf,"%u",wTorque);
 WritePrivateProfileString(Ident,"Torque",buf,GetCFile());
 sprintf(buf,"%u",wStaticGain);
 WritePrivateProfileString(Ident,"Gain",buf,GetCFile());
 sprintf(buf,"%lu",dwMaxVelocity);
 WritePrivateProfileString(Ident,"MaxVelocity",buf,GetCFile());
 sprintf(buf,"%lu",dwAcceleration);
 WritePrivateProfileString(Ident,"Acceleration",buf,GetCFile());
 sprintf(buf,"%lu",dwVelocity);
 WritePrivateProfileString(Ident,"Velocity",buf,GetCFile());
 return TDC_Drive::SaveSettings(bLastSave);
 };

BOOL TC_812::ActivateFilterParameters(void)
 {
 char  cmd[MaxString];

 sprintf(cmd,"%uDB%u\r",nOnBoardId,wDeathBand);
 if(R_OK != ExecuteCmd(cmd))
  return FALSE;
 sprintf(cmd,"%uSQ%u,%uSG%u,%uSE%u\r", nOnBoardId,wTorque,\
                    nOnBoardId,wStaticGain,\
                    nOnBoardId,wDynamicGain);
 if(R_OK!=ExecuteCmd(cmd))
  return FALSE;
 SetVelocity(dwMaxVelocity);
 SetAcceleration(dwAcceleration);
 SetLimit(dwRemoveLimit);
 GetSpeed();
 return TRUE;
 };

BOOL TC_812::Reset(void)
 {
 long lDeltaP = lDeltaPosition;
 BOOL bIsCal = IsCalibrated();
 BOOL  ret = SetHome();
 lDeltaPosition = lDeltaP;
 SetCalibrationState(bIsCal);
 nC812 = GetId();
 return ret;
 };

BOOL TC_812::SetMoment(float moment)
 {
 // Dreh-Moment 0 .. 1.0
 if(moment <= 1.0)
  wTorque = 127 * moment;
  else
  wTorque = 60;
 SetTorque(wTorque);
 return TRUE;
 };

float TC_812::GetMoment(void)
 {
 WORD torque;
 // Dreh-Moment 0 .. 1.0
 torque = GetTorque();
 return (torque / wMaxTorque);
 };

BOOL TC_812::SetLine(int number,BOOL status)
 {
 char      cmd[MaxString+1];

 if((1 > number) && (16 < number))
  return FALSE;
 if(status)
  sprintf(cmd,"%uCT%u,%uCN%u\r",nOnBoardId,number,nOnBoardId,number);
  else
  sprintf(cmd,"%uCT%u,%uCF%u\r",nOnBoardId,number,nOnBoardId,number);
 if(R_OK != ExecuteCmd(cmd))
  return FALSE;
 return TRUE;
 };

BOOL TC_812::IsLimitHit(void)
 {
 if(GetStatus() & StatMLimitHit)
  return TRUE;
  else
  return FALSE;
 };

BOOL TC_812::IsMoveFinish(void)
 {
 if(bInquireStatus)
  {
  if(GetStatus() & StatMStopped)
   return TRUE;
  }
  else
  {
  if(labs(GetFailure()) <= (long)wDeathBand)
   return TRUE;
  }
 return FALSE;
 };

BOOL TC_812::IsIndexArrived(void)
 {
 if(bIndexDetected && IsMoveFinish())
  return TRUE;
 if(IsLimitHit())
  {
  if(!bIndexDetected)
   {
   DelayTime(20);
   bIndexDetected = TRUE;
   }
  }
 return FALSE;
 };

BOOL TC_812::StartToIndex(long &oldPos)
 {
 SetSpeed(10000.0);
 lDeltaPosition = 0;
 SetCorrectionState(0);
 GetPosition(TRUE);
 oldPos = lPosition;
 bIndexDetected = FALSE;
 bIndexLine = FALSE;
 MoveToPosition(lPosition - 400000000l);
 // Die Motoren werden in Bewegung gesetzt
 // Erreichen der Stillstands-Position
 DelayTime(100);
 return TRUE;
 };

BOOL TC_812::ActivateDrive(void)
 {
 char      cmd[MaxString+1];

 sprintf(cmd,"%uSP%u\r",nOnBoardId,wDeccelerationPoint);
 if(R_OK != ExecuteCmd(cmd))
  return FALSE;
 sprintf(cmd,"%uMN\r",nOnBoardId);
 if(R_OK != ExecuteCmd(cmd))
  return FALSE;
 return TRUE;
 };

BOOL TC_812::StopDrive(int bOffOn)
 {
 char    cmd[MaxString+1];

 if(bOffOn)
  {
  sprintf(cmd,"%uAB\r",nOnBoardId);
  if(R_OK != ExecuteCmd(cmd))
   return FALSE;
  // Einige Motoren k÷nnen nach diesem Stop ihre Position
  // nicht mehr einregeln, deshalb ein zweites Kommando zum
  // zum Gleichsetzen von Target und Position
  Delay(100);
  sprintf(cmd,"%uAB\r",nOnBoardId);
  if(R_OK != ExecuteCmd(cmd))
   return FALSE;
  sprintf(cmd,"%uMN\r",nOnBoardId);
  if(R_OK != ExecuteCmd(cmd))
   return FALSE;
  }
  else
  {
  sprintf(cmd,"%uAB\r",nOnBoardId);
  if(R_OK != ExecuteCmd(cmd))
   return FALSE;
  }
 return TRUE;
 };

BOOL TC_812::SetDynamicGain(WORD dygain)
 {
 char    cmd[MaxString+1];

 dygain = min(dygain,(WORD)255);
 dygain = max(dygain,(WORD)1);
 wDynamicGain = dygain;
 sprintf(cmd,"%uSE%u\r",nOnBoardId,wDynamicGain);
 if(R_OK != ExecuteCmd(cmd))
  return FALSE;
 return TRUE;
 };

WORD TC_812::GetDynamicGain(void)
 {
 return wDynamicGain;
 };

BOOL TC_812::SetTorque(WORD torque)
 {
 char    cmd[MaxString+1];

 wTorque = min(torque,(WORD)127);
 sprintf(cmd,"%uSQ%u\r",nOnBoardId,wTorque);
 if(R_OK != ExecuteCmd(cmd))
  return FALSE;
 return TRUE;
 };

WORD TC_812::GetTorque(void)
 {
 wTorque = min(wTorque,(WORD)127);
 return wTorque;
 };

BOOL TC_812::SetVelocity(DWORD velocity)
 {
 char    cmd[MaxString+1];

 dwVelocity = (velocity<dwMaxVelocity)?velocity:dwMaxVelocity;
 sprintf(cmd,"%uSV%lu\r",nOnBoardId,dwVelocity);
 if(R_OK != ExecuteCmd(cmd))
  return FALSE;
 sprintf(cmd,"%uCP\r",nOnBoardId);
 if(R_OK != ExecuteCmd(cmd))
  return FALSE;
 return TRUE;
 };

DWORD TC_812::GetVelocity(void)
 {
 dwVelocity = (dwVelocity<dwMaxVelocity)?dwVelocity:dwMaxVelocity;
 return dwVelocity;
 };

BOOL TC_812::SetAcceleration(DWORD acceleration)
 {
 char    cmd[MaxString+1];

 dwAcceleration = acceleration;
 sprintf(cmd,"%uSA%lu\r",nOnBoardId,dwAcceleration);
 if(R_OK != ExecuteCmd(cmd))
  return FALSE;
 sprintf(cmd,"%uSD%lu\r",nOnBoardId,dwAcceleration);
 if(R_OK != ExecuteCmd(cmd))
  return FALSE;
 sprintf(cmd,"%uCP\r",nOnBoardId);
 if(R_OK != ExecuteCmd(cmd))
  return FALSE;
 return TRUE;
 };

DWORD TC_812::GetAcceleration(void)
 {
 return dwAcceleration;
 };

BOOL TC_812::SetLimit(DWORD limit)
 {
 char    cmd[MaxString+1];

 dwRemoveLimit = limit;
 sprintf(cmd,"%uLS%lu\r",nOnBoardId,dwRemoveLimit);
 if(R_OK != ExecuteCmd(cmd))
  return FALSE;
 return TRUE;
 };

BOOL TC_812::SetHome(void)
 {
 char    cmd[MaxString+1];

 // changing K-System
 TMotor::SetHome();
 sprintf(cmd,"%uDH\r",nOnBoardId);
 if(R_OK != ExecuteCmd(cmd))
  return FALSE;
 return TRUE;
 };

WORD TC_812::GetStatus(void)
 {
 char    buf[MaxString+1];
 char    msg[MaxString];
 char    *token;
 WORD    _status;

 sprintf(buf,"%uTS\r",nOnBoardId);
 switch(ExecuteCmd(buf)) {
  case R_OK:
  token = strtok(buf,"\n\3\r");
  if(!token) return FALSE;
  if((token[1]-'0') != nOnBoardId) return FALSE;
  if(token[2] != 'S') return FALSE;
  if(strlen(token) < 6) return FALSE;
  sscanf(&(token[3]),"%u",&_status);
  return _status;

  case R_TimeOut:
  sprintf(msg,"GetStatus: %s",buf);
  MessageBox(GetFocus(),msg,"TimeOut MS",MBFAILURE);
  return -1;

  case R_UnknownCmd:
  sprintf(msg,"GetStatus: %s",buf);
  MessageBox(GetFocus(),msg,"Fehler",MBFAILURE);
  return -1;

  default:
  return -1;
  }
 };

BOOL TC_812::_GetPosition(long *position)
 {
 char        buf[MaxString];
 char        msg[MaxString];
 char        *token;

 sprintf(buf,"%uTP\r",nOnBoardId);
 switch(ExecuteCmd(buf)) {
  case R_OK:
  token = strtok(buf,"\n\3\r");
  if(!token) return FALSE;
  if((token[1]-'0') != nOnBoardId) return FALSE;
  if(token[2] != 'P') return FALSE;
  sscanf(&(token[3]),"%ld",position);
  return TRUE;

  case R_TimeOut:
  sprintf(msg,"GetPosition: %s",buf);
  MessageBox(GetFocus(),msg,"TimeOut MS",MBFAILURE);
  return FALSE;

  case R_UnknownCmd:
  sprintf(msg,"GetPosition: %s",buf);
  MessageBox(GetFocus(),msg,"Fehler",MBFAILURE);
  return FALSE;

  default:
  return FALSE;
  }
 };

BOOL TC_812::_GetFailure(long *failure)
 {
 char        buf[MaxString+1];
 char        msg[MaxString];
 char        *token;
 sprintf(buf,"%uTE\r",nOnBoardId);
 switch(ExecuteCmd(buf)) {
  case R_OK:
  token = strtok(buf,"\n\3\r");
  if(!token) return FALSE;
  if((token[1]-'0') != nOnBoardId) return FALSE;
  if(token[2] != 'E') return FALSE;
  if(strlen(token) < 12)
   {
   nWaitTicks += 2;
   return FALSE;
   }
  sscanf(&(token[3]),"%ld",failure);
  return TRUE;

  case R_TimeOut:
  sprintf(msg,"GetFailure: %s",buf);
  MessageBox(GetFocus(),msg,"TimeOut MS",MBFAILURE);
  return FALSE;

  case R_UnknownCmd:
  sprintf(msg,"GetFailure: %s",buf);
  MessageBox(GetFocus(),msg,"Fehler",MBFAILURE);
  return FALSE;

  default:
  return FALSE;
  }
 };

BOOL TC_812::MoveRelative(long pos)
 {
 char    cmd[MaxString+1];

 sprintf(cmd,"%uMR%ld\r",nOnBoardId,pos);
 if(R_OK == ExecuteCmd(cmd))
  return TRUE;
 return FALSE;
 };

BOOL TC_812::MoveAbsolute(long pos)
 {
 char    cmd[MaxString+1];

 sprintf(cmd,"%uMA%ld\r",nOnBoardId,pos);
 if(R_OK == ExecuteCmd(cmd))
  return TRUE;
 return FALSE;
 };
//##############################################################################
//############## IEEE Interface ################################################
//##############################################################################
//##############################################################################
TC_812GPIB::TC_812GPIB(void) : TC_812()
 {
 char    Ident[MaxString],buf[MaxString];
 WORD  hostio,hostaddr;

 while(!hGPIBModule)
  {
  // IEEE - Controller initialisieren
  sprintf(Ident,"GPIB0",nId);
  hGPIBModule = LoadLibrary("win488.dll");
  if(!hGPIBModule)
   break;
  hostio = (WORD)GetPrivateProfileInt(Ident,"IOAddr",0x200,GetCFile());
  hostaddr = (WORD)GetPrivateProfileInt(Ident,"GPIBAddr",1,GetCFile());
  (FARPROC)gInitialize  = GetProcAddress(hGPIBModule,"IEEE488_INITIALIZE");
  (FARPROC)gSend        = GetProcAddress(hGPIBModule,"IEEE488_SEND");
  (FARPROC)gEnter       = GetProcAddress(hGPIBModule,"IEEE488_ENTER");
  (FARPROC)gTransmit    = GetProcAddress(hGPIBModule,"IEEE488_TRANSMIT");
  (FARPROC)gReceive     = GetProcAddress(hGPIBModule,"IEEE488_RECEIVE");
  (FARPROC)gSPoll       = GetProcAddress(hGPIBModule,"IEEE488_SPOLL");
  (FARPROC)gPPoll       = GetProcAddress(hGPIBModule,"IEEE488_PPOLL");
  (FARPROC)gSetPort   = GetProcAddress(hGPIBModule,"IEEE488_SETPORT");
  (FARPROC)gSetTimeout  = GetProcAddress(hGPIBModule,"IEEE488_SETTIMEOUT");
  (FARPROC)gSetOutputEOS= GetProcAddress(hGPIBModule,"IEEE488_SETOUTPUTEOS");
  (FARPROC)gSetInputEOS = GetProcAddress(hGPIBModule,"IEEE488_SETINPUTEOS");
  (FARPROC)gEnable488Ex = GetProcAddress(hGPIBModule,"IEEE488_ENABLE_488EX");
  (FARPROC)gEnable488SD = GetProcAddress(hGPIBModule,"IEEE488_ENABLE_488SD");
  (FARPROC)gListenerOk  = GetProcAddress(hGPIBModule,"IEEE488_LISTENER_PRESENT");
  (FARPROC)gBoardPresent= GetProcAddress(hGPIBModule,"IEEE488_BOARD_PRESENT");
  gSetPort(0,hostio);
  gInitialize(hostaddr,0);
  break;
  }
 sprintf(Ident,"motor%d",nId);
 wGPIBAddr = (WORD)GetPrivateProfileInt(Ident,"GPIBAddr",15,GetCFile());
 bInquireStatus = (BOOL)GetPrivateProfileInt(Ident,"InquireStatus",0,GetCFile());
 sprintf(buf,"%d",bInquireStatus);
 WritePrivateProfileString(Ident,"InquireStatus",buf,GetCFile());
 };

int TC_812GPIB::Initialize(void)
 {
 int  retval;

 if(!hGPIBModule)
  {
  MessageBox(GetFocus(),"Can't find win488.dll","Motor Library",MBSTOP);
  return R_Failure;
  }
 if(!gBoardPresent())
  {
  MessageBox(GetFocus(),"No GPIB-Controller present !","Failure",MBSTOP);
  return R_Failure;
  }
 gSetTimeout(100);
 gSetInputEOS(3);
 retval = TC_812::Initialize();
 return retval;
 };

BOOL TC_812GPIB::CheckBoardOk(void)
 {
 char  buf[MaxString];
 int   status;
 char  poll;

 if(!gListenerOk(wGPIBAddr))
  {
  sprintf(buf,"No GPIB-Device with Address %d present !",wGPIBAddr);
  MessageBox(GetFocus(),buf,"Failure",MBSTOP);
  return FALSE;
  }
 gSPoll(wGPIBAddr,&poll,&status);
 bControlBoardOk = TRUE;
 return TRUE;
 };

int TC_812GPIB::ExecuteCmd(char *pString)
 {
 char   buf[MaxString],poll;
 // char   info[20];
 int       status,retval = R_OK,cnt;
 WORD      length;
 static    BOOL    bCmdActive = FALSE;

 if(!bControlBoardOk)
  return 0;
 if(bCmdActive)
  return R_Failure;
 bCmdActive = TRUE;
 // Befehls-String senden
 sprintf(buf,"UNL UNT MTA LISTEN %d DATA ' %s'",wGPIBAddr,pString);
 gTransmit(buf,0xFFFF,&status);
 if(status != 0)
  {
  retval = R_Failure;
  goto Exit;
  }
#ifdef WriteLog
 FILE  *LogFile;
 LogFile = fopen("\\motor.log","a");
 if(LogFile)
  {
  fseek(LogFile,0,2);
  fwrite(pString,strlen(pString),1,LogFile);
  fclose(LogFile);
  }
#else
 Delay(3);
#endif
 // Antwort empfangen
 cnt = 0;
 do
  {
  gSPoll(wGPIBAddr,&poll,&status);
  if(0x41 == poll)
   {
   Delay(3);
   break;
   }
  if(0x12 == poll)
   {
   Delay(3);
   break;
   }
  if(0x2 == poll)
   {
   Delay(7);
   }
  if(++cnt > 20) break;
  }
 while(1);
 // Feststellen, ob im vorherigen Kommando ein Fehler aufgetreten ist
 if(poll & 0x4)
  {
#ifdef WriteLog
 FILE  *LogFile;
 LogFile = fopen("\\motor.log","a");
 if(LogFile)
  {
  fseek(LogFile,0,2);
  fwrite(pString,strlen(pString),1,LogFile);
  fclose(LogFile);
  }
 MessageBox(GetFocus(),(LPSTR)pString,"Command Failure",MBSTOP);
#else
 MessageBox(GetFocus(),(LPSTR)pString,"Command Failure",MBSTOP);
#endif
  }
 if(poll & 1)
  {
  sprintf(buf,"UNL UNT MLA TALK %d",wGPIBAddr);
  gTransmit(buf,0xFFFF,&status);
  gReceive(pString,80,&length,&status);
  }
  else
  pString[0] = 0;
Exit:
 bCmdActive = FALSE;
 return R_OK;
 };
//##############################################################################
//############### ISA Interface ################################################
//##############################################################################
//##############################################################################
TC_812ISA::TC_812ISA(void) : TC_812()
 {
 char    buf[MaxString];
 char    Ident[MaxString];

 sprintf(Ident,"motor%d",nId);
 GetPrivateProfileString(Ident,"RamAddr","0xD000",buf,MaxString,(LPSTR)GetCFile());
 sscanf(buf,"%x",&wBaseAddr);
 if((0xC000 <= wBaseAddr) && (0xD000 > wBaseAddr))
  {
#ifdef __WIN32__
  lpOut1  = (LPSTR)(0x10 * 0xC000 + 0x03fc + 0x10 * (wBaseAddr-0xC000));
  lpOut2  = (LPSTR)(0x10 * 0xC000 + 0x03ff + 0x10 * (wBaseAddr-0xC000));
  lpFlag  = (LPSTR)(0x10 * 0xC000 + 0x0800 + 0x10 * (wBaseAddr-0xC000));
  lpIn   = (LPSTR)(0x10 * 0xC000 + 0x03fe + 0x10 * (wBaseAddr-0xC000));
  lpDPRam = (LPSTR)(0x10 * 0xC000 + 0x10 * (wBaseAddr-0xC000));
#else
  lpOut1  = (LPSTR)MK_FP(FP_OFF(__C000h),0x03fc + 0x10 * (wBaseAddr-0xC000));
  lpOut2  = (LPSTR)MK_FP(FP_OFF(__C000h),0x03ff + 0x10 * (wBaseAddr-0xC000));
  lpFlag  = (LPSTR)MK_FP(FP_OFF(__C000h),0x0800 + 0x10 * (wBaseAddr-0xC000));
  lpIn    = (LPSTR)MK_FP(FP_OFF(__C000h),0x03fe + 0x10 * (wBaseAddr-0xC000));
  lpDPRam = (LPSTR)MK_FP(FP_OFF(__C000h),0x10 * (wBaseAddr-0xC000));
#endif
  }
 if((0xD000 <= wBaseAddr) && (0xE000 > wBaseAddr))
  {
#ifdef __WIN32__
  lpOut1  = (LPSTR)(0x10 * 0xD000 + 0x03fc + 0x10 * (wBaseAddr-0xD000));
  lpOut2  = (LPSTR)(0x10 * 0xD000 + 0x03ff + 0x10 * (wBaseAddr-0xD000));
  lpFlag  = (LPSTR)(0x10 * 0xD000 + 0x0800 + 0x10 * (wBaseAddr-0xD000));
  lpIn   = (LPSTR)(0x10 * 0xD000 + 0x03fe + 0x10 * (wBaseAddr-0xD000));
  lpDPRam = (LPSTR)(0x10 * 0xD000 + 0x10 * (wBaseAddr-0xD000));
#else
  lpOut1  = (LPSTR)MK_FP(FP_OFF(__D000h),0x03fc + 0x10 * (wBaseAddr-0xD000));
  lpOut2  = (LPSTR)MK_FP(FP_OFF(__D000h),0x03ff + 0x10 * (wBaseAddr-0xD000));
  lpFlag  = (LPSTR)MK_FP(FP_OFF(__D000h),0x0800 + 0x10 * (wBaseAddr-0xD000));
  lpIn    = (LPSTR)MK_FP(FP_OFF(__D000h),0x03fe + 0x10 * (wBaseAddr-0xD000));
  lpDPRam = (LPSTR)MK_FP(FP_OFF(__D000h),0x10 * (wBaseAddr-0xD000));
#endif
  }
 nWaitTicks  = 5;
 };

BOOL TC_812ISA::CheckBoardOk(void)
 {
 char    buf[MaxString];
 int   cnt = 60;
 int     retval;

 *lpOut1 = '\r';
 *lpOut1 = '\r';
 do
  {
  DelayTime(4);
  if(*lpIn == '\r')
   break;
  if(*lpIn == '\03')
   break;
  }
 while(--cnt);
 if(!cnt)
  {
  sprintf(buf,"No C-812 Board present at address %X !",wBaseAddr);
  MessageBox(GetFocus(),buf,"Fehler MS",MBSTOP);
#ifndef TESTLAUF
  return FALSE;
#endif
  }
 bControlBoardOk = TRUE;
 /* {
 char   info[20*MaxString];
 int         hFile;
 OFSTRUCT    of;
 strcpy(info,"HE6\r");
 retval = ExecuteCmd(info);
 hFile = OpenFile("info.txt",&of,OF_CREATE);
 _lwrite(hFile,(LPSTR)info,strlen(info));
 _lclose(hFile);
 } */
 strcpy(buf,"DM\r");
 retval = ExecuteCmd(buf);
 strcpy(buf,"EF\r");
 retval = ExecuteCmd(buf);
 if(retval != R_OK)
  {
  MessageBox(GetFocus(),buf,"Fehler MS",MBFAILURE);
#ifndef TESTLAUF
  bControlBoardOk = FALSE;
  return FALSE;
#endif
  }
 return TRUE;
 };

BOOL TC_812ISA::SetHome(void)
 {
 if(!TC_812::SetHome()) return FALSE;
#ifdef DirectAccess
 int  addr = 0x010A + nOnBoardId - 1;
 *(lpDPRam + addr)          = 0x00;
 *(lpDPRam + addr + 0x0004)  = 0x00;
 *(lpDPRam + addr + 0x0008)  = 0x00;
 *(lpDPRam + addr + 0x000C)  = 0x00;
#endif
 return TRUE;
 };

BOOL TC_812ISA::IsMoveFinish(void)
 {
#ifdef DirectAccess
 long fail1,fail2;

 _GetFailure(&fail1);
 if(labs(fail1) > (long)wDeathBand)
  return FALSE;
 DelayTime(100);
 _GetFailure(&fail2);
 if(fail1-fail2)
  return FALSE;
 return TRUE;
#else
 return TC_812::IsMoveFinish();
#endif
 };
 

BOOL TC_812ISA::_GetPosition(long *position)
 {
#ifdef DirectAccess
 tpos    data;
 int     addr = 0x010A + nOnBoardId - 1;

 data.byte[0] = (char)*(lpDPRam + addr);
 data.byte[1] = (char)*(lpDPRam + addr + 0x0004);
 data.byte[2] = (char)*(lpDPRam + addr + 0x0008);
 data.byte[3] = (char)*(lpDPRam + addr + 0x000C);
 *position    = data.pos;
 return TRUE;
#else
 return TC_812::_GetPosition(position);
#endif
 };

BOOL TC_812ISA::_GetFailure(long *failure)
 {
#ifdef DirectAccess
 tpos  data;
 int   addr = 0x006C + nOnBoardId - 1;

 data.byte[0] = (char)*(lpDPRam + addr);
 data.byte[1] = (char)*(lpDPRam + addr + 0x0004);
 data.byte[2] = (char)*(lpDPRam + addr + 0x0008);
 data.byte[3] = (char)*(lpDPRam + addr + 0x000C);
 *failure    = data.pos;
 return TRUE;
#else
 return TC_812::_GetFailure(failure);
#endif
 };

int TC_812ISA::ExecuteCmd(char *pString)
 {
#ifndef TESTLAUF
 int       idx,cnt,retval = R_OK;;
 char      chr;
#endif

 static    BOOL    bCmdActive = FALSE;

 if(!bControlBoardOk)  return 0;
 if(bCmdActive)        return R_Failure;
 bCmdActive = TRUE;
#ifndef TESTLAUF
 cnt = 50;
 while ((chr = GetChar()) != '\x0')
  {
  if(!cnt--)
   {
   // timeout
   strcpy(pString,"TimeOut read");
   bControlBoardOk = FALSE;
   bCmdActive = FALSE;
   retval = R_TimeOut;
   goto Exit;
   }
  }
#endif
 // Befehls-String senden
#ifdef WriteLog
 FILE  *LogFile;
 LogFile = fopen("\motor.log","a");
 if(LogFile) fseek(LogFile,0,2);
#endif
#ifndef TESTLAUF
 idx = 0;
 while(pString[idx] != 0)
  {
  if(!PutChar(pString[idx]))
   {
   Delay(10);
   if(!PutChar(pString[idx]))
    {
    chr = GetChar();
    if(chr) continue;
    // Timeout beim Schreiben
    bCmdActive = FALSE;
    bControlBoardOk = FALSE;
    strcpy(pString,"TimeOut write");
    retval = R_TimeOut;
    goto Exit;
    }
   }
  idx++;
  }
#endif
#ifdef WriteLog
 if(LogFile) fwrite(pString,strlen(pString),1,LogFile);
#endif
 // recieve Request
 Delay(50);
#ifndef TESTLAUF
 idx = 0; cnt = 250;
 while(idx < (20 * MaxString))
  {
  chr = GetChar();
  if(!chr)
   {
   Delay(15);
   if(!cnt)
    { // Timeout beim Lesen
    MessageBox(GetFocus(),"TimeOut read","C-812",MBINFO);
    // strcpy(pString,"TimeOut read");
    bCmdActive = FALSE;
    // bControlBoardOk = FALSE;
    retval = R_TimeOut;
    goto Exit;
    }
   if((cnt--) && (idx == 0)) continue;   // auf den Request warten
   if(pString[idx-1] == '\x3') break; // Ende der *bertragung abwarten
   continue;
   }
  pString[idx++] = chr;
  }
 pString[idx] = '\x0';
 bCmdActive = FALSE;
 if(pString[0] == '?')
  {
  retval = R_Failure;
  goto Exit;
  }
 if(!cnt)
  {
  retval = R_Failure;
  goto Exit;
  }
#endif
Exit:
#ifdef WriteLog
 if(LogFile) fclose(LogFile);
#endif
#ifndef TESTLAUF
 return retval;
#else
 bCmdActive = FALSE;
 pString[0] = '\x0';
 return R_OK;
#endif
 };

int TC_812ISA::PutChar(const char c)
 {
 int time1,time2;

 Delay(3); // 3
 for(time1 = 30000; (*lpFlag & 0x01) && time1; time1--);
 if(time1)   //time
  {
  // check if timeout
  *lpOut1 = c;    // write data
  Delay(3); // 3
  *lpOut2 = c;  // generate internal sidnal
  }
 for(time2 = 30000; (*lpFlag & 0x00) && time2; time2--);
 Delay(3); // 3
 return time1;    // return zero for timeout
 };

char TC_812ISA::GetChar(void)
 {
 char chr = 0;

 Delay(1);  // 1
 // Wenn Bit 1 gesetzt ist, so liegen Daten von der Steuerung an.
 if(!(*lpFlag & 0x02))   // text ready-flag
  return 0;             // no data available
 chr = *lpIn;              // read data
 Delay(2);  // 2
 return chr;
 };
//##############################################################################
//################### Interface ################################################
//##############################################################################
//##############################################################################
BOOL TC_832::bLimitHit = FALSE;
BOOL TC_832::bIdle    = FALSE;
BOOL  TC_832::bIOActive = FALSE;

TC_832::TC_832(void) : TDC_Drive()
 {
 char    Ident[MaxString],buf[MaxString];

 sprintf(Ident,"motor%d",nId);
 GetPrivateProfileString(Ident,"IOAddr","0x210",(LPSTR)buf,MaxString,GetCFile());
 sscanf(buf,"%x",&wBaseAddr);
 nOnBoardId = GetPrivateProfileInt(Ident,"BoardId",0,GetCFile());
 wKI = (WORD)GetPrivateProfileInt(Ident,"IntegralGain",10,GetCFile());
 wKL = (WORD)GetPrivateProfileInt(Ident,"IntegralLimit",10,GetCFile());
 wKP = (WORD)GetPrivateProfileInt(Ident,"Gain",100,GetCFile());
 wKD = (WORD)GetPrivateProfileInt(Ident,"DynamicGain",37,GetCFile());
 cConfig = 0x80;
 if(GetPrivateProfileInt(Ident,"DifferentialEncoder",0,GetCFile()))
  if(0 == nOnBoardId)
   cConfig |= 0x10;
   else
   cConfig |= 0x20;
 if(GetPrivateProfileInt(Ident,"EnableInterrupts",0,GetCFile()))
  cConfig |= 0x40;
 wSample = 0x0100; // 512 ´s
 };

BOOL TC_832::Reset(void)
 {
 // Reset setzt Position auf Null, falls Initialisierung nicht eindeutig genug
 // sollte hier erst Position gelesen werden und dann der Reset ausgef‚hrt
 // werden.
 // changing K-System
 Drive628(RESET,0,0);
 Drive628(RSTI,0,0);
 Drive628(MSKI,0,0);
 return TRUE;
 };

void TC_832::OptimizingDlg(void)
 {
 TModalDlg* dlg;

 dlg = (TOptimizeDC_832 *)new TOptimizeDC_832();
 dlg->ExecuteDialog(GetFrameHandle());
 delete dlg;
 };

BOOL TC_832::  ActivateFilterParameters(void)
 {
 // Static Gain entspricht dem P-Term
 Drive628(LFIL,wSample | LD_KP,wKP);
 // Dynamic Gain entspricht dem D-Term
 Drive628(LFIL,wSample | LD_KD,wKD);
  // Integral Gain entspricht dem I-Term
 Drive628(LFIL,wSample | LD_KI,wKI);
 // Integral-Limit entspricht dem L-Term
 Drive628(LFIL,wSample | LD_IL,wKL);
 Drive628(UDF,0,0);
 SetVelocity(dwMaxVelocity);
 SetAcceleration(dwAcceleration);
 GetSpeed();
 //StartLimitWatch();
 return TRUE;
 };

int TC_832::SaveSettings(int LastSave)
 {
 char        buf[MaxString];
 char      Ident[MaxString];

 sprintf(Ident,"motor%d",nId);
 sprintf(buf,"%u",wKD);
 WritePrivateProfileString(Ident,"DynamicGain",buf,GetCFile());
 sprintf(buf,"%u",wKP);
 WritePrivateProfileString(Ident,"Gain",buf,GetCFile());
 sprintf(buf,"%u",wKI);
 WritePrivateProfileString(Ident,"IntegralGain",buf,GetCFile());
 sprintf(buf,"%u",wKL);
 WritePrivateProfileString(Ident,"IntegralLimit",buf,GetCFile());
 sprintf(buf,"%lu",dwMaxVelocity);
 WritePrivateProfileString(Ident,"MaxVelocity",buf,GetCFile());
 sprintf(buf,"%lu",dwAcceleration);
 WritePrivateProfileString(Ident,"Acceleration",buf,GetCFile());
 sprintf(buf,"%lu",dwVelocity);
 WritePrivateProfileString(Ident,"Velocity",buf,GetCFile());
 return TDC_Drive::SaveSettings(LastSave);
 };

BOOL TC_832::SetHome(void)
 {
 TMotor::SetHome();
 // changing K-System
 Drive628(DFH,0,0);
 Drive628(LTRJ,LD_POS,0);
 Drive628(STT,0,0);
 return TRUE;
 };

BOOL TC_832::ActivateDrive(void)
 {
 long  pos;

 Drive628(UDF,0,0);
 _GetPosition(&pos);
 Drive628(LTRJ,LD_POS,pos);
 Drive628(STT,0,0);
 return TRUE;
 };

BOOL TC_832::StopDrive(int bOffOn)
 {
 WORD  ctr = 0x0400;  // Stop smoothly --> programming manual (page 29)

 Drive628(LTRJ,ctr,0);
 Drive628(STT,0,0);
 while(!IsMoveFinish()) DelayTime(4);
 if(!bOffOn) return TRUE;
 Drive628(UDF,0,0);
 Drive628(STT,0,0);
 return TRUE;
 };

BOOL TC_832::StartLimitWatch(void)
 {
 if(bLimitWatchActive) return FALSE;
 nEvent = timeSetEvent(150,1,(LPTIMECALLBACK)&TC_832::LimitWatch,0,TIME_PERIODIC);
 bLimitWatchActive = TRUE;
 return TRUE;
 };

BOOL TC_832::StopLimitWatch(void)
 {
 if(!bLimitWatchActive) return FALSE;
 timeKillEvent(nEvent);
 bLimitWatchActive = FALSE;
 return TRUE;
 };

void CALLBACK TC_832::LimitWatch(UINT /*IDEvent*/,UINT,DWORD /*dwUser*/,DWORD,DWORD)
 // UINT IDEvent;   identifies timer event
 // UINT uReserved;  not used
 // DWORD dwUser;   application-defined instance data */
 // DWORD dwReserved1; not used
 // DWORD dwReserved2; not used
 {
 BYTE  status = 0;
 static  count = 0;
 static  MessageIsPosted = 0;

 LM628Ready(::baddr);
#ifndef __WIN32__
 outp(::baddr,::config | 0x07);
 status = inp(::baddr+1);
#endif
 bLimitHit = 0;
 count++;
 PostMessage(GetFrameHandle(),WM_COMMAND,cm_SetWatchIndicator,(LPARAM)count);
 if(status & 0x01)
  {
  ::raddr  = (::config | 0x00);
  Drive628c(LTRJ,0x400,0,::baddr,::raddr);
  Drive628c(STT,0,0,::baddr,::raddr);
  bLimitHit = 1;
  }
 if(status & 0x02)
  {
  ::raddr  = (::config | 0x02);
  Drive628c(LTRJ,0x400,0,::baddr,::raddr);
  Drive628c(STT,0,0,::baddr,::raddr);
  bLimitHit = 2;
  }
 if(bLimitHit && !MessageIsPosted)
  PostMessage(GetFrameHandle(),WM_COMMAND,cm_LimitHitOccure,(LPARAM)bLimitHit);
 };

BOOL TC_832::IsLimitHit(void)
 {
 BYTE   status;

 // Interrupt-Register
 LM628Ready(wBaseAddr);
#ifndef __WIN32__
 outp(wBaseAddr,cConfig | 0x07);
 status = inp(wBaseAddr+1);
#else
   status = 1;
#endif
 if(status & (nOnBoardId+1))
  {
  Drive628(LTRJ,0x400,0);   // stop appruptly
  Drive628(STT,0,0);
  if(bUpwards)
   Drive628(LTRJ,LD_RPOS,-labs(dwRemoveLimit));
   else
   Drive628(LTRJ,LD_RPOS,labs(dwRemoveLimit));
  bUpwards = !bUpwards;
  Drive628(STT,0,0);
  while(!IsMoveFinish())
   DelayTime(10);
  DelayTime(100);
  LM628Ready(wBaseAddr);
#ifndef __WIN32__
  outp(wBaseAddr,cConfig | 0x07);
  status = inp(wBaseAddr+1);
  outp(wBaseAddr+1,status & ~(nOnBoardId+1));
#endif
  DelayTime(10);
  bLimitHit = bRangeHit = TRUE;
  return TRUE;
  }
 bLimitHit = FALSE;
 return FALSE;
 };

BOOL TC_832::IsIndexArrived(void)
 {
 long    ipos,pos;

 if(IsLimitHit())
  {
  Drive628(RSTI,0,0);
  Drive628(MSKI,0,0);
  Drive628(STT,0,0);
  if(bIndexLine)
   {
   Drive628(SIP,0,0);
   Drive628(LTRJ,LD_RPOS,400000000l);
   bUpwards = TRUE;
   Drive628(STT,0,0);
   return FALSE;
   }
  return TRUE;
  }
 if(bIndexLine && bIndexDetected && IsMoveFinish())
  return TRUE;
 if(!bIndexLine && bRangeHit && IsMoveFinish())
  return TRUE;
 if(!bRangeHit && bMoveFirstToLimit)
  return FALSE;
 if(0x08 & Drive628(RDSIGS,0,0))
  {
  // stop drive
  Drive628(LTRJ,0x400,0);
  Drive628(STT,0,0);
  bIndexDetected = TRUE;
  Drive628(RSTI,0,0);
  Drive628(MSKI,0,0);
  ipos = Drive628(RDIP,0,0);
  while(!IsMoveFinish());
  pos = Drive628(RDRP,0,0);
  bUpwards = (ipos > pos);
  Drive628(LTRJ,LD_POS,ipos);
  Drive628(STT,0,0);
  Delay(150);
  return FALSE;
  }
 return FALSE;
 };

BOOL TC_832::StartToIndex(long &oldPos)
 {
 SetSpeed(10000.0);
 bIndexDetected = FALSE;
 bRangeHit = FALSE;
 bLimitHit = FALSE;
 lDeltaPosition = 0;
 SetCalibrationState(FALSE);
 SetCorrectionState(FALSE);
 lPosition = oldPos = Drive628(RDRP,0,0);
 bUpwards = FALSE;
 if(!bMoveFirstToLimit && bIndexLine)
  {
  Drive628(RSTI,0,0);
  Drive628(SIP,0,0);
  }
 Drive628(LTRJ,LD_RPOS,-400000000l);
 Drive628(STT,0,0);
 // Die Motoren werden in Bewegung gesetzt
 // Erreichen der Stillstands-Position
 DelayTime(150);
 return TRUE;
 };

BOOL TC_832::SetVelocity(DWORD velocity)
 {
 dwVelocity = (velocity<dwMaxVelocity)?velocity:dwMaxVelocity;
 if(R_OK != Drive628(LTRJ,0x0008,dwVelocity))
  return FALSE;
 return TRUE;
 };

DWORD TC_832::GetVelocity(void)
 {
 dwVelocity = (dwVelocity<dwMaxVelocity)?dwVelocity:dwMaxVelocity;
 return dwVelocity;
 };

BOOL TC_832::SetAcceleration(DWORD acceleration)
 {
 dwAcceleration = acceleration;
 if(R_OK != Drive628(LTRJ,0x0020,dwAcceleration))
  return FALSE;
 return TRUE;
 };

DWORD TC_832::GetAcceleration(void)
 {
 return dwAcceleration;
 };

BOOL TC_832::SetLimit(DWORD limit)
 {
 dwRemoveLimit = limit;
 return TRUE;
 };

WORD TC_832::GetStatus(void)
 {
 return (WORD)Drive628(RDSTAT,0,0);
 };

BOOL TC_832::_GetPosition(long *position)
 {
 *position = Drive628(RDRP,0,0);
 return TRUE;
 };

BOOL TC_832::_GetFailure(long *failure)
 {
 *failure = (Drive628(RDRP,0,0) - Drive628(RDDP,0,0));
 return TRUE;
 };

BOOL TC_832::MoveRelative(long position)
 {
 long rpos;
 rpos = Drive628(RDRP,0,0);
 rpos += position;
 Drive628(LTRJ,LD_POS,rpos);
 Drive628(STT,0,0);
 return TRUE;
 };

BOOL TC_832::MoveAbsolute(long pos)
 {
 Drive628(LTRJ,LD_POS,pos);
 Drive628(STT,0,0);
 return TRUE;
 };

BOOL TC_832::IsMoveFinish(void)
 {
 DelayTime(5);
 if(Drive628(RDSIGS,0,0) & ON_TARGET)
  return TRUE;
  else
  return FALSE;
 };

BOOL TC_832::CheckBoardOk()
 {
 bControlBoardOk = FALSE;
#ifndef TESTLAUF
#ifndef __WIN32__
 outp(wBaseAddr,cConfig | (nOnBoardId << 1));
 if(inp(wBaseAddr+1) == 0xFF)
  return FALSE;
#endif
#endif
 bControlBoardOk = TRUE;
 return TRUE;
 };

BOOL TC_832::ExecuteCmd(LPSTR)
 {
 return R_OK;
 };

long TC_832::Drive628(BYTE cmd,WORD ctrl_word,long param)
 {
 // load static variables
 ::config = cConfig;
 ::drive  = nOnBoardId;
 ::baddr  = wBaseAddr;
 ::raddr  = (::config | (::drive<<1));
#ifdef WriteLog
 FILE  *LogFile;
 char buf[30];

 LogFile = fopen("\motor.log","a");
 if(LogFile)
  {
  fseek(LogFile,0,2);
  sprintf(buf,"%d\n",cmd);
  fwrite(buf,strlen(buf),1,LogFile);
  fclose(LogFile);
  }
#endif
 return Drive628c(cmd,ctrl_word,param,::baddr,::raddr);
 };

//******************************************************************************
//******************************************************************************
long Drive628c(BYTE cmd,WORD ctrl_word,long param,WORD base,WORD regaddr)
 {
 TCSet    *pCmdDesc;

 if(TC_832::bIdle)
  {
  TC_832::bIdle = FALSE;
  };
 TC_832::bIdle = TRUE;
#ifndef __WIN32__
 // seeking command description
 pCmdDesc   = CmdSet;
 if(cmd==RDSTAT)
  {
  // Status
  outp(base,regaddr);
  TC_832::bIdle = FALSE;
  return((long)inp(base + 1));
  }
  else
  while(cmd != pCmdDesc->cmd)
   pCmdDesc++;

 LM628Ready(base);
 outp(base + 1,cmd);
 if(pCmdDesc->data)
  {
  // read/write data
  if((cmd==LTRJ) | (cmd==LFIL))
   PutWord(ctrl_word,base,regaddr);
  if(pCmdDesc->report)
   {
   // report command
   if(pCmdDesc->length32)
    {
    TC_832::bIdle = FALSE;
    return  GetDWord(base,regaddr); // 32 Bit data
    }
    else
    {
    TC_832::bIdle = FALSE;
    return  (long)GetWord(base,regaddr);  // 16 Bit data
    }
   }
   else
   {
   // control command
   if(pCmdDesc->length32)
    PutDWord(param,base,regaddr);  // 32 Bit parameter
    else
    PutWord((int)param,base,regaddr); // 16 Bit parameter
   }
  }
#endif
 TC_832::bIdle = FALSE;
 return 0;
 };

int GetWord(WORD base,WORD regaddr)
 {
 union {
    int  integer;
    BYTE byte[2];
    } temp;

 LM628Ready(base);
#ifndef __WIN32__
 outp(base,regaddr + 1);
 temp.byte[1] = inp(base + 1);
 temp.byte[0] = inp(base + 1);
#endif
 return temp.integer;
 };

long GetDWord(WORD base,WORD regaddr)
 {
 union {
    long  lval;
    BYTE  byte[4];
    } temp;

 LM628Ready(base);
#ifndef __WIN32__
 outp(base,regaddr + 1);
 temp.byte[3] = inp(base + 1);
 temp.byte[2] = inp(base + 1);
 LM628Ready(base);
 outp(base,regaddr+1);
 temp.byte[1] = inp(base + 1);
 temp.byte[0] = inp(base + 1);
#endif
 return temp.lval;
 };

void PutWord(int data,WORD base,WORD regaddr)
 {
 union {
    int  integer;
    BYTE byte[2];
    } temp;

 LM628Ready(base);
#ifndef __WIN32__
 outp(base,regaddr + 1);
 Delay(2);
 temp.integer = data;
 outp(base + 1,temp.byte[1]);
 outp(base + 1,temp.byte[0]);
#else
 data = 1;
#endif
 };

void PutDWord(long data,WORD base,WORD regaddr)
 {
 union {
    long  lval;
    BYTE byte[4];
    } temp;

 temp.lval = data;
 LM628Ready(base);
#ifndef __WIN32__
 outp(base,regaddr+1);
 outp(base + 1,temp.byte[3]);
 outp(base + 1,temp.byte[2]);
 LM628Ready(base);
 outp(base,regaddr+1);
 outp(base + 1,temp.byte[1]);
 outp(base + 1,temp.byte[0]);
#else
 data = 1;
#endif
 };

BOOL LM628Ready(WORD base)
 {
 int   tt;
 int   time_out=1000;

 // command register
#ifndef __WIN32__
 outp(base,::config | (::drive<<1));
 do {
  tt = inp(base+1);
  if(!(time_out--)) return FALSE;
  }
  // test BUSY bit 0
  while(tt & 0x01);
 if(tt & 0x02)
  {
  time_out++;
  }
#endif
 return TRUE;
 };
// __LastLine__