/*
 * Copyright 1988, 1989, 1990, 1991 Massachusetts Institute of Technology
 */
/* rpd_driver.h */

/* RMS: this supercedes the 'tdriv.h' file */

#ifndef RPD_DRIVER_H
#define RPD_DRIVER_H

typedef struct _frameblock
{
	int	start;		/* beginning of block */
	int	nframes;	/* #frames in block (including 1st) */
	int	owner;		/* non-zero if anyone has claimed it */
	int	recorded;	/* non-zero if block is recorded on */
	int     volume_id;      /* volume info for use in client struct */
	char    volume_name[30];/* name of volume*/
	struct _frameblock *next;	
} RPD_SEGLIST;

typedef int (*METHOD)();

typedef struct 
{
  int		fd;		/* the file for talking */
  int           devnum;         /* device number for the rpd since
                                   some rpd'es can be chained  */
  Server        *serv;          /* for netrpd's */
  char		port[16];	/* tty_port name - for debugging */
  char		model[32];	/* manufacturer's name */
  char		devname[32];	/* logical name */
  int           devtype;        /* same as above but compiled */
  char		volume[128];	/* what's currently mounted */
  int           volnum;         /* this to use for netrpd's */
  int           speed;          /* to cache this info */
  int           frame;          /* negative means invalid frame */
  int	       	firstframe;	/* first valid frame (current volume) */
  int           lastframe;      /* last valid frame (approx.) */
  int           pseudo_out;     /* for recorders only */
  int           num_errors;     /* number of consecutive errors */
#ifdef NEW_VERSION
  int           max_errors;     /* max consecutive allowed on this device */
#endif /* NEW_VERSION */
  int           avail;          /* -1 if avail, clinum if busy. */
  /* if rpd is recorder, next 2 ptrs will be non-NULL */
  
  RPD_SEGLIST   *freelist;	/* blocks of free space */
  RPD_SEGLIST   *usedlist;	/* blocks of recorded space */

  char          *extension;     /* ptr to device-specific extension (if any) */
  
  struct
    {
      unsigned	audio1_on :	1;
      unsigned	audio2_on :	1;
      unsigned	indexon :	1; /* if char gen display is on */
      unsigned	volume_loaded : 1; /* if media is in device, ready for playback */
      unsigned	not_responding: 1; /* gets set after no response to reset */
      unsigned  defdisp:        1; /* if banner is on */

/* new flags */
      unsigned  CLV:            1; /* if current disc is CLV mode */
      unsigned  ejected:        1; /* gets set after eject */
      unsigned  inited:         1; /* if initial device state has been set */
#ifdef OBSOLETE
      unsigned  tapedev:        1; /* if device is not a disc, but a tape */
#endif /* OBSOLETE */
    }		state;
  
  int scratch;  /* scratch byte for temp state */
  
  Output          output_chans[MAXSERVEROUTS];
  int             outputnum[MAXSERVEROUTS];
  METHOD                proddev;        /* no args */
  METHOD		reset;		/* no args */
  METHOD		cmd;		/* 1 arg; see below */
  METHOD		search;		/* ( frame, wait ) */
  METHOD		segplay;	/* ( fr1, fr2, , speed, wait ) */
  METHOD		getframe;	/* no args */
  METHOD		getspeed;	/* no args */
  METHOD		varspeed;	/* 1 arg; see below */
  METHOD		jog;		/* jog( 1 arg; +- n frames ); */
  METHOD		record;		/* ( begin, end, speed, wait ) */
  METHOD                recordsetup;    /* (begin, end) */
  METHOD                recordlen;      /* (len, speed, wait) */
  METHOD                buildfreelist;  /* build list of free frames */
#ifdef OBSOLETE
/* These are fairly player independant, I'm going to try to use routines
   in rpd_util.c  -- danapple */
  METHOD		valloc;		/* ( nframes ) */
  METHOD		vfree;		/* ( start, nframes ) */
#endif /* OBSOLETE */
} RPD, *RPD_ptr;

RPD_ptr	rpdutil_open();
RPD_ptr	rpdutil_close();

int rpd_getspeed_f();

/* stuff for player caching -- hal */
#define rpd_getspeed(rpd) (rpd->speed)
#define rpd_getframe(rpd) (rpd->frame)
#define rpd_setspeed(rpd,spd) (rpd->speed = spd)
#define rpd_setframe(rpd,frm) (rpd->frame = frm)

#define rpd_error(rpd) if (++(rpd->num_errors) > MAX_ERRORS) need_to_rebuild_list = 1
#ifdef NEW_VERSION
#define rpd_error(rpd) if (++(rpd->num_errors) > rpd->max_errors || rpd->num_erros > MAX_ERRORS) need_to_rebuild_list = 1;
#endif /* NEW_VERSION */

#define rpd_clear_error(rpd) (rpd->num_errors = 0)

/* russ: stuff for calculating maximum error in getframe requests
   (where disc was when we asked vs. where it is by the time
   we get the reply); assume that in the 1200+ baud range,
   this is going to be at most 2 frames (1 or 0 at 9600,
   1 at 4800, 1-2 at 2400, 2 at 1200); possible error increases
   with disc speed */

#define MAX_GETFRAME_DELAY 2
#define MAX_GETFRAME_ERROR(fps) (int)(((fps) * (MAX_GETFRAME_DELAY / 30.0)) + .5)

#endif
