/*
	The MagTape

	11-feb-2025	Created by mk@lemo.dk
*/

/*
#undef DEBUG
*/

#define TIMER_INTERVAL 20

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glext.h>

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <malloc.h>
#include <time.h>
#include <sys/fcntl.h>

#include "MagTape_w32.h"
#include "MagTapeP_w32.h"
#include "spole7.h"
#include "GIER.h"
#include "common.h"

int UAKK1=8;
double ADJLIMIT=0.2;
extern XsMagTapeWidget MagTape;
extern void PrintMessage(UINT);
#define UAKK2 22
extern unsigned long long clock_count;
extern int gier_clock;
extern int tape_wait;
extern HWND magtapehwnd;

#define dtor(x) ( (x)/180.0*M_PI )
#define rtod(x) ( (x)*180.0/M_PI )

extern void bbox(double ,double *,double *,double *,double *,char *);
extern void stroke(double ,double ,double ,double ,char *);

/*
Forward declarations */
static void XsmagTapeInsertValues();
void XsmagTapeInsertDefaultValues();
static void updateit(XsMagTapeWidget, int);
GLvoid DrawGLScene(XsMagTapeWidget,int);
static void startTimer(XsMagTapeWidget);

int TimerRunning=0;

static char *tape_color_types[]={"TAPE_COLOR_BLACK",
                                 "TAPE_COLOR_WHITE",
                                 "TAPE_COLOR_RED",
                                 "TAPE_COLOR_GREEN",
                                 "TAPE_COLOR_BLUE",
                                 "TAPE_COLOR_BLACK_T",
                                 "TAPE_COLOR_GRAY8_T",
                                 "TAPE_COLOR_TAPE"};

static double glcolors[][4] =
{
  {0.00, 0.00, 0.00, 1.00},
  {1.00, 1.00, 1.00, 1.00},
  {1.00, 0.00, 0.00, 1.00},
  {0.00, 1.00, 0.00, 1.00},
  {0.00, 0.00, 1.00, 1.00},
  {0.00, 0.00, 0.00, 0.00}, 
  {0.80, 0.80, 0.80, 0.00},
  {0.59, 0.39, 0.00, 1.00}};

static HDC hDC;
static void done_magTape(XsMagTapeWidget,int);

static void Realize(), Destroy(), Redisplay();

static double seconds(XsMagTapeWidget w)
{
  double td;
  long tn;
  w->magTape.time1 = clock_count;
  td = ((double) (w->magTape.time1-w->magTape.time0))/((double)gier_clock);
  return(td);
}

static int QUAREQ2(double A, double B, double C, double *x1, double *x2)
{
  double D;
  int ret=0;
  if(A==0.0)
  {
    if(B==0.0)
      ret=1;
    else
    {
      *x1 = -C/A;
      *x2 = *x1;
    }
  }
  else
  {
    D=SQR(B)-4.0*A*C;
    if(D<0.0)
      ret=1;
    else
    {
      *x1 = (-B - ((B<0.0)?-1.0:1.0)*sqrt(D))/2.0/A;
      *x2 = C/A/(*x1);
    }
  }
  return(ret);
}

static double radius2Length(XsMagTapeWidget w,double r)
{
  return((M_PI/w->magTape.thickness)*SQR(r)+M_PI*r-SQR(w->magTape.radius0)*M_PI/w->magTape.thickness);
}

static double length2Thickness(XsMagTapeWidget w,double l, double r)
{
  return(M_PI*(SQR(r)-SQR(w->magTape.radius0))/(l-M_PI*r));
}

static double length2Radius(XsMagTapeWidget w,double l)
{
  double A,B,C,x1,x2;
  A=M_PI/w->magTape.thickness;
  B=M_PI;
  C=-(SQR(w->magTape.radius0)*M_PI/w->magTape.thickness)-l;
  QUAREQ2(A, B, C, &x1, &x2);
  return(x2);
}

static double rotation2Length(XsMagTapeWidget w,double r)
{
  return(M_PI*w->magTape.thickness*SQR(r)+(2.0*M_PI*w->magTape.radius0)*r);
}

static double length2Rotation(XsMagTapeWidget w,double l)
{
  double A,B,C,x1,x2;
  A=M_PI*w->magTape.thickness;
  B=2.0*M_PI*w->magTape.radius0;
  C=-l;
  QUAREQ2(A, B, C, &x1, &x2);
  return(x2);
}


static void disk(GLdouble x0, GLdouble y0, GLdouble z0,GLdouble r1, GLdouble r2)
{
  GLdouble x1,y1,x2,y2,v,lastx1,lasty1,lastx2,lasty2;

  lastx1=x0+r1;
  lasty1=y0;
  lastx2=x0+r2;
  lasty2=y0;
  for(v=5;v<=360;v+=5)
  {
    x1=x0+r1*cos(v/180.0*M_PI);
    y1=y0+r1*sin(v/180.0*M_PI);
    x2=x0+r2*cos(v/180.0*M_PI);
    y2=y0+r2*sin(v/180.0*M_PI);
    glVertex3d(lastx1,lasty1,z0);
    glVertex3d(lastx2,lasty2,z0);
    glVertex3d(x1,y1,z0);
    glVertex3d(lastx2,lasty2,z0);
    glVertex3d(x2,y2,z0);
    glVertex3d(x1,y1,z0);
    lastx1=x1;
    lasty1=y1;
    lastx2=x2;
    lasty2=y2;
  }
}

static void circle(GLdouble x0, GLdouble y0, GLdouble r, GLdouble v0, GLdouble v1)
{
  GLdouble lastx,lasty,x,y,v;
  int i,n;

  n=r*2;
  lastx=x0+r*cos(v0/180.0*M_PI);
  lasty=y0-r*sin(v0/180.0*M_PI);
  for(i=1;i<=n;i++)
  {
    v=v0+(v1-v0)*((double)i)/((double) n);
    x=x0+r*cos(v/180.0*M_PI);
    y=y0-r*sin(v/180.0*M_PI);
    glVertex3d(lastx,lasty,0.0);
    glVertex3d(x,y,0.0);
    lastx=x;
    lasty=y;
  }
}


    
static void intersectionLineCircle(double a1, double c1,
                                   double x1, double y1, double r1,
				   double *xi1, double *yi1,
				   double *xi2, double *yi2)
{
  double A,B,C,d,tmp;
  A=(1.0+SQR(a1));
  B=(-2.0*x1+2.0*a1*(y1+c1));
  C=SQR(x1)+SQR(y1+c1)-SQR(r1);
  d=SQR(B)-4.0*A*C;
  if(d<0)
  {
    fprintf(stderr, "no intersection\n");
    exit(-1);
  }
  *xi1 = (-B+sqrt(d))/2.0/A;
  *xi2 = (-B-sqrt(d))/2.0/A;
  if((*xi1) > (*xi2))
  {
    tmp=*xi1;
    *xi1=*xi2;
    *xi2=tmp;
  }
  *yi1 = -c1-a1*(*xi1);
  *yi2 = -c1-a1*(*xi2);
}

static void intersectionLines(double a1, double c1,
                              double a2, double c2,
			      double *x, double *y)
{
  *x = (c1-c2)/(a2-a1);
  *y = -c1-a1*(*x);
}

static void intersectionCircles(double x1, double y1, double r1,
                                double x2, double y2, double r2,
				double *xi1, double *yi1,
				double *xi2, double *yi2)
{
  double R,tmp;
  /* https://math.stackexchange.com/questions/256100/how-can-i-find-the-points-at-which-two-circles-intersect */
  R=sqrt(SQR(x1-x2)+SQR(y1-y2));
  *xi1 = (x1+x2)/2.0 + (SQR(r1)-SQR(r2))/2.0/SQR(R)*(x2-x1)
        +0.5*sqrt(2.0*(SQR(r1)+SQR(r2))/SQR(R)-SQR(SQR(r1)-SQR(r2))/SQR(SQR(R))-1.0)*(y2-y1);
  *xi2 = (x1+x2)/2.0 + (SQR(r1)-SQR(r2))/2.0/SQR(R)*(x2-x1)
        -0.5*sqrt(2.0*(SQR(r1)+SQR(r2))/SQR(R)-SQR(SQR(r1)-SQR(r2))/SQR(SQR(R))-1.0)*(y2-y1);
  *yi1 = (y1+y2)/2.0 + (SQR(r1)-SQR(r2))/2.0/SQR(R)*(y2-y1)
        +0.5*sqrt(2.0*(SQR(r1)+SQR(r2))/SQR(R)-SQR(SQR(r1)-SQR(r2))/SQR(SQR(R))-1.0)*(x1-x2);
  *yi2 = (y1+y2)/2.0 + (SQR(r1)-SQR(r2))/2.0/SQR(R)*(y2-y1)
        -0.5*sqrt(2.0*(SQR(r1)+SQR(r2))/SQR(R)-SQR(SQR(r1)-SQR(r2))/SQR(SQR(R))-1.0)*(x1-x2);
  if((*xi1)>(*xi2))
  {
    tmp=(*xi1); *xi1 = (*xi2); *xi2=tmp;
    tmp=(*yi1); *yi1 = (*yi2); *yi2=tmp;
  }
}

static void points2Line(double x1, double y1,
                        double x2, double y2,
			double *a, double *c)
{
  *a = (y1-y2)/(x2-x1);
  *c = -(*a)*x1-y1;
}

static void twoCirclesTangent(double x1, double y1, double r1,
                              double x2, double y2, double r2,
			      int transverse,
			      double *xi11, double *yi11,
			      double *xi12, double *yi12,
			      double *xi21, double *yi21,
			      double *xi22, double *yi22)
{
  /* https://math.stackexchange.com/questions/1662110/common-tangent-to-two-circles */
  double a,c,xr,yr,ca,cc,cx1,cy1,cx2,cy2,ca2,cc2,x3,y3,r3,angle;
  points2Line(x1,y1,x2,y2,&ca,&cc);
  angle=atan2(y2-y1,x2-x1)+M_PI_2;
  cx1=x1+r1*cos(angle);
  cy1=y1+r1*sin(angle);
  cx2=x2+r2*cos(angle+(transverse?M_PI:0));
  cy2=y2+r2*sin(angle+(transverse?M_PI:0));
  points2Line(cx1,cy1,cx2,cy2,&ca2,&cc2);
  intersectionLines(ca,cc,ca2,cc2,&xr,&yr);
  x3=(x2+xr)/2.0;
  y3=(y2+yr)/2.0;
  r3=sqrt(SQR(xr-x2)+SQR(yr-y2))/2.0;
  intersectionCircles(x2,y2,r2,x3,y3,r3,xi21,yi21,xi22,yi22);
  x3=(x1+xr)/2.0;
  y3=(y1+yr)/2.0;
  r3=sqrt(SQR(xr-x1)+SQR(yr-y1))/2.0;
  intersectionCircles(x1,y1,r1,x3,y3,r3,xi11,yi11,xi12,yi12);
}

GLfloat LightAmbient[]  = {0.5, 0.5, 0.5, 1.0}; 
GLfloat LightDiffuse[]  = {1.0, 1.0, 1.0, 1.0}; 
GLfloat LightPosition[] = {0.0, 0.0, 2.0, 1.0};

static void tapeuakk(XsMagTapeWidget w,int unitNo,int serial)
{
  return;
  if(unitNo==0)
  {
    double t=seconds(w);
    printf("%10.3f color_status serial: %d unit: %d %s\n",t,serial,unitNo,tape_color_types[w->magTape.color_status[unitNo]]);
  }
}

static int setTimerRunning(XsMagTapeWidget w,int serial,int clearcolor)
{
  int unitNo,stopped=0;
  w->magTape.timerRunning=0;
  for(unitNo=0; unitNo<w->magTape.ndrives; unitNo++)
  {
    if(debug&DEBUGbuffer) fprintf(debug_fh, "setTimerRunning: unit %d status: %d in: %g cap: %g out: %g\n",unitNo,w->magTape.status[unitNo],w->magTape.inSpeed[unitNo],w->magTape.capstanSpeed[unitNo],w->magTape.outSpeed[unitNo]);
    if(w->magTape.status[unitNo] != TAPE_IDLE) w->magTape.timerRunning=1;
    if(fabs(w->magTape.inSpeed[unitNo])>IDLE_SPEED) w->magTape.timerRunning=1;
    if(fabs(w->magTape.capstanSpeed[unitNo])>IDLE_SPEED) w->magTape.timerRunning=1;
    if(fabs(w->magTape.outSpeed[unitNo])>IDLE_SPEED) w->magTape.timerRunning=1;
  }
  stopped=!(w->magTape.timerRunning);

  if(stopped)
  {
    for(unitNo=0; unitNo<w->magTape.ndrives; unitNo++)
    {
      w->magTape.inSpeed[unitNo]=0.0;
      w->magTape.capstanSpeed[unitNo]=0.0;
      w->magTape.lastCapstan[unitNo]=0.0;
      w->magTape.outSpeed[unitNo]=0.0;
      if(clearcolor) w->magTape.color_status[unitNo] = TAPE_IDLE_COLOR;
      tapeuakk(w,unitNo,1);
    }
  }
  tape_wait=w->magTape.timerRunning;
  if(debug&DEBUGbuffer) fprintf(debug_fh, "setTimerRunning: %d\n",w->magTape.timerRunning);
  return stopped;
}

/* The main drawing function. */

XsMagTapeWidget savew;

void CALLBACK timercb(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
  double total,inSpeed,outSpeed;
  int i,n;
  int unitNo,stopped;
  XsMagTapeWidget w = (XsMagTapeWidget) savew;
  if(debug&DEBUGbuffer) fprintf(debug_fh, "timercb called\n");
  w->magTape.secs=seconds(w);
  w->magTape.dsecs2=w->magTape.secs-w->magTape.lastsecs;
  if(debug&DEBUGbuffer) fprintf(debug_fh, "timercb dsecs2: %g\n",w->magTape.dsecs2);
  if(w->magTape.dsecs2==0)
  {
    stopped=setTimerRunning(w,1,1);
    if(debug&DEBUGbuffer) fprintf(debug_fh, "start timer: %d stopped: %d\n",w->magTape.timerRunning,stopped);
    if(w->magTape.timerRunning)startTimer(w);
    if(debug&DEBUGbuffer) fprintf(debug_fh, "timercb done\n");
    return;
  }
  if(w->magTape.dsecs2>0)
  {
  w->magTape.lastsecs=w->magTape.secs;
  w->magTape.dsecs=w->magTape.dsecs2;
  if(w->magTape.dsecs2>TIME_STEP)
  {
    n=w->magTape.dsecs2/TIME_STEP;
    w->magTape.dsecs=TIME_STEP;
  }
  else
  {
    n=1;
  }
  for(unitNo=0; unitNo<w->magTape.ndrives; unitNo++)
  {
    w->magTape.inLast[unitNo] = w->magTape.INlength[unitNo];
    w->magTape.outLast[unitNo] = w->magTape.OUTlength[unitNo];
  }
  for(i=0;i<n;i++)
  {
    if(i==(n-1))
      w->magTape.dsecs=w->magTape.dsecs2-(n-1)*TIME_STEP;
    if(debug&DEBUGbuffer) fprintf(debug_fh, "kilroy2 dsecs2: %g i: %d n: %d dsecs: %g\n", w->magTape.dsecs2,i,n,w->magTape.dsecs);
    for(unitNo=0; unitNo<w->magTape.ndrives; unitNo++)
    {
      updateit(w,unitNo);
    }
  }
  for(unitNo=0; unitNo<w->magTape.ndrives; unitNo++)
  {
    inSpeed = -(w->magTape.INlength[unitNo] - w->magTape.inLast[unitNo])/w->magTape.dsecs2;
    outSpeed = -(w->magTape.OUTlength[unitNo] - w->magTape.outLast[unitNo])/w->magTape.dsecs2;
    if(inSpeed*w->magTape.lastCapstan[unitNo]<(-IDLE_SPEED) ||
       outSpeed*w->magTape.lastCapstan[unitNo]>IDLE_SPEED)
    {
      if(debug&DEBUGbuffer) fprintf(debug_fh, "%d: %11.3f: Gulerod %10.3f %10.3f %10.3f\n",
	unitNo,
	w->magTape.secs,
	inSpeed,
	w->magTape.lastCapstan[unitNo],
	outSpeed);
    }
  }
  }
  if(debug&DEBUGbuffer) {fprintf(debug_fh, "call InvalidateRect\n"); fflush(debug_fh); }
  InvalidateRect(magtapehwnd, NULL, 0);
  for(unitNo=0; unitNo<w->magTape.ndrives; unitNo++)
  {
    if(fabs(w->magTape.capstanSpeed[unitNo])<0.01)
    {
      w->magTape.color_status[unitNo] = TAPE_IDLE_COLOR;
      tapeuakk(w,unitNo,2);
      if(debug&DEBUGbuffer) fprintf(debug_fh, "%d: color_status I: %s\n", unitNo, tape_color_types[w->magTape.color_status[unitNo]]);
    }
  }
  stopped=setTimerRunning(w,2,1);
  if(debug&DEBUGbuffer) fprintf(debug_fh, "start timer: %d stopped: %d\n",w->magTape.timerRunning,stopped);
  if(w->magTape.timerRunning)startTimer(w);
  if(debug&DEBUGbuffer) fprintf(debug_fh, "timercb done\n");
}

static void startTimer(XsMagTapeWidget w)
{
  if(debug&DEBUGbuffer) fprintf(debug_fh, "kilroy1:\n");
  if(debug&DEBUGbuffer) fflush(debug_fh);
  savew = w;
  if(SetTimer(magtapehwnd, 1, TIMER_INTERVAL, NULL)==0)
  {
    DWORD dw=GetLastError();
    fprintf(stderr, "SetTimer failed: %ld\n",dw);
    if(debug&DEBUGbuffer) {fprintf(debug_fh, "SetTimer failed: %ld\n",dw); fflush(debug_fh);}
  }
  TimerRunning=1;
}

static char *status_text(int s)
{
  if(s==TAPE_IDLE) return "TAPE_IDLE";
  if(s==FORWARD_ACCELERATE) return "FORWARD_ACCELERATE";
  if(s==FORWARD_KEEP) return "FORWARD_KEEP";
  if(s==FORWARD_DECELERATE) return "FORWARD_DECELERATE";
  if(s==REVERSE_ACCELERATE) return "REVERSE_ACCELERATE";
  if(s==REVERSE_KEEP) return "REVERSE_KEEP";
  if(s==REVERSE_DECELERATE) return "REVERSE_DECELERATE";
  if(s==REWIND_ACCELERATE) return "REWIND_ACCELERATE";
  if(s==REWIND_KEEP) return "REWIND_KEEP";
  if(s==REWIND_DECELERATE) return "REWIND_DECELERATE";
  return "Unknown status";
}

static void updateit(XsMagTapeWidget w, int unitNo)
{
  double total;
  switch(w->magTape.status[unitNo])
  {
    case TAPE_IDLE:
      break;

    case FORWARD_ACCELERATE:
      if(w->magTape.capstanSpeed[unitNo]>READSPEED)
      {
	w->magTape.capstanAcceleration[unitNo]=0.0;
	w->magTape.capstanSpeed[unitNo]=READSPEED;
	w->magTape.status[unitNo]=FORWARD_KEEP;
      }
      break;
    case FORWARD_KEEP:
      if((w->magTape.taperead[unitNo]-w->magTape.readstart[unitNo]+GAPLEN)>=w->magTape.tapeappetite[unitNo])
      {
	w->magTape.capstanAcceleration[unitNo]=-CAPSTANACCELERATION;
	w->magTape.status[unitNo]=FORWARD_DECELERATE;
      }
      break;
    case FORWARD_DECELERATE:
      if(w->magTape.capstanSpeed[unitNo]<0.01)
      {
	w->magTape.capstanSpeed[unitNo]=0;
	w->magTape.capstanAcceleration[unitNo]=0;
	w->magTape.tapeadjust[unitNo]=w->magTape.readstart[unitNo]+w->magTape.tapeappetite[unitNo]-w->magTape.taperead[unitNo];
//	  if(debug&DEBUGbuffer) fprintf(debug_fh, "%d: tapeadjust: %.8f\n",unitNo, w->magTape.tapeadjust[unitNo]);
	w->magTape.taperead[unitNo]+=w->magTape.tapeadjust[unitNo];
	w->magTape.inTape[unitNo]-=w->magTape.tapeadjust[unitNo];
	w->magTape.outTape[unitNo]+=w->magTape.tapeadjust[unitNo];
	w->magTape.status[unitNo]=TAPE_IDLE;
	done_magTape(w,unitNo);
//	  goto out;
      }
      break;

    case REVERSE_ACCELERATE:
      if(w->magTape.capstanSpeed[unitNo]<(-READSPEED))
      {
	w->magTape.capstanAcceleration[unitNo]=0.0;
	w->magTape.capstanSpeed[unitNo]=-READSPEED;
	w->magTape.status[unitNo]=REVERSE_KEEP;
      }
      break;
    case REVERSE_KEEP:
      if((w->magTape.readstart[unitNo]-w->magTape.taperead[unitNo]+GAPLEN)>=w->magTape.tapeappetite[unitNo])
      {
	w->magTape.capstanAcceleration[unitNo]=CAPSTANACCELERATION;
	w->magTape.status[unitNo]=REVERSE_DECELERATE;
      }
      break;
    case REVERSE_DECELERATE:
      if(w->magTape.capstanSpeed[unitNo]>-0.01)
      {
	w->magTape.capstanSpeed[unitNo]=0;
	w->magTape.capstanAcceleration[unitNo]=0;
	w->magTape.tapeadjust[unitNo]=w->magTape.taperead[unitNo]-w->magTape.readstart[unitNo]+w->magTape.tapeappetite[unitNo];
//	  if(debug&DEBUGbuffer) fprintf(debug_fh, "%d: tapeadjust: %.8f\n",unitNo, w->magTape.tapeadjust[unitNo]);
	w->magTape.taperead[unitNo]-=w->magTape.tapeadjust[unitNo];
	w->magTape.inTape[unitNo]+=w->magTape.tapeadjust[unitNo];
	w->magTape.outTape[unitNo]-=w->magTape.tapeadjust[unitNo];
	w->magTape.status[unitNo]=TAPE_IDLE;
	w->magTape.tapeadjust[unitNo]=w->magTape.taperead[unitNo]-w->magTape.readstart[unitNo]-w->magTape.tapeappetite[unitNo];
	done_magTape(w,unitNo);
//	  goto out;
      }
      break;

    case REWIND_ACCELERATE:
      if(w->magTape.capstanSpeed[unitNo]<(-REWINDSPEED))
      {
	w->magTape.capstanAcceleration[unitNo]=0.0;
	w->magTape.capstanSpeed[unitNo]=-REWINDSPEED;
	w->magTape.status[unitNo]=REWIND_KEEP;
      }
      break;
    case REWIND_KEEP:
      if(w->magTape.OUTlength[unitNo]<GAPLEN)
      {
	w->magTape.capstanAcceleration[unitNo]=CAPSTANACCELERATION;
	w->magTape.status[unitNo]=REWIND_DECELERATE;
      }
      break;
    case REWIND_DECELERATE:
      if(w->magTape.capstanSpeed[unitNo]>-0.01)
      {
	w->magTape.capstanSpeed[unitNo]=0;
	w->magTape.capstanAcceleration[unitNo]=0;
	w->magTape.OUTlength[unitNo]=0.0;
	w->magTape.INlength[unitNo]=TAPELENGTH;
	w->magTape.taperead[unitNo]=0;
	w->magTape.status[unitNo]=TAPE_IDLE;
        w->magTape.color_status[unitNo] = TAPE_IDLE_COLOR;
      tapeuakk(w,unitNo,3);
	done_magTape(w,unitNo);
//	  goto out;
      }
      break;
  }
  w->magTape.INlength[unitNo] -= w->magTape.inSpeed[unitNo]*w->magTape.dsecs;
  w->magTape.OUTlength[unitNo] -= w->magTape.outSpeed[unitNo]*w->magTape.dsecs;
  w->magTape.inTape[unitNo] += w->magTape.inSpeed[unitNo]*w->magTape.dsecs;
  w->magTape.outTape[unitNo] += w->magTape.outSpeed[unitNo]*w->magTape.dsecs;
  w->magTape.inTape[unitNo] -= w->magTape.capstanSpeed[unitNo]*w->magTape.dsecs;
  w->magTape.outTape[unitNo] += w->magTape.capstanSpeed[unitNo]*w->magTape.dsecs;
  w->magTape.taperead[unitNo] += w->magTape.capstanSpeed[unitNo]*w->magTape.dsecs;
  w->magTape.inSpeed[unitNo] += w->magTape.inAcceleration[unitNo]*w->magTape.dsecs;
  w->magTape.outSpeed[unitNo] += w->magTape.outAcceleration[unitNo]*w->magTape.dsecs;
  w->magTape.capstanSpeed[unitNo] += w->magTape.capstanAcceleration[unitNo]*w->magTape.dsecs;
  
  w->magTape.inRatio[unitNo] = w->magTape.inTape[unitNo]/MAXCHAMPERTAPELENGTH - 0.5;
  w->magTape.outRatio[unitNo] = w->magTape.outTape[unitNo]/MAXCHAMPERTAPELENGTH - 0.5;

  w->magTape.inError[unitNo]=w->magTape.inSpeed[unitNo]-w->magTape.capstanSpeed[unitNo];
  w->magTape.outError[unitNo]=w->magTape.outSpeed[unitNo]+w->magTape.capstanSpeed[unitNo];
  w->magTape.inAcceleration[unitNo]= -w->magTape.inError[unitNo]*w->magTape.UAKK[unitNo];
  if(fabs(w->magTape.inRatio[unitNo])>ADJLIMIT)
  {
//    double inadjust=ADJLIMIT*SIGN(w->magTape.inRatio[unitNo])*w->magTape.UAKK[unitNo];
    double inadjust=w->magTape.inRatio[unitNo]*w->magTape.UAKK[unitNo];
    if(debug&DEBUGbuffer) fprintf(debug_fh, "%d: inadjust: %.8f %g\n",unitNo, inadjust,w->magTape.UAKK[unitNo]);
    w->magTape.inAcceleration[unitNo]-=inadjust;
  }
  w->magTape.outAcceleration[unitNo]= -w->magTape.outError[unitNo]*w->magTape.UAKK[unitNo];
  if(fabs(w->magTape.outRatio[unitNo])>ADJLIMIT)
  {
//    double outadjust=ADJLIMIT*SIGN(w->magTape.outRatio[unitNo])*w->magTape.UAKK[unitNo];
    double outadjust=w->magTape.outRatio[unitNo]*w->magTape.UAKK[unitNo];
    if(debug&DEBUGbuffer) fprintf(debug_fh, "%d: outadjust: %.8f %g\n",unitNo, outadjust,w->magTape.UAKK[unitNo]);
    w->magTape.outAcceleration[unitNo]-=outadjust;
  }
  total=w->magTape.INlength[unitNo]+w->magTape.OUTlength[unitNo]+w->magTape.inTape[unitNo]+w->magTape.outTape[unitNo];

  if(debug&DEBUGbuffer) fprintf(debug_fh, "%d: inSpeed: %g capstanSpeed: %g outSpeed: %g\n",unitNo,w->magTape.inSpeed[unitNo],w->magTape.capstanSpeed[unitNo],w->magTape.outSpeed[unitNo]);
  if(w->magTape.inRatio[unitNo] < -0.5 || w->magTape.inRatio[unitNo] > 0.5 || w->magTape.outRatio[unitNo] < -0.5 || w->magTape.outRatio[unitNo] > 0.5)
  {
    if(debug&DEBUGbuffer) fprintf(debug_fh, "%d: inRatio: %g outRatio: %g\n",unitNo,w->magTape.inRatio[unitNo],w->magTape.outRatio[unitNo]);
  }
}

static void Layout(XsMagTapeWidget w)
{
  if(debug&DEBUGbuffer) {fprintf(debug_fh, "Layout: ndrives: %d\n",w->magTape.ndrives); fflush(debug_fh); }
  switch(w->magTape.ndrives)
  {
    case 1:
    case 2:
    case 3:
      w->magTape.nx=w->magTape.ndrives;
      w->magTape.ny=1;
      break;
    case 4:
      w->magTape.nx=2;
      w->magTape.ny=2;
      break;
    case 5:
    case 6:
      w->magTape.nx=3;
      w->magTape.ny=2;
      break;
  }
}

static void pushmatrix(int lno)
{
  int mm;
  if(debug&DEBUGbuffer)
  {
    glGetIntegerv(GL_MATRIX_MODE, &mm);
    if(mm==GL_MODELVIEW) fprintf(debug_fh, "pushmatrix %d GL_MODELVIEW\n",lno);
    else if(mm==GL_PROJECTION) fprintf(debug_fh, "pushmatrix %d GL_PROJECTION\n",lno);
    else if(mm==GL_TEXTURE) fprintf(debug_fh, "pushmatrix %d GL_TEXTURE\n",lno);
    else if(mm==GL_COLOR) fprintf(debug_fh, "pushmatrix %d GL_COLOR\n",lno);
    else fprintf(debug_fh, "pushmatrix %d UNKNOWN %d\n",lno,mm);
  }
}

static void popmatrix(int lno)
{
  int mm;
  if(debug&DEBUGbuffer)
  {
    glGetIntegerv(GL_MATRIX_MODE, &mm);
    if(mm==GL_MODELVIEW) fprintf(debug_fh, "popmatrix %d GL_MODELVIEW\n",lno);
    else if(mm==GL_PROJECTION) fprintf(debug_fh, "popmatrix %d GL_PROJECTION\n",lno);
    else if(mm==GL_TEXTURE) fprintf(debug_fh, "popmatrix %d GL_TEXTURE\n",lno);
    else if(mm==GL_COLOR) fprintf(debug_fh, "popmatrix %d GL_COLOR\n",lno);
    else fprintf(debug_fh, "popmatrix %d UNKNOWN %d\n",lno,mm);
  }
}

GLvoid DrawGLScene(XsMagTapeWidget w,int unitNo)
{
  char txt[100];
  double x,y;
  int width, height;
  int widthr, heightr;
  int ix, iy;
  GLdouble window_xmin, window_xmax, window_ymin, window_ymax;
  GLdouble xcenter, ycenter, aspect, xsize, ysize, fHeight, fWidth;
  double a1,c1,xi1,yi1,xi2,yi2,angle1,angle2;
  double xi11,yi11,xi12,yi12,xi21,yi21,xi22,yi22;
  double xcenter1,ycenter1,xcenter2,ycenter2,acenter,ccenter;
  double r1,angle3,x1,y1,x2,y2,x3,y3,s,sx,sy;
  double tapewidth=1.0,angle;
  double textXmin, textXmax, textYmin, textYmax;
GLfloat trans[3];			/* current translation */
GLfloat rot[2];				/* current rotation */

    if(0)
    {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glPushMatrix();
    rot[0] = 0.0;
    rot[1] = 0.0;
    trans[0] = 0.0;
    trans[1] = 0.0;
    trans[2] = 0.0;
    glTranslatef(trans[0], trans[1], trans[2]);
    glRotatef(rot[0], 1.0f, 0.0f, 0.0f);
    glRotatef(rot[1], 0.0f, 1.0f, 0.0f);
    glBegin(GL_TRIANGLES);

#define TOP glIndexi(1); glColor3f(1.0f, 0.0f, 0.0f); glVertex3i(0, 1, 0)
#define FR  glIndexi(2); glColor3f(0.0f, 1.0f, 0.0f); glVertex3i(1, -1, 1)
#define FL  glIndexi(3); glColor3f(0.0f, 0.0f, 1.0f); glVertex3i(-1, -1, 1)
#define BR  glIndexi(3); glColor3f(0.0f, 0.0f, 1.0f); glVertex3i(1, -1, -1)
#define BL  glIndexi(2); glColor3f(0.0f, 1.0f, 0.0f); glVertex3i(-1, -1, -1)

    TOP; FL; FR;
    TOP; FR; BR;
    TOP; BR; BL;
    TOP; BL; FL;
    FR; FL; BL;
    BL; BR; FR;
    
    glEnd();
    glPopMatrix();
    glFlush();
    SwapBuffers(hDC);			/* nop if singlebuffered */
    return;
    }

  if(debug&DEBUGbuffer){ fprintf(debug_fh, "bamse 1\n"); fflush(debug_fh); }
    if(unitNo==0)
    {
      glClearColor(1.0, 1.0, 1.0, 1.0);	// Clear The Background Color To White 
      glClearDepth(0.9);				// Enables Clearing Of The Depth Buffer
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    }
  glDepthFunc(GL_LESS);			// The Type Of Depth Test To Do
  glEnable(GL_DEPTH_TEST);			// Enables Depth Testing
  glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);

  if(debug&DEBUGbuffer){ fprintf(debug_fh, "bamse 2\n"); fflush(debug_fh); }
  glShadeModel(GL_SMOOTH);			// Enables Smooth Color Shading
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glDisable(GL_BLEND);
  glEnable(GL_LINE_SMOOTH);
    
  if(debug&DEBUGbuffer){ fprintf(debug_fh, "bamse 3\n"); fflush(debug_fh); }
  glMatrixMode(GL_MODELVIEW);

  glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);
  glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);
  glLightfv(GL_LIGHT1, GL_POSITION, LightPosition);
  glEnable(GL_LIGHT1);
  glMatrixMode(GL_PROJECTION);
//pushmatrix(__LINE__);
//glPushMatrix();
  if(debug&DEBUGbuffer){ fprintf(debug_fh, "bamse 4\n"); fflush(debug_fh); }
  glLoadIdentity();
  if(debug&DEBUGbuffer){ fprintf(debug_fh, "bamse 5\n"); fflush(debug_fh); }
  if(debug&DEBUGbuffer) {fprintf(debug_fh, "DrawGLScene: %d: width: %d height: %d nx: %d ny: %d\n", unitNo, w->magTape.width, w->magTape.height, w->magTape.nx, w->magTape.ny); fflush(debug_fh); }

  ix=unitNo%w->magTape.nx;
  iy=unitNo/w->magTape.nx;
  iy=w->magTape.ny-1-iy;
  widthr = w->magTape.width/w->magTape.nx;
  heightr = w->magTape.height/w->magTape.ny;
 
  if(debug&DEBUGbuffer){ fprintf(debug_fh, "bamse 6\n"); fflush(debug_fh); }
  glViewport(ix*widthr, iy*heightr, widthr, heightr);
  if(debug&DEBUGbuffer){ fprintf(debug_fh, "bamse 7\n"); fflush(debug_fh); }
  w->magTape.window_aspect = ((GLdouble) widthr)/((GLdouble) heightr)*((GLdouble) YMAX)/((GLdouble) XMAX);
  if(debug&DEBUGbuffer) fprintf(debug_fh, "%d: glViewport(%d, %d, %d, %d)\n",unitNo,ix*widthr, iy*heightr, widthr, heightr);
//if(debug&DEBUGbuffer) fprintf(debug_fh, "%d: window_aspect 1: %g\n",unitNo, w->magTape.window_aspect);
//if(debug&DEBUGbuffer) fprintf(debug_fh, "gulerod 1\n");
  if(debug&DEBUGbuffer){ fprintf(debug_fh, "glOrtho(0.0, %g, %g, 0.0, -1.0, 1.0)\n",((double)XMAX)*w->magTape.window_aspect,((double)YMAX)); fflush(debug_fh); }
  glOrtho(0.0,((double)XMAX)*w->magTape.window_aspect,((double)YMAX),0.0,-1.0,1.0);
//if(debug&DEBUGbuffer) fprintf(debug_fh, "gulerod 2\n");
  glMatrixMode(GL_MODELVIEW);
//if(debug&DEBUGbuffer) fprintf(debug_fh, "gulerod 3\n");
//pushmatrix(__LINE__);
//glPushMatrix();
//if(debug&DEBUGbuffer) fprintf(debug_fh, "gulerod 4\n");
  if(debug&DEBUGbuffer){ fprintf(debug_fh, "bamse 8\n"); fflush(debug_fh); }
  glLoadIdentity();
  if(debug&DEBUGbuffer){ fprintf(debug_fh, "bamse 9\n"); fflush(debug_fh); }
//if(debug&DEBUGbuffer) fprintf(debug_fh, "gulerod 5\n");

  glDisable(GL_BLEND);
//if(debug&DEBUGbuffer) fprintf(debug_fh, "gulerod 6\n");
  glDisable(GL_TEXTURE_2D);
//if(debug&DEBUGbuffer) fprintf(debug_fh, "gulerod 7\n");
  glLoadIdentity();				// Reset The View
//if(debug&DEBUGbuffer) fprintf(debug_fh, "gulerod 8\n");
  glBegin(GL_LINES);
//if(debug&DEBUGbuffer) fprintf(debug_fh, "gulerod 9\n");
  glColor4dv(glcolors[TAPE_COLOR_BLACK]);
//if(debug&DEBUGbuffer) fprintf(debug_fh, "gulerod 10\n");
//glLineWidth(1.0);
//if(debug&DEBUGbuffer) fprintf(debug_fh, "gulerod 11\n");
  if(debug&DEBUGbuffer){ fprintf(debug_fh, "bamse 10\n"); fflush(debug_fh); }
  /*
  glVertex3d(BottomReelX-BottomReelOuterR,BottomReelY-BottomReelOuterR,0.0);
  glVertex3d(BottomReelX-BottomReelOuterR,BottomReelY+BottomReelOuterR,0.0);

  glVertex3d(BottomReelX-BottomReelOuterR,BottomReelY+BottomReelOuterR,0.0);
  glVertex3d(BottomReelX+BottomReelOuterR,BottomReelY+BottomReelOuterR,0.0);

  glVertex3d(BottomReelX+BottomReelOuterR,BottomReelY+BottomReelOuterR,0.0);
  glVertex3d(BottomReelX+BottomReelOuterR,BottomReelY-BottomReelOuterR,0.0);

  glVertex3d(BottomReelX+BottomReelOuterR,BottomReelY-BottomReelOuterR,0.0);
  glVertex3d(BottomReelX-BottomReelOuterR,BottomReelY-BottomReelOuterR,0.0);
  */

  glVertex3d(1.0, 0.0, 0.0);
  glVertex3d(XMAX, 0.0, 0.0);

  glVertex3d(XMAX, 0.0, 0.0);
  glVertex3d(XMAX, YMAX, 0.0);

  glVertex3d(XMAX, YMAX, 0.0);
  glVertex3d(1.0, YMAX, 0.0);

  glVertex3d(1.0, YMAX, 0.0);
  glVertex3d(1.0, 0.0, 0.0);

  if(debug&DEBUGbuffer){ fprintf(debug_fh, "bamse 10.1\n"); fflush(debug_fh); }
//if(debug&DEBUGbuffer) fprintf(debug_fh, "gulerod 12\n");

  circle(TopReelX, TopReelY, TopReelOuterR, 0.0, 360.0);
  circle(TopReelX, TopReelY, TopReelInnerR, 0.0, 360.0);

//if(debug&DEBUGbuffer) fprintf(debug_fh, "gulerod 13\n");
#ifdef USECORNER
  circle(TopCornerX, TopCornerY, TopCornerOuterR, 0.0, 360.0);
  circle(TopCornerX, TopCornerY, TopCornerInnerR, 0.0, 360.0);
#endif

  circle(TopChamperInX, TopChamperInY, TopChamperInInnerR, 0.0, 360.0);

  if(debug&DEBUGbuffer){ fprintf(debug_fh, "bamse 10.2\n"); fflush(debug_fh); }
  points2Line(TopChamperOuter1X, TopChamperOuter1Y, TopChamperOuter2X, TopChamperOuter2Y,
              &a1, &c1);
  intersectionLineCircle(a1,c1,TopChamperInX,TopChamperInY,TopChamperInInnerR,
              &xi1,&yi1,&xi2,&yi2);

  glVertex3d(xi2,yi2,0.0);
  glVertex3d(TopChamperOuter2X,TopChamperOuter2Y,0.0);

  intersectionLineCircle(a1,c1,TopChamperInX,TopChamperInY,TopChamperInOuterR,
              &xi1,&yi1,&xi2,&yi2);

  angle1=-atan2(yi2-TopChamperInY,xi2-TopChamperInX)*180.0/M_PI;
  points2Line(TopChamperOuter4X, TopChamperOuter4Y, TopChamperOuter1X, TopChamperOuter1Y,
              &a1,&c1);
  intersectionLineCircle(a1,c1,TopChamperInX,TopChamperInY,TopChamperInOuterR,
              &xi1,&yi1,&xi2,&yi2);
  angle2=360.0-atan2(yi2-TopChamperInY,xi2-TopChamperInX)*180.0/M_PI;

//printf("Top: angle1: %lg angle2: %lg\n",angle1,angle2);

  if(debug&DEBUGbuffer){ fprintf(debug_fh, "bamse 10.3\n"); fflush(debug_fh); }
  circle(TopChamperInX, TopChamperInY, TopChamperInOuterR, angle1, angle2);

  glVertex3d(TopChamperOuter2X,TopChamperOuter2Y,0.0);
  glVertex3d(TopChamperOuter3X,TopChamperOuter3Y,0.0);

  glVertex3d(TopChamperOuter3X,TopChamperOuter3Y,0.0);
  glVertex3d(TopChamperOuter4X,TopChamperOuter4Y,0.0);

  glVertex3d(TopChamperOuter4X,TopChamperOuter4Y,0.0);
  glVertex3d(TopChamperOuter1X,TopChamperOuter1Y,0.0);

  glVertex3d(TopChamperOuter1X+9.0,TopChamperOuter1Y+7.0,0.0);
  glVertex3d(735.0,37.0,0.0);

  glVertex3d(TopChamperInner2X, TopChamperInner2Y, 0.0);
  glVertex3d(TopChamperInner3X, TopChamperInner3Y, 0.0);

  points2Line(799.0,88.0,TopChamperInner4X,TopChamperInner4Y,&a1,&c1);
  intersectionLineCircle(a1,c1,TopChamperOutX,TopChamperOutY,TopChamperOutR,
                         &xi1,&yi1,&xi2,&yi2);
  glVertex3d(799.0,88.0,0.0);
  glVertex3d(xi2,yi2,0.0);
  circle(TopChamperOutX,TopChamperOutY,TopChamperOutR,0.0,360.0);

  if(debug&DEBUGbuffer) {fprintf(debug_fh, "%d: color_status draw: %s\n", unitNo, tape_color_types[w->magTape.color_status[unitNo]]); fflush(debug_fh); }
  tapeuakk(w,unitNo,4);
  if(w->magTape.color_status[unitNo] != TAPE_IDLE_COLOR)
  {
    glEnd();
    glBegin(GL_TRIANGLES);
    glColor4dv(glcolors[w->magTape.color_status[unitNo]]);
    glVertex3d(Head1X,Head1Y,0.0);
    glVertex3d(Head2X,Head2Y,0.0);
    glVertex3d(Head3X,Head3Y,0.0);
    
    glVertex3d(Head6X,Head6Y,0.0);
    glVertex3d(Head1X,Head1Y,0.0);
    glVertex3d(Head3X,Head3Y,0.0);
    
    glVertex3d(Head3X,Head3Y,0.0);
    glVertex3d(Head5X,Head5Y,0.0);
    glVertex3d(Head6X,Head6Y,0.0);
    
    glVertex3d(Head3X,Head3Y,0.0);
    glVertex3d(Head4X,Head4Y,0.0);
    glVertex3d(Head5X,Head5Y,0.0);
    
    glEnd();
    glBegin(GL_LINES);

  }
  if(debug&DEBUGbuffer){ fprintf(debug_fh, "bamse 10.4\n"); fflush(debug_fh); }
  glColor4dv(glcolors[TAPE_COLOR_BLACK]);
  glVertex3d(Head1X,Head1Y,0.0);
  glVertex3d(Head2X,Head2Y,0.0);

  glVertex3d(Head2X,Head2Y,0.0);
  glVertex3d(Head3X,Head3Y,0.0);

  glVertex3d(Head3X,Head3Y,0.0);
  glVertex3d(Head4X,Head4Y,0.0);

  glVertex3d(Head4X,Head4Y,0.0);
  glVertex3d(Head5X,Head5Y,0.0);

  glVertex3d(Head5X,Head5Y,0.0);
  glVertex3d(Head6X,Head6Y,0.0);

  glVertex3d(Head6X,Head6Y,0.0);
  glVertex3d(Head1X,Head1Y,0.0);

  circle(CapstanX,CapstanY,CapstanR,0.0,360.0);
  if(debug&DEBUGbuffer){ fprintf(debug_fh, "bamse 11\n"); fflush(debug_fh); }

#ifdef CROSS
  angle = fmod(w->magTape.taperead[unitNo]/(2.0*M_PI*CapstanR/PIXELSPERM)*360.0,360.0);

  glVertex3d(CapstanX+CapstanR*cos((angle      )/180.0*M_PI),CapstanY+CapstanR*sin((angle      )/180.0*M_PI),0.0);
  glVertex3d(CapstanX+CapstanR*cos((angle+180.0)/180.0*M_PI),CapstanY+CapstanR*sin((angle+180.0)/180.0*M_PI),0.0);

  glVertex3d(CapstanX+CapstanR*cos((angle+90.0 )/180.0*M_PI),CapstanY+CapstanR*sin((angle+90.0 )/180.0*M_PI),0.0);
  glVertex3d(CapstanX+CapstanR*cos((angle+270.0)/180.0*M_PI),CapstanY+CapstanR*sin((angle+270.0)/180.0*M_PI),0.0);
#endif

#ifdef USECORNER
  circle(BottomCornerX, BottomCornerY, BottomCornerOuterR, 0.0, 360.0);
  circle(BottomCornerX, BottomCornerY, BottomCornerInnerR, 0.0, 360.0);
#endif

  circle(BottomChamperInX, BottomChamperInY, BottomChamperInInnerR, 0.0, 360.0);

  points2Line(BottomChamperOuter1X, BottomChamperOuter1Y, BottomChamperOuter2X, BottomChamperOuter2Y,
              &a1, &c1);
  intersectionLineCircle(a1,c1,BottomChamperInX,BottomChamperInY,BottomChamperInInnerR,
              &xi1,&yi1,&xi2,&yi2);

  glVertex3d(xi2,yi2,0.0);
  glVertex3d(BottomChamperOuter2X,BottomChamperOuter2Y,0.0);

  intersectionLineCircle(a1,c1,BottomChamperInX,BottomChamperInY,BottomChamperInOuterR,
              &xi1,&yi1,&xi2,&yi2);

  angle1=-atan2(yi2-BottomChamperInY,xi2-BottomChamperInX)*180.0/M_PI;
  points2Line(BottomChamperOuter4X, BottomChamperOuter4Y, BottomChamperOuter1X, BottomChamperOuter1Y,
              &a1,&c1);
  intersectionLineCircle(a1,c1,BottomChamperInX,BottomChamperInY,BottomChamperInOuterR,
              &xi1,&yi1,&xi2,&yi2);
  angle2=360+atan2(yi2-BottomChamperInY,xi2-BottomChamperInX)*180.0/M_PI;

//printf("Bottom: angle1: %lg angle2: %lg\n",angle1,angle2);
  circle(BottomChamperInX, BottomChamperInY, BottomChamperInOuterR, -angle2, angle1);

  glVertex3d(BottomChamperOuter2X,BottomChamperOuter2Y,0.0);
  glVertex3d(BottomChamperOuter3X,BottomChamperOuter3Y,0.0);

  glVertex3d(BottomChamperOuter3X,BottomChamperOuter3Y,0.0);
  glVertex3d(BottomChamperOuter4X,BottomChamperOuter4Y,0.0);

  glVertex3d(BottomChamperOuter4X,BottomChamperOuter4Y,0.0);
  glVertex3d(BottomChamperOuter1X,BottomChamperOuter1Y,0.0);

  glVertex3d(BottomChamperOuter1X+9.0,BottomChamperOuter1Y-7.0,0.0);
  glVertex3d(735.0,MirrorY-37.0,0.0);

  glVertex3d(BottomChamperInner2X, BottomChamperInner2Y, 0.0);
  glVertex3d(BottomChamperInner3X, BottomChamperInner3Y, 0.0);

  points2Line(799.0,MirrorY-88.0,BottomChamperInner4X,BottomChamperInner4Y,&a1,&c1);
  intersectionLineCircle(a1,c1,BottomChamperOutX,BottomChamperOutY,BottomChamperOutR,
                         &xi1,&yi1,&xi2,&yi2);
  glVertex3d(799.0,MirrorY-88.0,0.0);
  glVertex3d(xi2,yi2,0.0);
  circle(BottomChamperOutX,BottomChamperOutY,BottomChamperOutR,0.0,360.0);

  // Tape:

  if(debug&DEBUGbuffer) fprintf(debug_fh, "gulerod 14\n");
  glEnd();
  if(debug&DEBUGbuffer) fprintf(debug_fh, "gulerod 15\n");
  glColor4dv(glcolors[TAPE_COLOR_TAPE]);
  glBegin(GL_TRIANGLES);
  w->magTape.inRadius[unitNo]=length2Radius(w,w->magTape.INlength[unitNo])*PIXELSPERM;
  w->magTape.inRotation[unitNo]=-fmod(length2Rotation(w,w->magTape.INlength[unitNo])*360.0,360.0);
  w->magTape.outRadius[unitNo]=length2Radius(w,w->magTape.OUTlength[unitNo])*PIXELSPERM;
//printf("inRadius: %g outRadius: %g\n",inRadius,outRadius);
  w->magTape.outRotation[unitNo]=fmod(length2Rotation(w,w->magTape.OUTlength[unitNo])*360.0,360.0);
  disk(TopReelX,TopReelY,0.0,TopReelInnerR,w->magTape.inRadius[unitNo]);
  disk(BottomReelX,BottomReelY, 0.5,BottomReelInnerR,w->magTape.outRadius[unitNo]);
  glEnd();
  glBegin(GL_LINES);

#ifdef USECORNER
  twoCirclesTangent(TopReelX,TopReelY,w->magTape.inRadius[unitNo],
                    TopCornerX,TopCornerY,TopCornerInnerR,0,
		    &xi11,&yi11,&xi12,&yi12,&xi21,&yi21,&xi22,&yi22);
  glVertex3d(xi11,yi11,0.0);
  glVertex3d(xi21,yi21,0.0);

  twoCirclesTangent(TopCornerX,TopCornerY,TopCornerInnerR,
                    TopChamperInX,TopChamperInY,TopChamperInInnerR,1,
		    &xi11,&yi11,&xi12,&yi12,&xi21,&yi21,&xi22,&yi22);
  glVertex3d(xi12,yi12,0.0);
  glVertex3d(xi21,yi21,0.0);
#else
  twoCirclesTangent(TopReelX,TopReelY,w->magTape.inRadius[unitNo],
                    TopChamperInX,TopChamperInY,TopChamperInInnerR,1,
		    &xi11,&yi11,&xi12,&yi12,&xi21,&yi21,&xi22,&yi22);
  glVertex3d(xi12,yi12,0.0);
  glVertex3d(xi21,yi21,0.0);
#endif

  xcenter1=(TopChamperInner1X+TopChamperInner4X)/2.0;
  ycenter1=(TopChamperInner1Y+TopChamperInner4Y)/2.0;
  xcenter2=(TopChamperInner2X+TopChamperInner3X)/2.0;
  ycenter2=(TopChamperInner2Y+TopChamperInner3Y)/2.0;
  points2Line(xcenter1,ycenter1,xcenter2,ycenter2,&acenter,&ccenter);
  x=xcenter1+(xcenter2-xcenter1)*(w->magTape.inRatio[unitNo]+0.5);
  y=-ccenter-acenter*x;
  r1=fabs(acenter*TopChamperInner1X+TopChamperInner1Y+ccenter)/sqrt(SQR(acenter)+1.0)-tapewidth*0.5;
  angle3=atan(acenter)*180.0/M_PI;
//printf("angle3: %g\n",angle3);
//glVertex3d(xcenter1,-ccenter-acenter*xcenter1,0.0);
//glVertex3d(xcenter2,-ccenter-acenter*xcenter2,0.0);
  circle(x,y,r1,angle3-90.0,angle3+90.0);

  x2=r1*cos((angle3+90.0)/180.0*M_PI)+x;
  y2=r1*sin((angle3-90.0)/180.0*M_PI)+y;

  x3=xcenter1+5.0;
  y3=-ccenter-acenter*x3;
  x1=r1*cos((angle3+90.0)/180.0*M_PI)+x3;
  y1=r1*sin((angle3-90.0)/180.0*M_PI)+y3;
  glVertex3d(x1,y1,0.0);
  glVertex3d(x2,y2,0.0);

  x2=r1*cos((angle3-90.0)/180.0*M_PI)+x;
  y2=r1*sin((angle3-270.0)/180.0*M_PI)+y;
  
  x3=xcenter1+15.0;
  y3=-ccenter-acenter*x3;
  x1=r1*cos((angle3-90.0)/180.0*M_PI)+x3;
  y1=r1*sin((angle3-270.0)/180.0*M_PI)+y3;
  glVertex3d(x1,y1,0.0);
  glVertex3d(x2,y2,0.0);

  twoCirclesTangent(TopChamperOutX,TopChamperOutY,TopChamperOutR,
                    Head3X,Head3Y,tapewidth*0.5,1,
		    &xi11,&yi11,&xi12,&yi12,&xi21,&yi21,&xi22,&yi22);
  glVertex3d(xi12,yi12,0.0);
  glVertex3d(xi21,yi21,0.0);
  x=xi21+Head4X-Head3X;
  y=yi21;
  glVertex3d(xi21,yi21,0.0);
  glVertex3d(x,y,0.0);
  
  twoCirclesTangent(Head4X,Head4Y,tapewidth*0.5,
                    CapstanX,CapstanY,CapstanR,0,
		    &xi11,&yi11,&xi12,&yi12,&xi21,&yi21,&xi22,&yi22);
  glVertex3d(x,y,0.0);
  glVertex3d(xi22,yi22,0.0);

  twoCirclesTangent(CapstanX,CapstanY,CapstanR,
                    BottomChamperOutX,BottomChamperOutY,BottomChamperOutR,1,
		    &xi11,&yi11,&xi12,&yi12,&xi21,&yi21,&xi22,&yi22);
  glVertex3d(xi12,yi12,0.0);
  glVertex3d(xi21,yi21,0.0);

  xcenter1=(BottomChamperInner1X+BottomChamperInner4X)/2.0;
  ycenter1=(BottomChamperInner1Y+BottomChamperInner4Y)/2.0;
  xcenter2=(BottomChamperInner2X+BottomChamperInner3X)/2.0;
  ycenter2=(BottomChamperInner2Y+BottomChamperInner3Y)/2.0;
  points2Line(xcenter1,ycenter1,xcenter2,ycenter2,&acenter,&ccenter);
  x=xcenter1+(xcenter2-xcenter1)*(w->magTape.outRatio[unitNo]+0.5);
  y=-ccenter-acenter*x;
  r1=fabs(acenter*BottomChamperInner1X+BottomChamperInner1Y+ccenter)/
     sqrt(SQR(acenter)+1.0)-tapewidth*0.5;
  angle3=atan(acenter)*180.0/M_PI;
  circle(x,y,r1,angle3-90.0,angle3+90.0);

  x2=r1*cos((angle3+90.0)/180.0*M_PI)+x;
  y2=r1*sin((angle3-90.0)/180.0*M_PI)+y;
  x3=xcenter1+15;
  y3=-ccenter-acenter*x3;
  x1=r1*cos((angle3+90.0)/180.0*M_PI)+x3;
  y1=r1*sin((angle3-90.0)/180.0*M_PI)+y3;
  glVertex3d(x1,y1,0.0);
  glVertex3d(x2,y2,0.0);

  x2=r1*cos((angle3-90.0)/180.0*M_PI)+x;
  y2=r1*sin((angle3-270.0)/180.0*M_PI)+y;
  x3=xcenter1+5.0;
  y3=-ccenter-acenter*x3;
  x1=r1*cos((angle3-90.0)/180.0*M_PI)+x3;
  y1=r1*sin((angle3-270.0)/180.0*M_PI)+y3;
  glVertex3d(x1,y1,0.0);
  glVertex3d(x2,y2,0.0);

#ifdef USECORNER
  twoCirclesTangent(BottomReelX,BottomReelY,outRadius,
                    BottomCornerX,BottomCornerY,BottomCornerInnerR,0,
		    &xi11,&yi11,&xi12,&yi12,&xi21,&yi21,&xi22,&yi22);
  glVertex3d(xi11,yi11,0.0);
  glVertex3d(xi21,yi21,0.0);

  twoCirclesTangent(BottomCornerX,BottomCornerY,BottomCornerInnerR,
                    BottomChamperInX,BottomChamperInY,BottomChamperInInnerR,1,
		    &xi11,&yi11,&xi12,&yi12,&xi21,&yi21,&xi22,&yi22);
  glVertex3d(xi12,yi12,0.0);
  glVertex3d(xi21,yi21,0.0);
#else
  twoCirclesTangent(BottomReelX,BottomReelY,w->magTape.outRadius[unitNo],
                    BottomChamperInX,BottomChamperInY,BottomChamperInInnerR,1,
		    &xi11,&yi11,&xi12,&yi12,&xi21,&yi21,&xi22,&yi22);
  glVertex3d(xi12,yi12,0.0);
  glVertex3d(xi21,yi21,0.0);
#endif


  glEnd();
  if(debug&DEBUGbuffer){ fprintf(debug_fh, "bamse 12\n"); fflush(debug_fh); }

// Label on top reel:
//#define TopReelLabelWidth 100.0
//#define TopReelLabelHeight 50.0
//#define TopReelLabelDistance 100.0

// kilroy
  pushmatrix(__LINE__);
  glPushMatrix();
  if(debug&DEBUGbuffer){ fprintf(debug_fh, "bamse 13\n"); fflush(debug_fh); }
  glTranslated(TopReelX,TopReelY,0.0);
  glRotated(w->magTape.inRotation[unitNo],0.0,0.0,1.0);
  glPolygonMode(GL_FRONT, GL_FILL);
  glPolygonMode(GL_BACK, GL_FILL);
  glBegin(GL_QUADS);
    glColor4dv(glcolors[TAPE_COLOR_GRAY8_T]);
    glVertex3d(-TopReelLabelWidth/2.0, TopReelLabelDistance+TopReelLabelHeight/2.0, 0.5);
    glVertex3d( TopReelLabelWidth/2.0, TopReelLabelDistance+TopReelLabelHeight/2.0, 0.5);
    glVertex3d( TopReelLabelWidth/2.0, TopReelLabelDistance-TopReelLabelHeight/2.0, 0.5);
    glVertex3d(-TopReelLabelWidth/2.0, TopReelLabelDistance-TopReelLabelHeight/2.0, 0.5);
  glEnd();
  glColor4dv(glcolors[TAPE_COLOR_BLACK_T]);
//glTranslated(-TopReelLabelWidth/2.0, TopReelLabelDistance+TopReelLabelHeight/2.0, 1.0);
  glTranslated(0.0, TopReelLabelDistance, 1.0);
  if(debug&DEBUGbuffer){ fprintf(debug_fh, "bamse 13.1: %s\n",w->magTape.tapeLabels[unitNo]); fflush(debug_fh); }
  bbox(1.0, &textXmin, &textXmax, &textYmin, &textYmax, w->magTape.tapeLabels[unitNo]);
  if(debug&DEBUGbuffer) fprintf(debug_fh, "%d: textXmin: %g textXmax: %g textYmin: %g textYmax: %g\n", unitNo, textXmin, textXmax, textYmin, textYmax);
  sx=TopReelLabelWidth/(textXmax-textXmin);
  sy=TopReelLabelHeight/(textYmax-textYmin);
  s=sx;
  if(s>sy) s=sy;
  if(debug&DEBUGbuffer){ fprintf(debug_fh, "bamse 13.2\n"); fflush(debug_fh); }
  if(debug&DEBUGbuffer) fprintf(debug_fh, "%d: sx: %g sy: %g s: %g\n",unitNo, sx,sy,s);
  glScaled(s,-s,1.0);
  glTranslated(-(textXmin+textXmax)*0.5, -(textYmin+textYmax)*0.5, 0.0);
  glBegin(GL_LINES);
  stroke(1.0, 0.0, 0.0, 0.0, w->magTape.tapeLabels[unitNo]);
  glEnd();

  if(debug&DEBUGbuffer){ fprintf(debug_fh, "bamse 14\n"); fflush(debug_fh); }
  popmatrix(__LINE__);
  glPopMatrix();
  if(debug&DEBUGbuffer){ fprintf(debug_fh, "bamse 15\n"); fflush(debug_fh); }
  
  glEnable(GL_BLEND);
  pushmatrix(__LINE__);
  glPushMatrix();
  glTranslated(BottomReelX-BottomReelOuterR,BottomReelY-BottomReelOuterR,0.0);
  glScaled(BottomReelOuterR*2.0,BottomReelOuterR*2.0,1.0);
  glTranslated(0.5,0.5,0.0);
  glRotated(w->magTape.outRotation[unitNo],0.0,0.0,1.0);
  glTranslated(-0.5,-0.5,0.0);
  
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // scale linearly when image bigger than texture
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // scale linearly when image smalled than texture

    // 2d texture, level of detail 0 (normal), 3 components (red, green, blue), x size from image, y size from image, 
    // border 0 (normal), rgb color data, unsigned byte data, and finally the data itself.

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, spole7_width, spole7_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (unsigned char *) spole7_image);
  if(debug&DEBUGbuffer){ fprintf(debug_fh, "glTexImage2D: %d\n",glGetError()); fflush(debug_fh); }
  glEnable(GL_TEXTURE_2D);			// Enable Texture Mapping
  glBindTexture(GL_TEXTURE_2D, w->magTape.texture[0]);   // choose the texture to use.


  glBegin(GL_QUADS);
    glColor4dv(glcolors[TAPE_COLOR_WHITE]);
    glTexCoord2d(0.0, 0.0);
    glVertex3d(0.0, 0.0, 1.0);
    glTexCoord2d(0.0, 1.0);
    glVertex3d(0.0, 1.0, 1.0);
    glTexCoord2d(1.0, 1.0);
    glVertex3d(1.0, 1.0, 1.0);
    glTexCoord2d(1.0, 0.0);
    glVertex3d(1.0, 0.0, 1.0);

  glEnd();
  popmatrix(__LINE__);
  glPopMatrix();

}

static void Destroy(w)
XsMagTapeWidget w;
{
  /*
	This must release all GC's and
	remove all callbacks
  */
  if(debug&DEBUGbuffer) fprintf(debug_fh, "MagTape: Destroy called.\n");

  fclose(w->magTape.buffer_fh);
}

GLvoid displayClockStroke(XsMagTapeWidget w)
{
  double textXmin, textXmax, textYmin, textYmax;
  double size=50.0;
  double t=seconds(w);
  char txt[100];
  if(debug&DEBUGbuffer) {fprintf(debug_fh, "displayClockStroke: %10.3f\n",t); fflush(debug_fh); }
  sprintf(txt, "%10.3f", t);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glViewport(0, w->magTape.height/2, w->magTape.width/3, w->magTape.height/2);
  glOrtho(0.0,(double)XMAX,0.0,((double)YMAX),-1.0,1.0);
  glMatrixMode(GL_MODELVIEW);
  glDisable(GL_TEXTURE_2D);
  glDisable(GL_BLEND);
  bbox(size, &textXmin, &textXmax, &textYmin, &textYmax, txt);
//printf("textXmin: %g textXmax: %g textYmin: %g textYmax: %g\n",textXmin,textXmax,textYmin,textYmax);
  glBegin(GL_LINES);
  glColor4dv(glcolors[TAPE_COLOR_RED]);
  stroke(size, XMAX/2-(textXmax-textXmin)/2.0, YMAX-textYmax-YMAX/50.0, 1.0, txt);
  glEnd();
}

GLvoid displayClock(XsMagTapeWidget w)
{
  double t=seconds(w);
  char txt[100];
  sprintf(txt, "%10.3f", t);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glViewport(0, 0, w->magTape.width, w->magTape.height);
  glOrtho(0.0,(double)XMAX,0.0,((double)YMAX),-1.0,1.0);
  glMatrixMode(GL_MODELVIEW);
  glDisable(GL_TEXTURE_2D);
  glDisable(GL_BLEND);
  glColor4dv(glcolors[TAPE_COLOR_RED]);
  glRasterPos2d(140.0, YMAX-30.0);
  glPushAttrib(GL_LIST_BIT);
  glListBase(w->magTape.fontbase - 32);
  glCallLists(strlen(txt), GL_UNSIGNED_BYTE, txt);
  glPopAttrib();
}

static void Redisplay(w)
XsMagTapeWidget w;
{
  int unitNo,i;
  PAINTSTRUCT ps;
  if(debug&DEBUGbuffer)
  {
    fprintf(debug_fh, "MagTape: Redisplay entry.\n");
    for(i=0;i<6;i++)
      fprintf(debug_fh, "Redisplay I: unit: %d status: %d %s\n",i,w->magTape.status[i],status_text(w->magTape.status[i]));
    fflush(debug_fh);
  }

  Layout(w);
  hDC = BeginPaint(magtapehwnd, &ps);
  if(debug&DEBUGbuffer)
  {
    fprintf(debug_fh, "MagTape: BeginPaint:\n");
    fprintf(debug_fh, "\tfErase: %d\n",ps.fErase);
    fprintf(debug_fh, "\tfleft: %d\n",ps.rcPaint.left);
    fprintf(debug_fh, "\tfright: %d\n",ps.rcPaint.right);
    fprintf(debug_fh, "\tftop: %d\n",ps.rcPaint.top);
    fprintf(debug_fh, "\tfbottom: %d\n",ps.rcPaint.bottom);
  }
  if(w->magTape.hRC==NULL)
  {
    if(debug&DEBUGbuffer) fprintf(debug_fh, "wglCreateContext failed\n");
    return;
  }
  if(!wglMakeCurrent(hDC,w->magTape.hRC))
  {
    fprintf(stderr,"wglMakeCurrent failed\n");
  }
  for(unitNo=0; unitNo<w->magTape.ndrives; unitNo++)
  {
    if(debug&DEBUGbuffer) {fprintf(debug_fh, "Call DrawGLScene unitNo: %d\n",unitNo); fflush(debug_fh); }
    DrawGLScene(w,unitNo);
    if(debug&DEBUGbuffer) {fprintf(debug_fh, "Done DrawGLScene unitNo: %d\n",unitNo); fflush(debug_fh); }
  }
  displayClockStroke(w);


  glFlush();
  // since this is double buffered, swap the buffers to display what just got drawn.
  if(debug&DEBUGbuffer){ fprintf(debug_fh, "swap buffers\n"); fflush(debug_fh); }
  SwapBuffers(hDC);
  wglMakeCurrent(NULL, NULL);
//ReleaseDC(magtapehwnd,hDC);
//wglDeleteContext(hRC);
  EndPaint(magtapehwnd, &ps);

  if(debug&DEBUGbuffer)
  {
    for(i=0;i<6;i++)
    fprintf(debug_fh, "Redisplay II: unit: %d status: %d %s\n",i,w->magTape.status[i],(w->magTape.status[i] == TAPE_IDLE)?"IDLE":"busy");
  }
  if(debug&DEBUGbuffer) fprintf(debug_fh, "Redisplay exit.\n");
}

LONG WINAPI magtapeWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  XsMagTapeWidget w=MagTape;
  PrintMessage(uMsg);
  switch(uMsg)
  {
    case WM_SIZE:
      w->magTape.width = LOWORD(lParam);
      w->magTape.height = HIWORD(lParam);
      if(debug&DEBUGbuffer) {fprintf(debug_fh, "magtapeWndProc: geo: %d %d\n",w->magTape.width,w->magTape.height); fflush(debug_fh); }
      break;
    case WM_PAINT:
      if(debug&DEBUGbuffer) {fprintf(debug_fh, "magtapeWndProc: WM_PAINT TimerRunning: %d\n",TimerRunning); fflush(debug_fh); }
      Redisplay(w);
      /* if TimerRunning is 1, and no WM_TIMER event exist, restart timer */
      if(TimerRunning==1)
      {
	MSG Msg;
	int status;
	status=PeekMessage(&Msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE);
	if(status==0)
	{
	  if(debug&DEBUGbuffer) {fprintf(debug_fh, "magtapeWndProc: WM_PAINT Restart timer\n"); fflush(debug_fh); }
	  KillTimer(hWnd, 1);
	  if(SetTimer(magtapehwnd, 1, TIMER_INTERVAL, NULL)==0)
	  {
	    DWORD dw=GetLastError();
	    fprintf(stderr, "SetTimer failed: %ld\n",dw);
	    if(debug&DEBUGbuffer) {fprintf(debug_fh, "SetTimer failed: %ld\n",dw); fflush(debug_fh);}
	  }
	  TimerRunning=1;
	}
      }
      break;
    case WM_TIMER:
      if(debug&DEBUGbuffer) {fprintf(debug_fh, "magtapeWndProc: WM_TIMER\n"); fflush(debug_fh); }
      KillTimer(hWnd, 1);
      TimerRunning=0;
      timercb(hWnd, 0, 0, 0);
      break;
    default:
      return DefWindowProc(hWnd, uMsg, wParam, lParam);
  }
  return 0;
}

static void XsmagTapeInsertValues(w)
XsMagTapeWidget w;
{
  int i;
  if(debug&DEBUGbuffer) fprintf(debug_fh, "XsmagTapeInsertValues entry.\n");

    for(i=0; i<NDRIVES; i++)
    {
      w->magTape.tapeLabels[i] = malloc(80);
      sprintf(w->magTape.tapeLabels[i], "tape %d",i+1);
    }
}


void XsmagTapeInsertDefaultValues(w)
XsMagTapeWidget w;
{
  int i;

  if(debug&DEBUGbuffer) fprintf(debug_fh, "XsmagTapeInsertDefaultValues entry.\n");

  for(i=0;i<NDRIVES;i++)
  {
    w->magTape.inTape[i] = MAXCHAMPERTAPELENGTH*0.5;
    w->magTape.outTape[i] = MAXCHAMPERTAPELENGTH*0.5;
    w->magTape.inError[i] = 0.0;
    w->magTape.outError[i] = 0.0;
    w->magTape.OUTlength[i] = 0.0;
    w->magTape.INlength[i] = TAPELENGTH;
    w->magTape.tapeappetite[i] = 0.0;
    w->magTape.status[i] = TAPE_IDLE;
    w->magTape.color_status[i] = TAPE_IDLE_COLOR;
    tapeuakk(w,i,5);
    if(debug&DEBUGbuffer) fprintf(debug_fh, "XsmagTapeInsertDefaultValues: unit: %d status: %d %s\n",i,w->magTape.status[i],(w->magTape.status[i] == TAPE_IDLE)?"IDLE":"busy");
    w->magTape.readstart[i] = 0;
    w->magTape.taperead[i] = 0;
    w->magTape.UAKK[i] = UAKK1;
    w->magTape.capstanAcceleration[i] = 0;
  }
  w->magTape.time0 = clock_count;
  w->magTape.thickness = THICKNESS;
  w->magTape.radius0 = 0.113/2.0;
  w->magTape.lastsecs=seconds(w);
  w->magTape.timerRunning=0;
  w->magTape.ndrives=NDRIVES;
  w->magTape.buffer_fh = fopen("buffer.log","w");
//fprintf(stderr, "buffer_fh I: %ld\n", (long)(w->magTape.buffer_fh));
  XsmagTapeInsertValues(w);
  if(debug&DEBUGbuffer) fprintf(debug_fh, "XsmagTapeInsertDefaultValues exit.\n");
}

static int lastUnitNo=0;

static void done_magTape(XsMagTapeWidget w,int unitNo)
{
  static long lunitNo;

  lunitNo=unitNo;

}

/* Exported functions */

extern double tape_position(int);

void XsmagTapeLog(XsMagTapeWidget w, int unitNo, char *txt)
{
  double t=seconds(w);
  double position;
  int i;
  position=tape_position(unitNo+1);
//fprintf(stderr, "buffer_fh II: %ld\n", (long)(w->magTape.buffer_fh));
  fprintf(w->magTape.buffer_fh, "%d: %8.3f\t",unitNo,t);
//fprintf(stderr, "buffer_fh II.2: %ld\n", (long)(w->magTape.buffer_fh));
//for(i=0;i<unitNo;i++) fprintf(w->magTape.buffer_fh, "\t");
  fprintf(w->magTape.buffer_fh, "%s %.2f%s\n", txt, position, (position>TAPELENGTH)?" EOT":"");
  fflush(w->magTape.buffer_fh);
  if(debug&DEBUGbuffer) fprintf(debug_fh, "XsmagTapeLog: %d %8.3f\t%s %.2f%s\n", unitNo,t,txt,position,(position>TAPELENGTH)?" EOT":"");
  
}

int XsmagTapeIdle(XsMagTapeWidget w,int unitNo)
{
//fprintf(stderr, "XsmagTapeIdle. buffer_fh: %ld\n", (long)(w->magTape.buffer_fh));
//if(debug&DEBUGbuffer) fprintf(debug_fh, "XsmagTapeIdle: unit: %d status: %d %s\n",unitNo,w->magTape.status[unitNo],(w->magTape.status[unitNo] == TAPE_IDLE)?"IDLE":"busy");
  return(w->magTape.status[unitNo] == TAPE_IDLE);
}

int XsmagTapeCommand(XsMagTapeWidget w, int unitNo, int cmd, double parameter, int type)
{
  int ret=1;
  char *cmds[]={"TAPE_IDLE","TAPE_FORWARD","TAPE_REVERSE","TAPE_DO_REWIND","TAPE_SETPOS"};
  int stopped;
  if(debug&DEBUGbuffer) fprintf(debug_fh, "XsmagTapeCommand called %d %d %g %d\n",unitNo,cmd,parameter,type);

  if(debug&DEBUGbuffer) fflush(debug_fh);
  if(debug&DEBUGbuffer) { fprintf(debug_fh, "%d: XsmagTapeCommand\n", unitNo); fflush(debug_fh); }
  if(debug&DEBUGbuffer) { fprintf(debug_fh, "%d: XsmagTapeCommand status: %d\n", unitNo, w->magTape.status[unitNo]); fflush(debug_fh); }
  if(debug&DEBUGbuffer) { fprintf(debug_fh, "%d: XsmagTapeCommand status: %d taperead: %g\n", unitNo, w->magTape.status[unitNo], w->magTape.taperead[unitNo]); fflush(debug_fh); }
  if(debug&DEBUGbuffer) { fprintf(debug_fh, "%d: XsmagTapeCommand status: %d taperead: %g type: %s\n", unitNo, w->magTape.status[unitNo], w->magTape.taperead[unitNo], tape_color_types[type]); fflush(debug_fh); }
  if(debug&DEBUGbuffer) { fprintf(debug_fh, "%d: XsmagTapeCommand status: %d taperead: %g type: %s cmd: %s\n", unitNo, w->magTape.status[unitNo], w->magTape.taperead[unitNo], tape_color_types[type], cmds[cmd]); fflush(debug_fh); }
  w->magTape.color_status[unitNo] = type;
  tapeuakk(w,unitNo,6);
  if(w->magTape.status[unitNo]!=TAPE_IDLE)
  {
    if(debug&DEBUGbuffer) fprintf(debug_fh, "%d TapeCommand: Tape is already running: %d!\n", unitNo, w->magTape.status[unitNo]);
    if(debug&DEBUGbuffer) fflush(debug_fh);
    return 1;
  }
  if(cmd==TAPE_SETPOS)
  {
    if(parameter==0.0)
    {
      cmd=TAPE_DO_REWIND;
      if(debug&DEBUGbuffer) { fprintf(debug_fh, "%d: cmd: %d\n", unitNo, cmd); fflush(debug_fh); }
    }
    else if(parameter>w->magTape.taperead[unitNo])
    {
      cmd=TAPE_FORWARD;
      if(debug&DEBUGbuffer) { fprintf(debug_fh, "%d: cmd: %d\n", unitNo, cmd); fflush(debug_fh); }
      parameter -= w->magTape.taperead[unitNo];
    }
    else if(parameter<w->magTape.taperead[unitNo])
    {
      cmd=TAPE_REVERSE;
      if(debug&DEBUGbuffer) { fprintf(debug_fh, "%d: cmd: %d\n", unitNo, cmd); fflush(debug_fh); }
      parameter = w->magTape.taperead[unitNo]-parameter;
    }
    else
    {
      /* already at position */
      if(debug&DEBUGbuffer) { fprintf(debug_fh, "%d: already at position, exit\n", unitNo); fflush(debug_fh); }
      return 0;
    }
  }
  switch(cmd)
  {
    case TAPE_DO_REWIND:
      if(w->magTape.taperead[unitNo]>0)
      {
	w->magTape.capstanAcceleration[unitNo]=-CAPSTANACCELERATION;
	w->magTape.lastCapstan[unitNo]=-1.0;
	w->magTape.UAKK[unitNo]=UAKK2;
	w->magTape.status[unitNo]=REWIND_ACCELERATE;
	if(debug&DEBUGbuffer) fprintf(debug_fh, "%d: start REWIND\n", unitNo);
	if(debug&DEBUGbuffer) fflush(debug_fh);
	ret=0;
      }
      break;
    case TAPE_FORWARD:
      w->magTape.readstart[unitNo]=w->magTape.taperead[unitNo];
      w->magTape.tapeappetite[unitNo]=parameter;
      w->magTape.capstanAcceleration[unitNo]=CAPSTANACCELERATION;
      w->magTape.lastCapstan[unitNo]=1.0;
      w->magTape.UAKK[unitNo]=UAKK1;
      w->magTape.status[unitNo]=FORWARD_ACCELERATE;
      if(debug&DEBUGbuffer) fprintf(debug_fh, "%d: start FORWARD\n", unitNo);
      if(debug&DEBUGbuffer) fflush(debug_fh);
      ret=0;
      break;
    case TAPE_REVERSE:
      if(w->magTape.taperead[unitNo]>0)
      {
	w->magTape.readstart[unitNo]=w->magTape.taperead[unitNo];
	w->magTape.tapeappetite[unitNo]=parameter;
	w->magTape.capstanAcceleration[unitNo]=-CAPSTANACCELERATION;
	w->magTape.lastCapstan[unitNo]=-1.0;
	w->magTape.UAKK[unitNo]=UAKK1;
	w->magTape.status[unitNo]=REVERSE_ACCELERATE;
	if(debug&DEBUGbuffer) fprintf(debug_fh, "%d: start REVERSE\n", unitNo);
	if(debug&DEBUGbuffer) fflush(debug_fh);
	ret= 0;
      }
      break;
  }
  if(debug&DEBUGbuffer) fprintf(debug_fh, "%d: XsmagTapeCommand: timerRunning I: %d\n",unitNo,w->magTape.timerRunning);
  if(debug&DEBUGbuffer) fflush(debug_fh);
  InvalidateRect(magtapehwnd, NULL, 0);
  if(!w->magTape.timerRunning)
  {
    stopped=setTimerRunning(w,3,1);
    if(debug&DEBUGbuffer) fprintf(debug_fh, "%d: XsmagTapeCommand: timerRunning II: %d stopped: %d\n",unitNo,w->magTape.timerRunning,stopped);
    if(debug&DEBUGbuffer) fflush(debug_fh);
    if(w->magTape.timerRunning)
    {
      w->magTape.lastsecs=seconds(w);
      startTimer(w);
    }
  }
  fflush(stdout);
  return(ret) ;
}

