;:ts=8
	far	code
	far	data
;/*  TT8 specific includes  */
;#include        <TT8.h>                 /* Tattletale Model 8 Definitions */
;#include        <tat332.h>              /* 68332 Tattletale (7,8) Hardware Definitions */
;#include        <sim332.h>              /* 68332 System Integration Module Definitions */
;#include        <qsm332.h>              /* 68332 Queued Serial Module Definitions */
;#include        <dio332.h>              /* 68332 Digital I/O Port Pin Definitions */
;#include        <tt8lib.h>              /* definitions and prototypes for Model 8 library */
;
;/*  general C includes  */
;#include        <stdio.h>
;#include        <stdlib.h>
;#include        <userio.h>
;#include		<math.h>
;
;/*  includes specific to the ad7716 routines  */
;#include		"ASSERT.h"
;#include		"memcheck.h"
;#include		"ad7716.h"
;#include		"logtime.h"
	dseg
	ds	0
_LATEST_LOGGER_TIME:
	ds.b	0
	dc.l	$ffffffff
	dc.l	$0000
	cseg
	dseg
	ds	0
_EARLIEST_LOGGER_TIME:
	ds.b	0
	dc.l	$0000
	dc.l	$0000
	cseg
;#include		"misc.h"
;#include		"text_log.h"
;
;//  Frequency of the crystal which the AD7716 is using
;#define			XTAL_FREQ		7.3728e6F
;
;//  Local routines used only within AD7716.c
;int AD7716_SPI_buffer_open (long n_points);
;void AD7716_SPI_buffer_delete (void);
;void AD7716_SPI_buffer_empty (void);
;void AD7716_SPI_interface_init (void);
;void AD7716_SPI_master_out (void);
;void AD7716_SPI_master_in (void);
;void AD7716_SPI_rupt_handler (void);
;void AD7716_SPI_read_data (void);
;void AD7716_reset (void);
;void AD7716_command (short LSByte, short MSByte);
;void AD7716_rupt_handler (void);
;long AD7716_data_to_long (unsigned short low, unsigned short high);
;void AD7716_push_data_to_buff (long value);
;int AD7716_interrupt_serviced (void);
;int AD7716_data_saved (void);
;void AD7716_program_hardware (void);
;void AD7716_software_SPI_write (int byte);
;
;void AD7716_filter_chan_zero (unsigned short high, unsigned short low);
;void AD7716_filter_chan_one (unsigned short high, unsigned short low);
;void AD7716_filter_chan_two (unsigned short high, unsigned short low);
;void AD7716_filter_chan_three (unsigned short high, unsigned short low);
;
;
;//  Local structure used to track information describing the 7716 converter
;//  setup
;struct AD7716  {
;	short AD7716_open_flag;			//  non-zero if we the 7716 is active
;	short convert_rate;				//	conversion rate
;	short save_channels;			//  bit pattern specifies which channels to save
;	short n_channels;				//  number of channels to save
;
;	volatile unsigned long icounter;
;
;	volatile unsigned long data_pushed;
;									//  reset to zero when the start time is saved; incremented
;									//  each time a piece of data is pushed onto the SPI_buffer
;	time_tt start_time;				//  time at which we last saved data used in calculating
;									//  the actual conversion rate
;	double measured_rate;			//  actual conversion rate, as measured using the precision
;									//  TT8 clock and a count of the number of conversions recieved
;	long rate_calc_threshold;		//  number of data points to push on buffer before recalculating
;									//  the conversion rate									
;	short n_to_average;				//  Number of points which are averaged together
;									//  Also the decimation rate.									
;	long c0_total;
;	long c1_total;
;	long c2_total;
;	long c3_total;
;	short c0_n_averaged;									
;	short c1_n_averaged;									
;	short c2_n_averaged;									
;	short c3_n_averaged;									
;	short SPI_finished;				//  flag set when the SPI completes
;	#ifdef SIMULATE_DATA
;		short sim_chan[4];			//  remembers the bit pattern used for channel
;									//  numbers when simulating data
;		unsigned long n_simulated;									
;	#endif
;} AD7716;
;
;//  Recalculate the rate every 300 seconds.  This will have given 12 million
;//  ticks of the clock, which I presume to give an accuracy of approximately
;//  one part in 12 million.  This should be accurate enough.  An alternative
;//  way of looking at this is that we can project time forward or backward by
;//  counting samples and using the rate, and err by only 1 tick over every 300
;//  seconds we project.
;#define		DTIME_RATE_CALCULATION	(300L)
;
;
;#ifdef SIMULATE_DATA
;	unsigned long AD7716_get_sim_count (void)  {
;		return AD7716.n_simulated;
;	}	
;	void AD7716_reset_sim_count (void)  {
;		AD7716.n_simulated = 0;
;	}	
;#endif
;
;
;
;/*  This struct is used by the SPI interrupt handler routines to buffer data before
; *  passing it on to the main routines.  This structure is not designed for use
; *  by the end user.
;*/
;struct SPI_buffer  {
;	long* data_start;			//  pointer to the start of the data buffer
;	long n_points;				//  number of longs which the buffer can hold
;	long* data_end;				//  pointer to the position one past the end of the buffer.
;								//  this is just here for convenience so we don't have to
;								//  keep calculating it each time we need it.
;	long* next_in;				//  pointer to position in the buffer to which we will
;								//  writing the next data point
;	long* next_out;				//  pointer to position in the buffer from which we will
;								//  remove the next data point when taking data from the
;								//  buffer; NULL if the routines have not been inited.
;								//  Equals next_in if there is no data available.
;	short overflow;				//  flag is set non-zero if we accidentally overflow the
;								//  the buffer and overwrite data.								
;} SPI_buffer;
; 
;
;#define         AD7716_BAUD             4
;#define         AD7716_DSCKL            1
;#define         AD7716_DTL              1
;
;#define			AD7716_CONVERT_129HZ	1
;#define			AD7716_CONVERT_257HZ	2
;
;
;//  The next few subroutines are error checking routines used during debug only.
;//  If the variable DEBUG is defined, they execute, otherwise they are defined
;//  as NOOP.  These must be the first routines in this file to insure that the
;//  'defines' work correctly.  These routines are not designed for error checking
;//  variables that the user enters.  That code is spread throughout the file.
;//  Rather, they are designed to insure that the internal variables
;//  describing what the code should do are all self-consistent, and that they
;//  won't crash the system when the code executes.  If an error is discovered,
;//  the code will abort and print an error message.  The routine
;//  sci_logger_assert_valid() should be callable at the start or finish of any
;//  of these routines without printing an error message.
;//
;#ifdef DEBUG
;//  This is essentially a special version of ASSERT that allows us to print out
;//  two line numbers.  It is used only here for the AD7716_assert_valid routine.
;//  It is useful because it allows us to print both the line number of the assert
;//  which failed and the line number from which we called the assert_valid routine.
;//  We don't bother to print the file name, because it is used only within this file
;//
;void AD7716_VALIDITY_FAILURE (void* exp, unsigned line1, unsigned line2)  {
;	fflush (stdout);
;	fflush (stderr);
;	printf ("\n\n***************************************\n");
;	printf ("AD7716 validity failure: %s @\n", (char*)exp);
;	printf ("  line %d, called from line %d\n", line1, line2);
;	printf ("***************************************\n\n");
;	fflush (stdout);
;    fflush (stderr);
;	exit (-1);
;}
;#define TEST_VALID(exp) \
;	    ( (exp) ? (void) 0 : AD7716_VALIDITY_FAILURE (#exp, __LINE__, calling_line) )
;
;//  AD7716_assert_valid (void)
;//  Internal use only
;//  Debugging use only
;//
;//  This routine checks the internal consistency of the science logger
;//  data structure in every way that I can think of.  It should be updated
;//  any time the logger code is changed.
;//  If the variable DEBUG is not defined, then this subroutine is defined
;//	so as to be a NOOP.  See code immediately following the #else.
;//
;void AD7716_assert_valid (unsigned calling_line)  {
;
;	TEST_VALID ((AD7716.AD7716_open_flag == 0) || (AD7716.AD7716_open_flag == 1));
;	TEST_VALID ((AD7716.convert_rate == AD7716_CONVERT_129HZ) || (AD7716.convert_rate == AD7716_CONVERT_257HZ));
;	TEST_VALID ((AD7716.save_channels&0xFFF0) == 0);
;	TEST_VALID ((AD7716.n_channels >= 0) && (AD7716.n_channels <= 4));
;
;	if (AD7716.AD7716_open_flag == 0)  {
;		//  if no points are allocated, then we should be closed, and the pointers are
;		//  all NULL
;		TEST_VALID (SPI_buffer.n_points == 0);
;		TEST_VALID (SPI_buffer.data_start == NULL);
;		TEST_VALID (SPI_buffer.data_end == NULL);
;		TEST_VALID (SPI_buffer.next_in == NULL);
;		TEST_VALID (SPI_buffer.next_out == NULL);
;		TEST_VALID (SPI_buffer.overflow == -1);
;	}  else  {
;		TEST_VALID ((SPI_buffer.overflow == 0) || (SPI_buffer.overflow == 1));
;		TEST_VALID (SPI_buffer.n_points > 0);
;		TEST_VALID (SPI_buffer.data_start != NULL);
;		TEST_VALID (SPI_buffer.data_end != NULL);
;		TEST_VALID (SPI_buffer.next_in != NULL);
;		TEST_VALID (SPI_buffer.next_out != NULL);
;		
;		TEST_VALID (SPI_buffer.data_end == &SPI_buffer.data_start[SPI_buffer.n_points]);
;		TEST_VALID (SPI_buffer.next_in >= SPI_buffer.data_start);
;		TEST_VALID (SPI_buffer.next_in < SPI_buffer.data_end);
;		TEST_VALID (SPI_buffer.next_out >= SPI_buffer.data_start);
;		TEST_VALID (SPI_buffer.next_out < SPI_buffer.data_end);
;		TEST_VALID (AD7716.n_to_average >= 1);
;		TEST_VALID (AD7716.n_to_average <= 8);
;	}
;}
;#endif
;
;
;
;
;//  AD7716_power_on_init (void)
;//  User callable
;//
;//	Called when the power is first turned on to make sure that the
;//  data structures are properly initialized.
;//
;void AD7716_power_on_init (void)  {
# 224 'ad7716.c' 659076233
| .2
	xdef	_AD7716_power_on_init
_AD7716_power_on_init:
;	//  first set all the hardware to power the chips off
;	AD7716_turn_power_off ();
^^	jsr	_AD7716_turn_power_off
;
;	//  then init the software variables
;	AD7716.AD7716_open_flag = 0;
^^^	clr.w	_AD7716
;	AD7716.convert_rate = AD7716_CONVERT_129HZ;
^	move.w	#1,_AD7716+2
;	SPI_buffer.data_start = NULL;
^	clr.l	_SPI_buffer
;	SPI_buffer.n_points = 0;
^	clr.l	_SPI_buffer+4
;	SPI_buffer.data_end = NULL;
^	clr.l	_SPI_buffer+8
;	SPI_buffer.next_in = NULL;
^	clr.l	_SPI_buffer+12
;	SPI_buffer.next_out = NULL;
^	clr.l	_SPI_buffer+16
;	SPI_buffer.overflow = -1;
^	move.w	#-1,_SPI_buffer+20
;
;	AD7716_assert_valid (__LINE__);
^^;}
^.3
	rts
.2
;
;
;
;
;void AD7716_turn_power_off (void)  {
# 244
| .4
	xdef	_AD7716_turn_power_off
_AD7716_turn_power_off:
;
;	//  Start by setting the shutdown pins for the power supply
;	TPUSetPin(4, SET);		//  CLR to turn on -Analog
^^^	move.w	#65535,-(sp)
	move.w	#4,-(sp)
	jsr	_TPUSetPin
;	TPUSetPin(5, SET);		//  CLR to turn on +Analog
^	move.w	#65535,-(sp)
	move.w	#5,-(sp)
	jsr	_TPUSetPin
;	
;	//  The adjust all the I/O pins.  Make sure they are driven low
;	//  so that we don't power the chips through their logic inputs
;	PConfOutp (E,0);	//  AD7716 TFS on the ADC module
^^^^;			PConfOutpE0
	dc.w	$8b8
	dc.w	$0
	dc.w	$fa17
	dc.w	$8f8
	dc.w	$0
	dc.w	$fa15
;	PClear (E,0);
^;			PClearE0
	dc.w	$8b8
	dc.w	$0
	dc.w	$fa11
;	PConfOutp (E,1);	//  ADC Reset line on the ADC module
^;			PConfOutpE1
	dc.w	$8b8
	dc.w	$1
	dc.w	$fa17
	dc.w	$8f8
	dc.w	$1
	dc.w	$fa15
;	PClear (E,1);
^;			PClearE1
	dc.w	$8b8
	dc.w	$1
	dc.w	$fa11
;
;	PConfOutp (E, 3);   //	E3 -> Output to ADC/ASI board controls science
^^;			PConfOutpE3
	dc.w	$8b8
	dc.w	$3
	dc.w	$fa17
	dc.w	$8f8
	dc.w	$3
	dc.w	$fa15
;	PClear (E,3);		//  channel 0 gain
^;			PClearE3
	dc.w	$8b8
	dc.w	$3
	dc.w	$fa11
;	PConfOutp (E, 5);	//	E5 -> Output to ADC/ASI board controls science
^;			PConfOutpE5
	dc.w	$8b8
	dc.w	$5
	dc.w	$fa17
	dc.w	$8f8
	dc.w	$5
	dc.w	$fa15
;	PClear (E,5);		//  channel 1 gain
^;			PClearE5
	dc.w	$8b8
	dc.w	$5
	dc.w	$fa11
;	PConfOutp (E, 6);   //	E6 -> Output to ADC/ASI board controls science
^;			PConfOutpE6
	dc.w	$8b8
	dc.w	$6
	dc.w	$fa17
	dc.w	$8f8
	dc.w	$6
	dc.w	$fa15
;	PClear (E, 6);		//  channel 2 gain
^;			PClearE6
	dc.w	$8b8
	dc.w	$6
	dc.w	$fa11
;	PConfOutp (E, 7);   //	E7 -> Output to ADC/ASI board controls science
^;			PConfOutpE7
	dc.w	$8b8
	dc.w	$7
	dc.w	$fa17
	dc.w	$8f8
	dc.w	$7
	dc.w	$fa15
;	PClear (E, 7);      //  channel 3 gain
^;			PClearE7
	dc.w	$8b8
	dc.w	$7
	dc.w	$fa11
;	
;	PConfOutp (F, 4);   //  Data Ready output from the 7716 chip
^^;			PConfOutpF4
	dc.w	$8b8
	dc.w	$4
	dc.w	$fa1f
	dc.w	$8f8
	dc.w	$4
	dc.w	$fa1d
;	PClear (F, 4);      //  Hold low with analog power off
^;			PClearF4
	dc.w	$8b8
	dc.w	$4
	dc.w	$fa19
;	PConfOutp(F,2);     //  DRDY output line from second ADC.  With the analog
^;			PConfOutpF2
	dc.w	$8b8
	dc.w	$2
	dc.w	$fa1f
	dc.w	$8f8
	dc.w	$2
	dc.w	$fa1d
;	PClear (F, 2);		//  power supply off, this can be held low
^;			PClearF2
	dc.w	$8b8
	dc.w	$2
	dc.w	$fa19
;	
;	//  Set the QSPI lines.  Configure the chip selects as low outputs, which
;	//  would normally select the chip, but which is irrelavent with the power
;	//  off.
;	PConfOutp (D,6);	//  pcs3 MAX186 A/D chip select active low
^^^^^;			PConfOutpD6
	dc.w	$8b8
	dc.w	$6
	dc.w	$fc16
	dc.w	$8f8
	dc.w	$6
	dc.w	$fc17
;	PSet (D,6);			//  disable the MAX186 (it is powered on still)
^;			PSetD6
	dc.w	$8f8
	dc.w	$6
	dc.w	$fc15
;	PConfOutp (D,5);	//  pcs2 1211 A/D chip select; active low, but
^;			PConfOutpD5
	dc.w	$8b8
	dc.w	$5
	dc.w	$fc16
	dc.w	$8f8
	dc.w	$5
	dc.w	$fc17
;	PClear (D,5);		//  hold low while power is off
^;			PClearD5
	dc.w	$8b8
	dc.w	$5
	dc.w	$fc15
;	PConfOutp (D,4);	//  pcs1 2nd 1211 A/D chip select as first
^;			PConfOutpD4
	dc.w	$8b8
	dc.w	$4
	dc.w	$fc16
	dc.w	$8f8
	dc.w	$4
	dc.w	$fc17
;	PClear (D,4);
^;			PClearD4
	dc.w	$8b8
	dc.w	$4
	dc.w	$fc15
;	PConfOutp (D,3);	//  pcs0 AD7716 RFS line.  hold low while power is off
^;			PConfOutpD3
	dc.w	$8b8
	dc.w	$3
	dc.w	$fc16
	dc.w	$8f8
	dc.w	$3
	dc.w	$fc17
;	PClear (D,3);
^;			PClearD3
	dc.w	$8b8
	dc.w	$3
	dc.w	$fc15
;	PConfOutp(D,2);	PClear(D,2);	//  SCLK
^;			PConfOutpD2
	dc.w	$8b8
	dc.w	$2
	dc.w	$fc16
	dc.w	$8f8
	dc.w	$2
	dc.w	$fc17
;			PClearD2
	dc.w	$8b8
	dc.w	$2
	dc.w	$fc15
;	PConfOutp(D,1);	PClear(D,2);	//  MOSI
^;			PConfOutpD1
	dc.w	$8b8
	dc.w	$1
	dc.w	$fc16
	dc.w	$8f8
	dc.w	$1
	dc.w	$fc17
;			PClearD2
	dc.w	$8b8
	dc.w	$2
	dc.w	$fc15
;	PInpToOut(D,0);					//  MISO - for minimum power draw we hope that
^;			PInpToOutD0
	dc.w	$8b8
	dc.w	$0
	dc.w	$fc16
	dc.w	$8b8
	dc.w	$0
	dc.w	$fc17
	dc.w	$11f8
	dc.w	$fc15
	dc.w	$fc15
	dc.w	$8f8
	dc.w	$0
	dc.w	$fc17
;									//  the MAX186 is holding this low
;}
^^	add.w	#8,sp
.5
	rts
.4
;	
;
;
;
;void AD7716_turn_power_on (void)  {
# 291
| .6
	xdef	_AD7716_turn_power_on
_AD7716_turn_power_on:
;
;	//  First make sure the power is off and the pins properly configured
;	//  If we don't do this it is possible to have partially powered the
;	//  chips through the logic lines, which can leave the ADC SPI interface
;	//  in a screwy configuration that might hang things.  Nothing in
;	//  the current code would do this, but the power off call is cheap
;	//  insurance against any changes that might be made.
;	AD7716_turn_power_off ();
^^^^^^^^	jsr	_AD7716_turn_power_off
;
;	//  Then reconfigure the MISO and DRDY lines so that the ADCs can
;	//  drive them; do this before powering the ADCs
;	PConfInp (D, 0);    //  MISO
^^^^;			PConfInpD0
	dc.w	$8b8
	dc.w	$0
	dc.w	$fc16
	dc.w	$8b8
	dc.w	$0
	dc.w	$fc17
;	PConfInp (F, 4);	//  Data ready output line from AD7716; convert this
^;			PConfInpF4
	dc.w	$8b8
	dc.w	$4
	dc.w	$fa1f
	dc.w	$8b8
	dc.w	$4
	dc.w	$fa1d
;						//  to a bus (interrupt) line when we are ready to
;						//  capture data
;	PConfInp (F, 2);	//  Data ready output line from BB1211
^^^;			PConfInpF2
	dc.w	$8b8
	dc.w	$2
	dc.w	$fa1f
	dc.w	$8b8
	dc.w	$2
	dc.w	$fa1d
;	
;	//  Then turn on the analog power supply
;	TPUSetPin(5, CLR);		//  CLR to turn on +Analog
^^^	clr.w	-(sp)
	move.w	#5,-(sp)
	jsr	_TPUSetPin
;	TPUSetPin(4, CLR);		//  CLR to turn on -Analog
^	clr.w	-(sp)
	move.w	#4,-(sp)
	jsr	_TPUSetPin
;	
;	//  Then re-adjust all the I/O pins.
;	PConfOutp (E,1);	//  ADC Reset line on the ADC module
^^^;			PConfOutpE1
	dc.w	$8b8
	dc.w	$1
	dc.w	$fa17
	dc.w	$8f8
	dc.w	$1
	dc.w	$fa15
;	PSet (E,1);			//  active high
^;			PSetE1
	dc.w	$8f8
	dc.w	$1
	dc.w	$fa11
;
;	PConfOutp (E, 3);   //	E3 -> Output to ADC/ASI board controls science
^^;			PConfOutpE3
	dc.w	$8b8
	dc.w	$3
	dc.w	$fa17
	dc.w	$8f8
	dc.w	$3
	dc.w	$fa15
;	PSet (E,3);			//  channel 0 gain; default to low gain
^;			PSetE3
	dc.w	$8f8
	dc.w	$3
	dc.w	$fa11
;	PConfOutp (E, 5);	//	E5 -> Output to ADC/ASI board controls science
^;			PConfOutpE5
	dc.w	$8b8
	dc.w	$5
	dc.w	$fa17
	dc.w	$8f8
	dc.w	$5
	dc.w	$fa15
;	PSet (E,5);			//  channel 1 gain
^;			PSetE5
	dc.w	$8f8
	dc.w	$5
	dc.w	$fa11
;	PConfOutp (E, 6);   //	E6 -> Output to ADC/ASI board controls science
^;			PConfOutpE6
	dc.w	$8b8
	dc.w	$6
	dc.w	$fa17
	dc.w	$8f8
	dc.w	$6
	dc.w	$fa15
;	PSet (E, 6);		//  channel 2 gain
^;			PSetE6
	dc.w	$8f8
	dc.w	$6
	dc.w	$fa11
;	PConfOutp (E, 7);   //	E7 -> Output to ADC/ASI board controls science
^;			PConfOutpE7
	dc.w	$8b8
	dc.w	$7
	dc.w	$fa17
	dc.w	$8f8
	dc.w	$7
	dc.w	$fa15
;	PSet (E, 7);		//  channel 3 gain
^;			PSetE7
	dc.w	$8f8
	dc.w	$7
	dc.w	$fa11
;
;	//  Set the QSPI lines.  Configure the chip selects so the chips are not
;	//  selected
;	PConfOutp (D,6);	//  pcs3 MAX186 A/D chip select active low
^^^^;			PConfOutpD6
	dc.w	$8b8
	dc.w	$6
	dc.w	$fc16
	dc.w	$8f8
	dc.w	$6
	dc.w	$fc17
;	PSet (D,6);			//  disable the MAX186
^;			PSetD6
	dc.w	$8f8
	dc.w	$6
	dc.w	$fc15
;	PConfOutp (D,5);	//  pcs2 BB1211 A/D chip select; active low
^;			PConfOutpD5
	dc.w	$8b8
	dc.w	$5
	dc.w	$fc16
	dc.w	$8f8
	dc.w	$5
	dc.w	$fc17
;	PSet (D,5);
^;			PSetD5
	dc.w	$8f8
	dc.w	$5
	dc.w	$fc15
;	PConfOutp (D,4);	//  pcs1 2nd BB1211 A/D chip select as first
^;			PConfOutpD4
	dc.w	$8b8
	dc.w	$4
	dc.w	$fc16
	dc.w	$8f8
	dc.w	$4
	dc.w	$fc17
;	PSet (D,4);
^;			PSetD4
	dc.w	$8f8
	dc.w	$4
	dc.w	$fc15
;	PConfOutp (D,3);	//  pcs0 AD7716 RFS line.
^;			PConfOutpD3
	dc.w	$8b8
	dc.w	$3
	dc.w	$fc16
	dc.w	$8f8
	dc.w	$3
	dc.w	$fc17
;	PSet (D,3);
^;			PSetD3
	dc.w	$8f8
	dc.w	$3
	dc.w	$fc15
;	PConfOutp (E,0);	//  AD7716 TFS on the ADC module
^;			PConfOutpE0
	dc.w	$8b8
	dc.w	$0
	dc.w	$fa17
	dc.w	$8f8
	dc.w	$0
	dc.w	$fa15
;	PSet (E,0);
^;			PSetE0
	dc.w	$8f8
	dc.w	$0
	dc.w	$fa11
;	
;	//  de-assert the ADC reset line
;	PClear (E,1);
^^^;			PClearE1
	dc.w	$8b8
	dc.w	$1
	dc.w	$fa11
;}
^	add.w	#8,sp
.7
	rts
.6
;	
;
;	
;
;
;//  AD7716_open (long n_buffer_points)
;//  User callable
;//
;//	Sets up the data structures used to get conversions from the
;//  AD7716 for conversions.reading.  Inits the buffers; does not
;//  mark any channels for saving; does not begin conversions, but
;//  sets up the hardware interface.
;//	DON'T call this routine unless the power has been turned on.
;//
;//  Arguments:
;//		n_buffer_points = length of the buffer into which the data
;//			is pushed, measured in long words.
;//	Returns: 0 if OK, negative on failure
;//	Failures: Fails if there is insufficient memory for the buffer
;//
;int AD7716_open (long n_buffer_points)  {
# 362
| .8
	xdef	_AD7716_open
_AD7716_open:
;	//  shouldn't call open when we're already open
;	ASSERT (AD7716.AD7716_open_flag	== 0);
~~ n_buffer_points 8 "l"
^^;
;	//  First mark us as open so the other routine will respond correctly
;	AD7716.AD7716_open_flag	= 1;
^^^	move.w	#1,_AD7716
;
;	//  no channels yet selected
;	AD7716.n_channels = 0;
^^^	clr.w	_AD7716+6
;	AD7716.save_channels = 0;
^	clr.w	_AD7716+4
;	
;	//  no averaging used to start
;	AD7716.n_to_average = 1;
^^^	move.w	#1,_AD7716+36
;	
;	//  make sure the system knows that the measured rate is not yet valid
;	AD7716.measured_rate = -1.0;
^^^	move.l	#$00000000,_AD7716+28
	move.l	#$bff00000,_AD7716+24
;
;	//  And allocate space for SPI data buffer
;	if (AD7716_SPI_buffer_open (n_buffer_points) < 0)  {
^^^	move.l	4(sp),-(sp)
	jsr	_AD7716_SPI_buffer_open
	tst.w	d0
	add.w	#4,sp
	bge	.10001
;		//  on failure make sure we unmark us as open
;		AD7716.AD7716_open_flag	= 0;
^^	clr.w	_AD7716
;		return -1;
^	move.l	#-1,d0
.9
	rts
;	}
^;	//  make sure interrupt servicing for the 7716 DRDY line is off
;	PConfInp (F,4);
.10001
^^;			PConfInpF4
	dc.w	$8b8
	dc.w	$4
	dc.w	$fa1f
	dc.w	$8b8
	dc.w	$4
	dc.w	$fa1d
;
;	//  Init the SPI interface to the 7716
;	AD7716_SPI_interface_init ();
^^^	jsr	_AD7716_SPI_interface_init
;
;	//  Reset the 7716 to a known state
;	AD7716_reset ();
^^^	jsr	_AD7716_reset
;	
;	//  Program the conversion rate, but don't start listening to the
;	//  interrupts yet
;	AD7716_program_hardware ();
^^^^	jsr	_AD7716_program_hardware
;	AD7716_assert_valid (__LINE__);
^;	return 0;
^	move.l	#0,d0
	bra	.9
;}
^.8
;
;
;
;
;//  AD7716_close ()
;//  User callable
;//
;//  Stops all conversions and deallocates all memory used.  The only
;//  A/D routine which the user may call after this is AD7716_open ()
;//
;void AD7716_close (void)  {
# 410
| .10
	xdef	_AD7716_close
_AD7716_close:
;	if (AD7716.AD7716_open_flag	== 0)
^;		return;
	tst.w	_AD7716
	bne	.10002
^.11
	rts
;
;	//  stop the data flow (i.e., the interrupt servicing) and delete
;	//  the buffers
;	AD7716_stop_data ();
.10002
^^^^	jsr	_AD7716_stop_data
;	AD7716_SPI_buffer_delete ();
^	jsr	_AD7716_SPI_buffer_delete
;	
;	//  REVIEW
;	//  we should probably configure the SPI port pins as outputs and drive them
;	//  low so that we can be sure we don't power the A/D through its digital input
;	//  pins
;
;	//  And finally mark the 7716 as closed
;	AD7716.AD7716_open_flag	= 0;
^^^^^^^^	clr.w	_AD7716
;	AD7716_assert_valid (__LINE__);
^;	return;
^	bra	.11
;}
^.10
;
;
;
;
;//  AD7716_set_channels (short channels)
;//  User callable
;//
;//  Sets which channels from the A/D are pushed into the data buffer for
;//  later retrieval using the AD7716_get_data_point() routine
;//
;//  Arguments:
;//		channel = bit pattern specifies which channels are to be
;//			saved in the buffer.  A bit is on if a channel is to be saved.
;//			Bit 0 represents what the AD7716 documentation calls channel 1.
;//			The AD7716 implements 4 channels.  (The rest of our code numbers
;//			channels as 0-3, not 1-4)
;//  Returns: none 
;//  Failures: during debugging, in an unused bit is set
;//
;void AD7716_set_channels (short channels)  {
# 448
| .12
	xdef	_AD7716_set_channels
_AD7716_set_channels:
	movem.l	d2/d3/d4,-(sp)
	move.w	16(sp),d4
;	unsigned short chan_bit, n;
;	#ifdef SIMULATE_DATA
;		int count;
;	#endif		
;	
;	//  Note: it isn't worth checking if we are actually opened
;	//  before we execute this code as it is in effect a NOOP.
;	
;	//  Doesn't make sense to change channels while collecting data.
;	//  Stop data (which also empties the buffers)
;	AD7716_stop_data ();
~ chan_bit d3 "I"
~ n d2 "I"
~~ channels d4 "i"
^^^^^^^^^^^	jsr	_AD7716_stop_data
;	
;	//  Calculate and record the channel information
;	AD7716.n_channels = 0;
^^^	clr.w	_AD7716+6
;	for (n = 0;  n < 4;  n++)  {
^	move.l	#0,d2
	bra	.10006
.10005
;		chan_bit = 0x01 << n;
^	move.l	#1,d3
	asl.w	d2,d3
;		if (chan_bit&channels)
^;			AD7716.n_channels++;
	move.w	d3,d0
	and.w	d4,d0
	beq	.10007
^	add.w	#1,_AD7716+6
;	}
.10007
^.10003
	add.w	#1,d2
.10006
	cmp.w	#4,d2
	bcs	.10005
.10004
;	AD7716.save_channels = channels;
^	move.w	d4,_AD7716+4
;	
;	#ifdef DEBUG
;		//  make sure no bits are set which are being ignored
;		while (n < (8*sizeof(channels)))  {
;			chan_bit = 0x01 << n++;
;			ASSERT ((chan_bit&channels) == 0);
;		}
;	#endif
;	#ifdef SIMULATE_DATA
;		count = 0;
;		for (n = 0;  n < 4;  n++)
;			AD7716.sim_chan[n] = 0;		
;		if (channels&0x01)
;			AD7716.sim_chan[count++] = 0;
;		if (channels&0x02)
;			AD7716.sim_chan[count++] = 0x02;
;		if (channels&0x04)
;			AD7716.sim_chan[count++] = 0x01;
;		if (channels&0x08)
;			AD7716.sim_chan[count++] = 0x03;
;		ASSERT (AD7716.n_channels == count);
;	#endif		
;	AD7716_assert_valid (__LINE__);
^^^^^^^^^^^^^^^^^^^^
^^^;}	
^.13
	movem.l	(sp)+,d2/d3/d4
	rts
.12
;
;
;
;
;
;//  AD7716_get_channels (void)
;//  User callable
;//
;//  Returns the bit pattern representing which channels are being saved
;//
;short AD7716_get_channels (void)  {
# 503
| .14
	xdef	_AD7716_get_channels
_AD7716_get_channels:
;	//  don't mislead user into thinking things are operational if the logger
;	//  isn't open
;	if (AD7716.AD7716_open_flag)
^^^;		return AD7716.save_channels;
	tst.w	_AD7716
	beq	.10008
^	move.w	_AD7716+4,d0
.15
	rts
;	else
.10008
;		return 0;	
^^	move.l	#0,d0
	bra	.15
;}
^.14
;
;
;
;//  AD7716_get_n_channels (void)
;//  User callable
;//
;//  Returns the number of channels activated
;//
;short AD7716_get_n_channels (void)  {
# 519
| .16
	xdef	_AD7716_get_n_channels
_AD7716_get_n_channels:
;	//  don't mislead user into thinking things are operational if the logger
;	//  isn't open
;	if (AD7716.AD7716_open_flag)
^^^;		return AD7716.n_channels;
	tst.w	_AD7716
	beq	.10009
^	move.w	_AD7716+6,d0
.17
	rts
;	else
.10009
;		return -1;	
^^	move.l	#-1,d0
	bra	.17
;}
^.16
;
;
;
;
;
;//  AD7716_start_data (void)
;//  User callable
;//
;//  Sets up the QSPI interface; resets the data buffer; starts the
;//  data from the AD7716 into the local data buffer
;//
;void AD7716_start_data (void)  {
# 538
| .18
	xdef	_AD7716_start_data
_AD7716_start_data:
	movem.l	d2/d3,-(sp)
;	//  make sure the logger has been opened before adjusting the hardware
;	if (AD7716.AD7716_open_flag != 1)
^^;		return;
	cmp.w	#1,_AD7716
	beq	.10010
^.19
	movem.l	(sp)+,d2/d3
	rts
;	//  verify the setup is OK
;	AD7716_assert_valid (__LINE__);
.10010
^^;
;#ifndef SIMULATE_DATA
;	//  make sure interrupt servicing is still off while we reset the interface
;	PConfInp (F,4);
^^^^;			PConfInpF4
	dc.w	$8b8
	dc.w	$4
	dc.w	$fa1f
	dc.w	$8b8
	dc.w	$4
	dc.w	$fa1d
;
;	//  Reset so we know we are at the beginning of a conversion cycle, which
;	//  therefore allows plenty of time for the data xfer when conversion is complete
;	//  This does not reset the programing of the conversion rate.
;	//
;	//  REVIEW - should we setup the interface first?
;	AD7716.icounter = 0;
^^^^^^^	move.l	#0,_AD7716+8
;	AD7716.c0_total = 0;
^	clr.l	_AD7716+38
;	AD7716.c0_n_averaged = 0;
^	clr.w	_AD7716+54
;	AD7716.c1_total = 0;
^	clr.l	_AD7716+42
;	AD7716.c1_n_averaged = 0;
^	clr.w	_AD7716+56
;	AD7716.c2_total = 0;
^	clr.l	_AD7716+46
;	AD7716.c2_n_averaged = 0;
^	clr.w	_AD7716+58
;	AD7716.c3_total = 0;
^	clr.l	_AD7716+50
;	AD7716.c3_n_averaged = 0;
^	clr.w	_AD7716+60
;	
;	if (AD7716.save_channels != 0)  {
^^	tst.w	_AD7716+4
	beq	.10011
;		AD7716_SPI_master_in ();
^	jsr	_AD7716_SPI_master_in
;		AD7716_reset ();
^	jsr	_AD7716_reset
;	
;		//  turn interrupt servicing for the 7716 DRDY line back on
;		#ifdef DEBUG
;		printf ("AD7716_start_data: about to configure input as bus.\n");
;		#endif
;		PConfBus (F,4);
^^^^^^;			PConfBusF4
	dc.w	$8f8
	dc.w	$4
	dc.w	$fa1f
;	}
^;	#ifdef DEBUG
;	printf ("Did it.\n");	
;	#endif
;#endif	
;	//  mark current measured conversion rate as bad	
;	AD7716.measured_rate = -1;
.10011
^^^^^^	move.l	#$00000000,_AD7716+28
	move.l	#$bff00000,_AD7716+24
;
;	//  Init the data necessary for the calculation of the conversion rate
;	//  Wait for data to be saved, then note the time
;	AD7716_data_saved ();
^^^^	jsr	_AD7716_data_saved
;	AD7716.start_time = logger_time_get_time ();
^	lea	_AD7716+16,a0
	move.l	a0,-(sp)
	jsr	_logger_time_get_time
	move.l	d0,a0
	move.l	(sp)+,a1
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
;	AD7716.data_pushed = 0;
^	move.l	#0,_AD7716+12
;	AD7716.rate_calc_threshold = DTIME_RATE_CALCULATION * AD7716.n_channels * AD7716_get_conversion_rate ();	
^	jsr	_AD7716_get_conversion_rate
	move.w	_AD7716+6,d2
	muls.w	#300,d2
	move.l	d1,-(sp)
	move.l	d0,-(sp)
	move.l	d2,d0
	jsr	.Pflt#
	move.l	d1,d3
	move.l	d0,d2
	move.l	(sp)+,d0
	move.l	(sp)+,d1
	jsr	.Pmul#
	jsr	.Pfix#
	move.l	d0,_AD7716+32
;}	
^	bra	.19
.18
;	
;
;
;//  AD7716_pause_data (void)
;//  User callable
;//
;//  Used to temporarily suspend processing of the interrupts which collect
;//  data from the AD7716; this does not actually stop the 7716 from
;//  converting, but merely pauses our collection of data from it.  If
;//  the AD7716_resume () routine is called quickly enough, then no data
;//  will be lost
;//
;void AD7716_pause_data (void)  {
# 600
| .20
	xdef	_AD7716_pause_data
_AD7716_pause_data:
;	if (AD7716.AD7716_open_flag != 1)
^;		return;
	cmp.w	#1,_AD7716
	beq	.10012
^.21
	rts
;		
;	//  REVIEW
;	//  suppose the logger has been opened, but the data flow hasn't been
;	//  started.  Does this respond correctly?
;
;	//  wait for an interrupt to complete processing
;	AD7716_interrupt_serviced ();
.10012
^^^^^^^	jsr	_AD7716_interrupt_serviced
;	
;	//  by configuring line 4 (AD7716's DRDY line) as an input instead of
;	//  a bus line, we prevent the 7716's interrupts from being serviced
;	//  and essentially pause the AD.  We call this a pause instead of a
;	//  stop because we have not reset the data buffer structures, so when
;	//  we restart the A/D, the new data is just added to the old
;	PConfInp (F, 4);
^^^^^^^;			PConfInpF4
	dc.w	$8b8
	dc.w	$4
	dc.w	$fa1f
	dc.w	$8b8
	dc.w	$4
	dc.w	$fa1d
;}
^	bra	.21
.20
;
;
;
;
;//  AD7716_resume_data (void)
;//  User callable
;//
;//  Restores the interrupts which process data from the 7716; resets the
;//  control pins that interact with it; resets the QSPI interface; begins
;//  data collection again at the point where it was paused.  Does NOT reset
;//  any of the data queues; does NOT check to verify that no data was lost
;//
;void AD7716_resume_data (void)  {
# 630
| .22
	xdef	_AD7716_resume_data
_AD7716_resume_data:
;	if (AD7716.AD7716_open_flag != 1)
^;		return;
	cmp.w	#1,_AD7716
	beq	.10013
^.23
	rts
;	#ifdef SIMULATE_DATA
;		//  never access hardware if simulating data
;		return;
;	#endif	    
;    
;	//  need to reinit the microcontroller's SPI interface and re-install
;	//  the interrupt vectors before we can re-enable the interrupts.
;	AD7716_SPI_interface_init ();
.10013
^^^^^^^^	jsr	_AD7716_SPI_interface_init
;	PConfBus (F, 4);
^;			PConfBusF4
	dc.w	$8f8
	dc.w	$4
	dc.w	$fa1f
;}
^	bra	.23
.22
;
;
;
;//  AD7716_stop_data ()
;//  User callable
;//
;//	Stops the data collection from the A/D converter and empties
;//  all data from the buffers
;//
;void AD7716_stop_data ()  {
# 652
| .24
	xdef	_AD7716_stop_data
_AD7716_stop_data:
;	//  don't do anything if we aren't open
;	if (AD7716.AD7716_open_flag != 1)
^^;		return;
	cmp.w	#1,_AD7716
	beq	.10014
^.25
	rts
;
;	//  Disable interrupt processing by resetting the interrupt line
;	//  from its bus function to a normal input function
;	PConfInp (F, 4);
.10014
^^^^;			PConfInpF4
	dc.w	$8b8
	dc.w	$4
	dc.w	$fa1f
	dc.w	$8b8
	dc.w	$4
	dc.w	$fa1d
;	
;	//  stop_data is used when we don't intend to re-start sequential data,
;	//  so we should throw out whatever we have
;	AD7716_SPI_buffer_empty ();
^^^^	jsr	_AD7716_SPI_buffer_empty
;}
^	bra	.25
.24
;
;
;		
;//  AD7716_set_conversion_rate (float f)
;//  User callable
;//
;//	Sets the conversion rate.  Currently allowed rates are only
;//	129 or 257 Hz; the others could easily be activated by adding
;//  a little code here.  If data is already flowing, then it is
;//  stopped and the buffers emptied.
;//
;//  Note that it is OK to call this routine when the AD7716 is not
;//  open.  This is a convenient thing to allow so that we can use
;//  the frequency checking in this routine to verify that a frequency
;//  which a user has requested is valid.
;//
;//  Arguments: the desired conversion rate, which must be within 1% of
;//		the exact conversion rate for this routine to work.  Illegal
;//		values cause the routine to do nothing and return negative to
;//		indicate error
;//	Returns: the exact conversion rate choosen assuming the XTAL_FREQ
;//		is correct; negative on failure
;//	Failure: if the requested rate is not within 1% of a known rate
;//
;double AD7716_set_conversion_rate (float rate)  {
# 689
| .26
	xdef	_AD7716_set_conversion_rate
_AD7716_set_conversion_rate:
	movem.l	d2/d3/d4/d5,-(sp)
;	float base_rate;
;	float rate_num;
;	
;	//  we can't reset the conversion rate while taking data.  Stop
;	//  and empty the buffers.  This will do nothing if the 7716 is
;	//  closed.  Note that the external user must restart the data
;	//  if appropriate!
;	AD7716_stop_data ();
~ base_rate d5 "f"
~ rate_num d4 "f"
~~ rate 8 "f"
^^^^^^^^	jsr	_AD7716_stop_data
;	
;	//  roughly 128.6 Hz for a 7.3728 Hz Xtal
;	base_rate = ((XTAL_FREQ/14.0)/(16*256.0));
^^^	move.l	#$43009249,d5
;	
;	rate_num = rate/base_rate;
^^	move.l	20(sp),d0
	move.l	d5,d1
	jsr	.Fdiv#
	move.l	d0,d4
;	if ((rate_num > 0.99) &&
^;	    (rate_num < 1.01)   )  {
	move.l	d4,d0
	jsr	.ftod#
	move.l	#$7ae147ae,d3
	move.l	#$3fefae14,d2
	jsr	.Pcmp#
	ble	.10015
	move.l	d4,d0
	jsr	.ftod#
	move.l	#$c28f5c29,d3
	move.l	#$3ff028f5,d2
	jsr	.Pcmp#
	bge	.10015
^;	    //  nominal rate is 128.5 Hz
;	    AD7716.convert_rate = AD7716_CONVERT_129HZ;
^^	move.w	#1,_AD7716+2
;	    AD7716_program_hardware ();
^	jsr	_AD7716_program_hardware
;		return base_rate;
^	move.l	d5,d0
	jsr	.ftod#
.27
	movem.l	(sp)+,d2/d3/d4/d5
	rts
;	}
^;	
;	if ((rate_num > 1.98) &&
.10015
^^;		(rate_num < 2.02)   )  {
	move.l	d4,d0
	jsr	.ftod#
	move.l	#$7ae147ae,d3
	move.l	#$3fffae14,d2
	jsr	.Pcmp#
	ble	.10016
	move.l	d4,d0
	jsr	.ftod#
	move.l	#$c28f5c29,d3
	move.l	#$400028f5,d2
	jsr	.Pcmp#
	bge	.10016
^;		//  nominal rate is 257 Hz
;	    AD7716.convert_rate = AD7716_CONVERT_257HZ;
^^	move.w	#2,_AD7716+2
;	    AD7716_program_hardware ();
^	jsr	_AD7716_program_hardware
;		return 2.0F*base_rate;
^	move.l	d5,d0
	move.l	#$40000000,d1
	jsr	.Fmul#
	jsr	.ftod#
	bra	.27
;	}
^;
;	AD7716_assert_valid (__LINE__);
.10016
^^;	return -1;
^	move.l	#$00000000,d1
	move.l	#$bff00000,d0
	bra	.27
;}
^.26
;
;
;
;
;
;//  AD7716_set_averaging (short n_to_average)
;//  User callable
;//
;//	Sets the number of samples which are averaged together to produce
;//  a single sample for the end user.  Currently allowed numbers are
;//  1 (no averaging) to 4; others could easily be added.  If data is
;//  already flowing, then it is stopped and the buffers emptied.
;//
;//  Note that it is OK to call this routine when the AD7716 is not
;//  open.  This is a convenient thing to allow so that we can use
;//  the error checking in this routine to verify that a number
;//  which a user has requested is valid.
;//
;//  Arguments: the desired number of samples to average together.
;//	Returns: 0 if OK; negative on failure
;//	Failure: if the requested number of samples is not between 1
;//			 and 4
;//
;short AD7716_set_averaging (short n_to_average)  {
# 745
| .28
	xdef	_AD7716_set_averaging
_AD7716_set_averaging:
	movem.l	d2,-(sp)
	move.w	8(sp),d2
;	if ((n_to_average < 1) ||
~~ n_to_average d2 "i"
^;		(n_to_average > 4)   )
;		return -1;
	cmp.w	#1,d2
	blt	.29
	cmp.w	#4,d2
	ble	.10017
.29
^^	move.l	#-1,d0
.30
	movem.l	(sp)+,d2
	rts
;		
;	//  we shouldn't reset the averaging while taking data.  Stop
;	//  and empty the buffers.  This will do nothing if the 7716 is
;	//  closed.  Note that the external user must restart the data
;	//  if appropriate!
;	AD7716_stop_data ();
.10017
^^^^^^	jsr	_AD7716_stop_data
;	AD7716.n_to_average = n_to_average;
^	move.w	d2,_AD7716+36
;	
;	//  Be sure to reset the measured rate since we changed the
;	//  averaging.  The code stop using any previously calculated
;	//  rate and will recalculate a new rate next time the data
;	//  is started.
;	AD7716.measured_rate = -1;
^^^^^^	move.l	#$00000000,_AD7716+28
	move.l	#$bff00000,_AD7716+24
;	return 0;
^	move.l	#0,d0
	bra	.30
;}		
^.28
;
;
;
;
;
;//  AD7716_get_conversion_rate (void)
;//  User callable
;//
;//	Returns the current conversion rate in conversions/second.
;//	NOTE: This assumes a 7.3728 MHz xtal.  There is no convenient
;//  way for the software to verify this.  We could fire up the
;//  converter and time the incoming interrupts, but this is probably
;//  an unnecessary pain in the ass.
;//
;double AD7716_get_conversion_rate (void)  {
# 778
| .31
	xdef	_AD7716_get_conversion_rate
_AD7716_get_conversion_rate:
	link	a6,#.32
	movem.l	d2/d3,-(sp)
;	double base_rate;
;	double rate;
;	
;	if (AD7716.AD7716_open_flag	== 0)
~ base_rate -8 "d"
~ rate -16 "d"
^^^^;		return -1;
	tst.w	_AD7716
	bne	.10018
^	move.l	#$00000000,d1
	move.l	#$bff00000,d0
.33
	movem.l	(sp)+,d2/d3
	unlk	a6
	rts
;	
;	//  if we have accumulated enough interrupts to have accurately
;	//  measured the conversion rate, then return the measured rate.
;	if (AD7716.measured_rate > 0)  {
.10018
^^^^	move.l	_AD7716+28,d1
	move.l	_AD7716+24,d0
	jsr	.Ptst#
	ble	.10019
;		return AD7716.measured_rate;
^	move.l	_AD7716+28,d1
	move.l	_AD7716+24,d0
	bra	.33
;//		printf ("measured rate is %.9lf\n", AD7716.measured_rate);
;	}	
^^;//	printf ("Using calculated rate.\n");
;	//  If we don't yet have enough interrupts, then calculate an approximate
;	//  conversion rate based on the target value of the crystal which controls
;	//  the rate.
;	//  The base rate is roughly 128.6 Hz for a 7.3728 Hz Xtal
;	base_rate = ((XTAL_FREQ/14.0)/(16*256.0));
.10019
^^^^^^	move.l	#$24924925,-4(a6)
	move.l	#$40601249,-8(a6)
;	switch (AD7716.convert_rate)  {
^	move.w	_AD7716+2,d0
	bra	.10020
;		default:
^.10022
;			//  shouldn't ever get here; abort during debug mode, default
;			//  to 129 Hz in actual use
;			ASSERT (0);
^^^;			AD7716.convert_rate = AD7716_CONVERT_129HZ; 
^	move.w	#1,_AD7716+2
;			
;		case AD7716_CONVERT_129HZ:
^^.10023
;			rate = base_rate;
^	move.l	-4(a6),-12(a6)
	move.l	-8(a6),-16(a6)
;			break;
^	bra	.10021
;			
;		case AD7716_CONVERT_257HZ:
^^.10024
;			rate =  2.0*base_rate;
^	move.l	-4(a6),d1
	move.l	-8(a6),d0
	move.l	#$00000000,d3
	move.l	#$40000000,d2
	jsr	.Pmul#
	move.l	d1,-12(a6)
	move.l	d0,-16(a6)
;			break;
^	bra	.10021
;	}
^.10020
	sub.w	#1,d0
	beq	.10023
	sub.w	#1,d0
	beq	.10024
	bra	.10022
.10021
;	
;	//  If we are averaging, then divide the 7716 data rate by the number of
;	//  samples averaged to get the actual rate.
;	rate /= AD7716.n_to_average;
^^^^	move.l	-12(a6),d1
	move.l	-16(a6),d0
	move.w	_AD7716+36,a0
	move.l	d1,-(sp)
	move.l	d0,-(sp)
	move.l	a0,d0
	jsr	.Pflt#
	move.l	d1,d3
	move.l	d0,d2
	move.l	(sp)+,d0
	move.l	(sp)+,d1
	jsr	.Pdiv#
	move.l	d1,-12(a6)
	move.l	d0,-16(a6)
;//	printf ("calculated rate is %.9lf\n", rate);	
;	return rate;
^^	move.l	-12(a6),d1
	move.l	-16(a6),d0
	bra	.33
;}
^.31
.32	equ	-16
;
;
;
;
;
;//	AD7716_program_hardware (void)
;//  Internal use only
;//  Does not do anything if the 7716 is closed
;//
;//	Reads the internal variable to determine the conversion rate and programs
;//  the 7716 appropriately
;//
;void AD7716_program_hardware (void)  {
# 831
| .34
	xdef	_AD7716_program_hardware
_AD7716_program_hardware:
;	if (AD7716.AD7716_open_flag == 0)
^;		return;
	tst.w	_AD7716
	bne	.10025
^.35
	rts
;
;//	printf ("programming hardware\n");
;	switch (AD7716.convert_rate)  {
.10025
^^^	move.w	_AD7716+2,d0
	bra	.10026
;		default:
^.10028
;			//  shouldn't ever get here; abort during debug mode, default
;			//  to 129 Hz in actual use
;			ASSERT (0);
^^^;			AD7716.convert_rate = AD7716_CONVERT_129HZ; 
^	move.w	#1,_AD7716+2
;			
;		case AD7716_CONVERT_129HZ:
^^.10029
;			//  see the 7716 data sheet for meaning of numbers
;			AD7716_command (0x00, 0xB1);
^^	move.w	#177,-(sp)
	clr.w	-(sp)
	jsr	_AD7716_command
;			return;
^	add.w	#4,sp
	bra	.35
;			
;		case AD7716_CONVERT_257HZ:
^^.10030
;			AD7716_command (0x01, 0xD1);
^	move.w	#209,-(sp)
	move.w	#1,-(sp)
	jsr	_AD7716_command
;			return;
^	add.w	#4,sp
	bra	.35
;	}
^.10026
	sub.w	#1,d0
	beq	.10029
	sub.w	#1,d0
	beq	.10030
	bra	.10028
.10027
;	ASSERT (0);
^;}	
^	bra	.35
.34
;
;
;
;
;
;//  AD7716_SPI_interface_init (void)
;//  Not for external use.
;//
;//  Turns off the MAX186, which shares the SPI interface with the AD7716.
;//  Inits the SPI ports which we use to talk to the AD7716; installs the
;//  interrupt handlers for the SPI interrupt (which occurs when an xfer
;//  completes) and the AD7716 interrupt (which occurs when the DataReady
;//  line of the 7716 is active).
;//
;//  Arguments, failures: none
;//
;void AD7716_SPI_interface_init (void)
;	{
# 870
^| .36
	xdef	_AD7716_SPI_interface_init
_AD7716_SPI_interface_init:
;	//  frames for the SPI interrupt handler and the IRQ4 interrupt handler
;	static ExcCFrame efspi;
	bss	.10031,20
;	static ExcCFrame ef4;
	bss	.10032,20
;	
;	//  This is an internal routine, and it is not called unless we have
;	//  been opened already.
;//	ASSERT (AD7716.AD7716_open_flag == 1);
;	
;	//  Shut off MAX186 ADC; Also need to keep PCS3 line (to MAX186) HIGH
;	//  to Tri-state its DOUT and DIN lines, which are connected to the QSPI
;//	Max186PowerDown();
;	
;	// install QSPI interrupt handler
;	InstallHandler(AD7716_SPI_rupt_handler, QSPI_INT_VECTOR, &efspi);
~ ''
~ 1 4 20
~ preamble 0 "[4I"
~ jump 8 "I"
~ target 10 "L"
~ postamble 14 "[3I"
~ efspi .10031 ":" 1
~ ef4 .10032 ":" 1
^^^^^^^^^^^^^^	pea	.10031
	move.w	#83,-(sp)
	pea	_AD7716_SPI_rupt_handler
	jsr	_InstallHandler
;
;	// install AD7716 Data Ready interrupt handler
;	InstallHandler(AD7716_rupt_handler, Level_4_Interrupt, &ef4);
^^^	pea	.10032
	move.w	#28,-(sp)
	pea	_AD7716_rupt_handler
	jsr	_InstallHandler
;
;	//  make sure we're set up to receive data
;	AD7716_SPI_master_in ();
^^^	jsr	_AD7716_SPI_master_in
;
;	// SETUP QSPI CONTROL REGISTERS 0,1, AND 3
;	*SPCR0 =        AD7716_BAUD             //  4 = 2 MHz;  baud rate (2 is max)
^^^;			|       (8 << 10)               //  bits per transfer (0 = 16)
;			|       M_MSTR  &       SET     //  1 = Master, 0 = Slave
;			|       M_WOMQ  &       CLR     //  1 = open drain, 0 = cmos
;			|       M_CPOL  &       CLR     //  1 = inactive SCK high
;			|       M_CPHA  &       SET     //  1 = change leading edge, capture falling
;	;
	move.w	#41220,-1000
;
;	*SPCR3 =        M_LOOPQ &       CLR     //  QSPI loop mode, 1 = on
^^^^^^^^;			|       M_HMIE  &       CLR     //  HALTA & MODF interrupt enable
;			|       M_HALT  &       CLR     //  Halt
;	;
	move.b	#0,-994
;
;	*SPCR1 =        AD7716_DTL              //  DTL delay after transfer
^^^^^;			|       (AD7716_DSCKL << 8)     //  DSCKL delay before SCK
;			|       M_SPE   &       CLR     //  QSPI enable = 1, 0 = I/O
;	;
	move.w	#257,-998
;
;
;
;	//  Why are we running a command through here?
;	//
;	//	SET UP SPCR2 FOR ONE COMMAND
;	*SPCR2 =        0                       //  NEWQP
^^^^^^^^^^;			|       1 << 8                  //  ENDQP
;			|       M_SPIFIE&       SET     //  SPI finished rupt enable = 1
;			|       M_WREN  &       CLR     //  wraparound enable = 1
;			|       M_WRTO  &       CLR     //  wrap to
;	;
	move.w	#33024,-996
;	
;
;	SPIXMT[0]  = 0x00;      // DUMMY TRANSMISSION SETUP PCS'S
^^^^^^^^	move.w	#0,-736
;	
;	//  COMMANDS ARE 0xFN, WHERE N IS PCS VALUES
;	SPICMD[0] =     11                      //  SET PCS3 LOW, TFS, RFS HIGH, RESET LOW
^^^;			|       M_CONT  &       SET     //  1=keep CS active
;			|       M_BITSE &       SET     //  0=8 bits, 1=use SPCR0
;			|       M_DT    &       SET     //  0=no delay after, 1=use SPCR1
;			|       M_DSCK  &       SET     //  0=1/2SCK, 1=use SPCR1
;			;
	move.b	#251,-704
;	
;	 SPICMD[1] = 0xFB;
^^^^^^^	move.b	#251,-703
;	_SPSR->SPIF = 0;                        //  clear any old results (intrpt flag)
^	and.w	#-129,-994
;	AD7716.SPI_finished = 0;				//  reset the SPI complete flag
^	clr.w	_AD7716+62
;	_SPCR1->SPE = 1;                        //  start QSPI
^	or.w	#32768,-998
;
;	//  This Stop call halts the clock until the SPI xmission completes
;//	Stop (0x2000);
;	while (AD7716.SPI_finished == 0)
^^^^	lea	20(sp),sp
.10033
	tst.w	_AD7716+62
	bne	.10034
;		{;}
^	bra	.10033
.10034
;	return;
^.37
	rts
;}
^.36
;
;
;
;
;
;//  AD7716_reset (void)
;//	User callable
;//
;//  Toggles the AD7716 reset line to synchronize channels if we have more than
;//  one converter.  Also insures that we will have a known amount of time to
;//  grab the data when the DataReady interrupt occurs.
;//
;void AD7716_reset (void)
;	{
# 958
^| .38
	xdef	_AD7716_reset
_AD7716_reset:
	movem.l	d2,-(sp)
;	int n;
;	
;	//  don't do anything unless we are open
;	if (AD7716.AD7716_open_flag != 1)
~ n d2 "i"
^^^^;		return;
	cmp.w	#1,_AD7716
	beq	.10035
^.39
	movem.l	(sp)+,d2
	rts
;		
;	//  make sure the reset line is configured as an output
;	PConfOutp (E, 1);		//  this should already be true
.10035
^^^;			PConfOutpE1
	dc.w	$8b8
	dc.w	$1
	dc.w	$fa17
	dc.w	$8f8
	dc.w	$1
	dc.w	$fa15
;	
;	//  The 7716 data sheet specs that RESET must be held high for
;	//  at least four CLKIN cycles, where CLKIN comes from the XTAL
;	//  on the 7716, which is a 7.3728 MHz XTAL.  Therefore it must
;	//  be high for at least 0.54 uSec.  For a loop count of 8 and
;	//  a TT8 clock frequency of 16 MHz, the measured pulse width
;	//  was approximately 12 usec.  A slower clock will only increase
;	//  this further.
;	PSet (E, 1);
^^^^^^^^^;			PSetE1
	dc.w	$8f8
	dc.w	$1
	dc.w	$fa11
;	for (n = 0;  n < 8;  n++)
^	move.l	#0,d2
.10038
;		{;}
^.10036
	add.w	#1,d2
	cmp.w	#8,d2
	blt	.10038
.10037
;
;	//  Now make sure the buffer is empty
;	AD7716_SPI_buffer_empty ();
^^^	jsr	_AD7716_SPI_buffer_empty
;
;	//  And de-assert reset
;	PClear (E, 1);
^^^;			PClearE1
	dc.w	$8b8
	dc.w	$1
	dc.w	$fa11
;
;	AD7716_assert_valid (__LINE__);
^^;	return;
^	bra	.39
;}
^.38
;
;
;
;//		QPDR-5 = PCS2 (connected to AD7716 RESET)
;//		QPDR-4 = PCS1 (connected to AD7716 TFS)
;
;
;//  AD7716_command
;//  Internal use only
;//
;//  Transmits a two byte command to the 7716.  See the data sheet for
;//  the AD7716 for the details on the meaning of these bytes.
;//
;//  The 7716 uses one line for both xmit and rcv, and distinguishes the
;//  two cases by whether TFS or RFS is pulled low before the transfer.
;//  This doesn't work well with the SPI, because the xmit and rcv pins
;//  are seperate, and must remain seperate in order to work with the
;//  TT8's on board A/D.  So we use the SPI to rcv bytes from the 7716,
;//  and for the few times we need to xmit to it, we disable the SPI, set
;//  the SPI lines as normal outputs, and simulate an SPI in software.
;//  This is slow, but we transmit so seldom that it just doesn't matter.
;//
;//  Arguments: The least and most significant bytes of the command to
;//		be transmitted.
;//
;//  SPI assignments:
;//		QPDR-7 = TxD (used by SCI)
;//		QPDR-6 = PCS3 (used by TT8's on-board MAXIM A/D converter)
;//		QPDR-5 = PCS2 (connected to a BB1211 CS)
;//		QPDR-4 = PCS1 (connected to a BB1211 CS)
;//		QPDR-3 = PCS0 (connected to AD7716 RFS)
;//		QPDR-2 = SCK (SPI clock)
;//		QPDR-1 = MOSI (master out, slave in)
;//		QPDR-0 = MISO (master in, slave out)
;//
;//		Port E0 = AD7716 TFS
;//  	Port E1 = ADC Reset
;//
;//  The masks are defined in the TT8 include file QSM332.h
;//
;void AD7716_command (short LSByte, short MSByte)
;	{
# 1029
^| .40
	xdef	_AD7716_command
_AD7716_command:
;	ASSERT (AD7716.AD7716_open_flag == 1);
~~ LSByte 8 "i"
~~ MSByte 10 "i"
^;	//  This routine should not be called unless the interrupt servicing routine
;	//  is turned off
;
;//	if (_SPCR1->SPE)
;//		printf ("wait for stop\n");
;	
;	//  set up for transmission of data over the SPI to the 7716
;	AD7716_SPI_master_out ();
^^^^^^^^	jsr	_AD7716_SPI_master_out
;	
;	//  we're all set up.  Now loop through setting the data pins and toggling
;	//  the clock line to xfer the data
;	AD7716_software_SPI_write (LSByte);
^^^^	move.w	4(sp),-(sp)
	jsr	_AD7716_software_SPI_write
;	AD7716_software_SPI_write (MSByte);
^	move.w	8(sp),-(sp)
	jsr	_AD7716_software_SPI_write
;	
;	//  be sure to reset the SPI interface to its default master_in state
;	AD7716_SPI_master_in ();
^^^	jsr	_AD7716_SPI_master_in
;	return;
^	add.w	#4,sp
.41
	rts
;}
^.40
;
;
;
;//  Series of defines to allow convenient setting of SPI bits
;#define AD7716_set_TFS_low      (PClear (E, 0))
;#define AD7716_set_TFS_high		(PSet (E, 0))
;#define AD7716_set_SCK_low		(_QPDR->SCK=0)
;#define AD7716_set_SCK_high		(_QPDR->SCK=1)
;#define AD7716_set_MISO_low		(_QPDR->MISO=0)
;#define AD7716_set_MISO_high	(_QPDR->MISO=1)
;
;//  AD7716_software_SPI_write (int byte)
;//
;//	Uses software control of the SPI interface to xmit a byte
;//  to the 7716 using the lines normally assigned to recieve
;//  data.  This is necessary so we can conveniently communicate
;//  with the 7716, which uses a single line for both transmit
;//  and receive.
;//
;//  IMPORTANT NOTE: this routine changes the DDR and PAR for the
;//  SPI.  The user must disable the 7716 interrupt servicing before
;//  call this routine, and should call SPI_master_in() before attempting
;//  to read data from the 7716 again.
;//
;void AD7716_software_SPI_write (int byte)  {
# 1074
| .42
	xdef	_AD7716_software_SPI_write
_AD7716_software_SPI_write:
	movem.l	d2,-(sp)
;	int n;
;	
;	//  start with the clock low
;	AD7716_set_SCK_low;
~ n d2 "i"
~~ byte 8 "i"
^^^^	and.w	#-5,-1004
;	
;	//  then pull TFS low
;	AD7716_set_TFS_low;
^^^;			PClearE0
	dc.w	$8b8
	dc.w	$0
	dc.w	$fa11
;	
;	//  Now loop through setting the data bit and toggling the clock
;	//  Note that we xmit the high order bits first
;	for (n = 7;  n >= 0;  n--)  {
^^^^	move.l	#7,d2
.10041
;		//  to send a bit, first set the clock high
;		AD7716_set_SCK_high;
^^	or.w	#4,-1004
;
;		//  then set the data bit appropriately
;		if (byte & (0x01 << n))
^^^;			AD7716_set_MISO_high;
	move.l	#1,d0
	asl.w	d2,d0
	and.w	8(sp),d0
	beq	.10042
^	or.w	#1,-1004
;		else	
	bra	.10043
.10042
;			AD7716_set_MISO_low;
^^	and.w	#-2,-1004
.10043
;	
;		//  finally, drop the clock low so the AD7716 will latch the data bit
;		AD7716_set_SCK_low;
^^^	and.w	#-5,-1004
;	}
^.10039
	sub.w	#1,d2
	tst.w	d2
	bge	.10041
.10040
;	//  after all bits are sent, return TFS to its high state
;	AD7716_set_TFS_high;
^^;			PSetE0
	dc.w	$8f8
	dc.w	$0
	dc.w	$fa11
;
;	//  and leave the MISO bit high too, though I don't think it matters
;	AD7716_set_MISO_high;
^^^	or.w	#1,-1004
;	//  return clock to its normal high state
;	AD7716_set_SCK_high;
^^	or.w	#4,-1004
;
;	return;
^^.43
	movem.l	(sp)+,d2
	rts
;}
^.42
;		
;		
;
;
;//  AD7716_SPI_read_data
;//  Internal use only
;//
;//  Reads 16 bytes from the AD7716 over the SPI interface
;//      This is accomplished by establishing a cue of 8 x 16 bit
;//      commands. The data sent by the AD7716 goes into receive RAM.
;//      SPIRCV[0,1] have data for channel 1...SPIRCV[6,7] have data
;//      for channel 4. Data is the most significant 22 bits, in
;//      two's-complement form.
;//      
;void AD7716_SPI_read_data (void)  {
# 1122
| .44
	xdef	_AD7716_SPI_read_data
_AD7716_SPI_read_data:
;	ASSERT (AD7716.AD7716_open_flag == 1);
^;
;	/*	SETUP 16 BIT TRANSFERS to READ AD7716. 8 TRANSFERS ARE NEEDED TO FETCH DATA.        
;		A FINAL TRANSFER IS NEEDED TO RESET DRDY
;	*/ 
;	*SPCR0 =        AD7716_BAUD             // 4 = 2 MHz; baud rate (2 is max)
^^^^^;			|       (0 << 10)               // bits per transfer (0 = 16)
;			|       M_MSTR  &       SET     // 1 = Master, 0 = Slave
;			|       M_WOMQ  &       CLR     // 1 = open drain, 0 = cmos
;			|       M_CPOL  &       CLR     // 1 = inactive SCK high
;			|       M_CPHA  &       SET     // 1 = chg lding edge, capt folng
;	 ;
	move.w	#33028,-1000
;
;
;	/*	SET UP SPCR2 FOR NINE COMMANDS  */        
;	*SPCR2 =        0                       // NEWQP
^^^^^^^^^^;			|       8 << 8                  // ENDQP
;			|       M_SPIFIE&       SET     // SPI finished rupt enable = 1
;			|       M_WREN  &       CLR     // wraparound enable = 1
;			|       M_WRTO  &       CLR     // wrap to
;	;
	move.w	#34816,-996
;	SPIXMT[0]=0x00;        
^^^^^^	move.w	#0,-736
;	SPIXMT[1]=0x01;
^	move.w	#1,-734
;	SPIXMT[2]=0x02;
^	move.w	#2,-732
;	SPIXMT[3]=0x03;
^	move.w	#3,-730
;	SPIXMT[4]=0x04;        
^	move.w	#4,-728
;	SPIXMT[5]=0x05;
^	move.w	#5,-726
;	SPIXMT[6]=0x06;
^	move.w	#6,-724
;	SPIXMT[7]=0x07;
^	move.w	#7,-722
;	SPIXMT[8]=0x08;        
^	move.w	#8,-720
;	SPIXMT[9]=0x09;
^	move.w	#9,-718
;	SPIXMT[10]=0x0A;
^	move.w	#10,-716
;	SPIXMT[11]=0x0B;
^	move.w	#11,-714
;	SPIXMT[12]=0x0C;        
^	move.w	#12,-712
;	SPIXMT[13]=0x0D;
^	move.w	#13,-710
;	SPIXMT[14]=0x0E;
^	move.w	#14,-708
;	SPIXMT[15]=0x0F;
^	move.w	#15,-706
;
;	
;    /*	COMMANDS ARE 0xFN, WHERE N IS PCS VALUES  */
;	SPICMD[0] =     0xE                		// PCS0 = RFS low, others high
^^^^;			|       M_CONT  &       SET     // 1=keep CS active
;			|       M_BITSE &       SET     // 0=8 bits, 1=use SPCR0
;			|       M_DT    &       SET     // 0=no delay after, 1=use SPCR1
;			|       M_DSCK  &       SET     // 0=1/2SCK, 1=use SPCR1
;			;
	move.b	#254,-704
;	
;	SPICMD[1] =0xFE;
^^^^^^^	move.b	#254,-703
;	SPICMD[2] =0xFE;
^	move.b	#254,-702
;	SPICMD[3] =0xFE;
^	move.b	#254,-701
;	SPICMD[4] =0xFE;
^	move.b	#254,-700
;	SPICMD[5] =0xFE;
^	move.b	#254,-699
;	SPICMD[6] =0xFE;
^	move.b	#254,-698
;	SPICMD[7] =0xFE;
^	move.b	#254,-697
;	SPICMD[8] =0xFE;
^	move.b	#254,-696
;	
;	
;	_SPSR->SPIF = 0;                        // clear any old results (intrpt flag)
^^^	and.w	#-129,-994
;	AD7716.SPI_finished = 0;				//  reset the SPI complete flag
^	clr.w	_AD7716+62
;	_SPCR1->SPE = 1;                        // START QSPI
^	or.w	#32768,-998
;}
^.45
	rts
.44
;
;
;
;
;//  AD7716_SPI_master_out
;//  Internal use only
;//
;//  Sets up the QSPI pins for output as an SPI master using
;//  the software routines, which drive the data out over the
;//  MISO line.
;//
;void AD7716_SPI_master_out (void)  {
# 1195
| .46
	xdef	_AD7716_SPI_master_out
_AD7716_SPI_master_out:
;	ASSERT (AD7716.AD7716_open_flag == 1);
^;	
;	//  Previously set values:
;	//		Port E0 = AD7716 TFS, already set high
;	//		Port E1 = ADC Reset, already set low
;
;	//  Set the data register, which controls the output values when
;	//  the SPI is not active
;	//		QPDR-7 = TxD (used by SCI)
;	//		QPDR-6 = PCS3 (used by TT8's on-board MAXIM A/D converter, active low, idle high)
;	//		QPDR-5 = PCS2 (connected to a BB1211 CS line, active low, idle high)
;	//		QPDR-4 = PCS1 (connected to a BB1211 CS line, active low, idle high)
;	//		QPDR-3 = PCS0 (connected to AD7716 RFS, active low)
;	//		QPDR-2 = SCK (SPI clock) (set to idle low)
;	//		QPDR-1 = MOSI (master out, slave in) (idle low)
;	//		QPDR-0 = MISO (master in, slave out) (idle low)
;	*QPDR = 0x78;		//  0111 1000
^^^^^^^^^^^^^^^^	move.b	#120,-1003
;
;	//  No need to set up the PAR, which controls which pins the SPI takes over, cause
;	//  the output of data is done in software, not hardware
;	//  Now set up the date direction register
;	//	  All PCS lines outputs
;	//	  SCK and MISO outputs
;	//    MOSI input
;	//
;	*QDDR = 0x7D;       //  0111 1101
^^^^^^^^^	move.b	#125,-1001
;}
^.47
	rts
.46
;
;
;
;
;//  AD7716_SPI_master_in (void);
;//  Internal use only
;//  
;//  Sets up the QSPI for input as an SPI master
;//
;void AD7716_SPI_master_in (void)  {
# 1232
| .48
	xdef	_AD7716_SPI_master_in
_AD7716_SPI_master_in:
;//	ASSERT (AD7716.AD7716_open_flag == 1);
;
;	//  Previously set values:
;	//		Port E0 = AD7716 TFS, already set high
;	//		Port E1 = ADC Reset, already set low
;
;	//  If the SPI is not enabled, which is most of the time, then the state
;	//  of the SPI pins (input/output and value) is defined by the values in
;	//  the registers QDDR (the data direction register) and QPDR (the data
;	//	register).  Which pins are assigned to the SPI when it is active is
;	//	defined by the value in the QPAR (pin assignment register).
;	//
;	//  Set the QDDR first so that the pin values are corrected when we start
;	//  driving the pins.
;	//
;	//  Setup the port QS data register to define PCS states between QSPI reads
;	//		QPDR-7 = TxD (used by SCI)
;	//		QPDR-6 = PCS3 (used by TT8's on-board MAXIM A/D converter, active low)
;	//		QPDR-5 = PCS2 (connected to BB1211 CS, active low, idle high)
;	//		QPDR-4 = PCS1 (connected to BB1211 CS, active low, idle high)
;	//		QPDR-3 = PCS0 (connected to AD7716 RFS, active low)
;	//		QPDR-2 = SCK (SPI clock) (set to idle low)
;	//		QPDR-1 = MOSI (master out, slave in) (idle low)
;	//		QPDR-0 = MISO (master in, slave out) (idle low)
;	*QPDR = 0x78;		//  0111 1000
^^^^^^^^^^^^^^^^^^^^
^^^^^	move.b	#120,-1003
;
;	//  Setup the pin assignment register, which determinew which pins the
;	//  SPI takes over when it is enabled.
;	//		Assign all PCS lines, MISO and SCK; note that the hardware is
;	//			not capable of unassigning SCK when the QSPI is active
;	//			(SPE bit set)
;	//		MOSI is not assigned because we don't want to write data out to the
;	//		AD7716 when reading data in the master in mode
;	*QPAR = 0x7B;		//	0111 1101
^^^^^^^^^	move.b	#123,-1002
;	
;	//  Now set up the date direction register
;	//	  All PCS lines outputs
;	//	  SCK output
;	//    MISO and MOSI are both inputs
;	//  We don't drive the MOSI line cause no one is listening anyway
;	*QDDR = 0x7C;		//  0111 1100
^^^^^^^	move.b	#124,-1001
;}
^.49
	rts
.48
;
;
;
;
;//  AD7716_SPI_rupt_handler (void)  {
;//  Internal use only
;//
;//  Interrupt handler for SPI
;//
;void AD7716_SPI_rupt_handler (void)  {
# 1284
| .50
	xdef	_AD7716_SPI_rupt_handler
_AD7716_SPI_rupt_handler:
;    //  clear any old results (intrpt flag)
;	_SPSR->SPIF = 0;
^^	and.w	#-129,-994
;	AD7716.SPI_finished = 1;
^	move.w	#1,_AD7716+62
;}
^.51
	rts
.50
;
;
;
;
;//  AD7716_rupt_handler (void)
;//  Internal use only
;//
;//  Interrupt handler is invoked when the AD7716 Data Ready line is active
;//
;//    On Data Ready (DRDY or IRQ4 LOW), this handler grabs data from receive
;//      RAM, checks the setup structure to decide which channels are to be
;//		saved, and pushes those channels onto a common buffer.  Later, the user
;//		program will call Get7716Data () to pull data out of the buffer.
;//
;void AD7716_rupt_handler (void)  {
# 1303
| .52
	xdef	_AD7716_rupt_handler
_AD7716_rupt_handler:
;	//  disable additional interrupts while we service this one
;	PConfInp(F,4);
^^;			PConfInpF4
	dc.w	$8b8
	dc.w	$4
	dc.w	$fa1f
	dc.w	$8b8
	dc.w	$4
	dc.w	$fa1d
;	
;	AD7716_SPI_read_data();
^^	jsr	_AD7716_SPI_read_data
;	//  will exit the stop instruction when the SPI interrupts to acknowledge
;	//  completion of the QSPI xfer
;//	Stop (0x2000);
;	while (AD7716.SPI_finished == 0)
^^^^.10044
	tst.w	_AD7716+62
	bne	.10045
;		{;}
^	bra	.10044
.10045
;
;	//  count interrupts; calculation of the conversion rates is performed by
;	//  the get_data_point routine as necessary.  The calculation can be time
;	//  consuming, and we would rather not do it as part of an interrupt
;	//  servicing routine.
;	AD7716.icounter++;
^^^^^^	add.l	#1,_AD7716+8
;
;	/*  check to see if we should save channel 1	*/
;	if (AD7716.save_channels&0x01)  {
^^^	move.w	_AD7716+4,d0
	and.w	#1,d0
	beq	.10046
;//		printf ("data 0x01 to buffer\n");
;		AD7716_filter_chan_zero (SPIRCV[0], SPIRCV[1]);
^^	move.w	-766,-(sp)
	move.w	-768,-(sp)
	jsr	_AD7716_filter_chan_zero
;	}	
^;		
;	/*  now check channel 2 						*/	
;	if (AD7716.save_channels&0x02)	
	add.w	#4,sp
.10046
^^^;		AD7716_filter_chan_one (SPIRCV[2], SPIRCV[3]);
	move.w	_AD7716+4,d0
	and.w	#2,d0
	beq	.10047
^	move.w	-762,-(sp)
	move.w	-764,-(sp)
	jsr	_AD7716_filter_chan_one
;	/*  etc  */	
;	if (AD7716.save_channels&0x04)	
	add.w	#4,sp
.10047
^^;		AD7716_filter_chan_two (SPIRCV[4], SPIRCV[5]);
	move.w	_AD7716+4,d0
	and.w	#4,d0
	beq	.10048
^	move.w	-758,-(sp)
	move.w	-760,-(sp)
	jsr	_AD7716_filter_chan_two
;	if (AD7716.save_channels&0x08)	
	add.w	#4,sp
.10048
^;		AD7716_filter_chan_three (SPIRCV[6], SPIRCV[7]);
	move.w	_AD7716+4,d0
	and.w	#8,d0
	beq	.10049
^	move.w	-754,-(sp)
	move.w	-756,-(sp)
	jsr	_AD7716_filter_chan_three
;
;	//  re-enable interrupts from the Data Ready line
;	PConfBus (F,4);
	add.w	#4,sp
.10049
^^^;			PConfBusF4
	dc.w	$8f8
	dc.w	$4
	dc.w	$fa1f
;}
^.53
	rts
.52
;
;
;
;
;//  AD7716_interrupt_serviced ()
;//  User callable.
;//
;//  Waits until we have just completed servicing an interrupt and then
;//  returns to the caller.  Also returns if no interrupts occur within
;//	a timeout period defined by the loop counter below.  This routine is
;//  useful when another routine wishes to temporarily grab the
;//	SPI interface for its own use.  Also used by the rate calculation
;//  routines to time exactly when an interrupt occured.  It is therefore
;//  important that the delay between the occurence of an interrupt and
;//  the return of this subroutine is as uniform as possible.  Any
;//	non-uniformity translates into inaccuracy in the timing information
;//  and therefore inaccuracy in our rate calculations.  See also the
;//  get_data () routine, which calculates conversion rates
;//
;//  Returns: 0 if interrupt was serviced
;//			 -1 if we timed out
;//  Failures: none - user probably doesn't care why we returned.
;//
;int AD7716_interrupt_serviced (void)  {
# 1361
| .54
	xdef	_AD7716_interrupt_serviced
_AD7716_interrupt_serviced:
	movem.l	d2/d3,-(sp)
;	long loop_count, old_icounter;
;
;	#ifdef SIMULATE_DATA
;		return 0;
;	#endif	
;    
;    //  This routine must respond correctly even if the 7716 is not open or
;    //  is not active.
;	//
;	//  We wait for the AD7716 to signal that it has just completed an
;	//  interrupt servicing sequence by changing the icounter variable
;	//  However, we don't want to get caught in an infinite loop if the
;	//  AD7716 is broken, so we also keep a timeout counter going
;	old_icounter = AD7716.icounter;
~ loop_count d2 "l"
~ old_icounter d3 "l"
^^^^^^^^^^^^^^	move.l	_AD7716+8,d3
;
;	//  A loop count of 1000 requires approximately 8 mS at 16 MHz.
;	//  The slowest interrupts from the 7716 should occur every 8 mS.	
;	//  this is slow, but is never executed unless we aren't receiving
;	//  interrupts, so it doesn't affect the accuracy with which we
;	//  time the completion of the interrupt servicing.
;	for (loop_count = 0;  loop_count < 10000;  loop_count++)  {
^^^^^^^	move.l	#0,d2
.10052
;		if (old_icounter != AD7716.icounter)
^;			return 0;
	cmp.l	_AD7716+8,d3
	beq	.10053
^	move.l	#0,d0
.55
	movem.l	(sp)+,d2/d3
	rts
;	}
.10053
^.10050
	add.l	#1,d2
	cmp.l	#10000,d2
	blt	.10052
.10051
;	return -1;
^	move.l	#-1,d0
	bra	.55
;}
^.54
;
;
;
;
;
;//  AD7716_data_saved (void)
;//  User callable.
;//
;//  Similar to interrupt_serviced (), except that it waits for data to
;//  be pushed into the SPI buffer before returning.  These may not
;//  be the same if we are averaging.
;//
;//  Returns: 0 if data was pushed
;//			 -1 if we timed out
;//  Failures: none - user probably doesn't care why we returned.
;//
;int AD7716_data_saved (void)  {
# 1404
| .56
	xdef	_AD7716_data_saved
_AD7716_data_saved:
	movem.l	d2/d3,-(sp)
;	long loop_count;
;	long old_value;
;	
;	old_value = AD7716.data_pushed;
~ loop_count d2 "l"
~ old_value d3 "l"
^^^^	move.l	_AD7716+12,d3
;	for (loop_count = 0;  loop_count < 60000L;  loop_count++)  {
^	move.l	#0,d2
.10056
;		if (old_value != AD7716.data_pushed)
^;			return 0;
	cmp.l	_AD7716+12,d3
	beq	.10057
^	move.l	#0,d0
.57
	movem.l	(sp)+,d2/d3
	rts
;	}
.10057
^.10054
	add.l	#1,d2
	cmp.l	#60000,d2
	blt	.10056
.10055
;	return -1;
^	move.l	#-1,d0
	bra	.57
;}
^.56
;
;
;
;
;//  The filter routines are expected to preserve the channel number code,
;//  which is embedded in the lower 2 bits of the data.  Unfortunately,
;//  simple averaging will not preserve this code.  For example, channel
;//  one has the code 0x0.  If the first data is 0, and the second data is
;//  0x4, then the average is 0x02, and we have changed the channel code
;//  Any averaging routine must preserve the code.  These routines do so.
;//  They do not attempt to be portable or pretty because they are called
;//  by the interrupt handler and must be fast.
;//  
;void AD7716_filter_chan_zero (unsigned short high, unsigned short low)  {
# 1428
| .58
	xdef	_AD7716_filter_chan_zero
_AD7716_filter_chan_zero:
	movem.l	d2,-(sp)
;	long newest;
;
;	newest = AD7716_data_to_long (high, low);
~ newest d2 "l"
~~ high 8 "I"
~~ low 10 "I"
^^^	move.w	10(sp),-(sp)
	move.w	10(sp),-(sp)
	jsr	_AD7716_data_to_long
	move.l	d0,d2
;	AD7716.c0_total += newest;
^	add.l	d2,_AD7716+38
;	AD7716.c0_n_averaged++;
^	add.w	#1,_AD7716+54
;	if (AD7716.c0_n_averaged >= AD7716.n_to_average)  {
^	move.w	_AD7716+54,d0
	cmp.w	_AD7716+36,d0
	add.w	#4,sp
	blt	.10058
;		AD7716.c0_total /= AD7716.n_to_average;
^	move.l	_AD7716+38,d0
	move.w	_AD7716+36,a0
	move.l	a0,d1
	jsr	.divs#
	move.l	d0,_AD7716+38
;		AD7716_push_data_to_buff (AD7716.c0_total&0xFFFFFFFC);
^	move.l	_AD7716+38,d0
	and.l	#-4,d0
	move.l	d0,-(sp)
	jsr	_AD7716_push_data_to_buff
;		AD7716.c0_total = 0;
^	clr.l	_AD7716+38
;		AD7716.c0_n_averaged = 0;
^	clr.w	_AD7716+54
;	}
^;	return;
	add.w	#4,sp
.10058
^.59
	movem.l	(sp)+,d2
	rts
;}
^.58
;	
;	
;		
;
;
;void AD7716_filter_chan_one (unsigned short high, unsigned short low)  {
# 1447
| .60
	xdef	_AD7716_filter_chan_one
_AD7716_filter_chan_one:
	movem.l	d2,-(sp)
;	long newest;
;	
;	newest = AD7716_data_to_long (high, low);
~ newest d2 "l"
~~ high 8 "I"
~~ low 10 "I"
^^^	move.w	10(sp),-(sp)
	move.w	10(sp),-(sp)
	jsr	_AD7716_data_to_long
	move.l	d0,d2
;	AD7716.c1_total += newest;
^	add.l	d2,_AD7716+42
;	AD7716.c1_n_averaged++;
^	add.w	#1,_AD7716+56
;	if (AD7716.c1_n_averaged >= AD7716.n_to_average)  {
^	move.w	_AD7716+56,d0
	cmp.w	_AD7716+36,d0
	add.w	#4,sp
	blt	.10059
;		AD7716.c1_total /= AD7716.n_to_average;
^	move.l	_AD7716+42,d0
	move.w	_AD7716+36,a0
	move.l	a0,d1
	jsr	.divs#
	move.l	d0,_AD7716+42
;		AD7716_push_data_to_buff (0x02 | (AD7716.c1_total&0xFFFFFFFC));
^	move.l	_AD7716+42,d0
	and.l	#-4,d0
	bset.l	#1,d0
	move.l	d0,-(sp)
	jsr	_AD7716_push_data_to_buff
;		AD7716.c1_total = 0;
^	clr.l	_AD7716+42
;		AD7716.c1_n_averaged = 0;
^	clr.w	_AD7716+56
;	}
^;	return;
	add.w	#4,sp
.10059
^.61
	movem.l	(sp)+,d2
	rts
;}
^.60
;	
;	
;		
;
;
;void AD7716_filter_chan_two (unsigned short high, unsigned short low)  {
# 1466
| .62
	xdef	_AD7716_filter_chan_two
_AD7716_filter_chan_two:
	movem.l	d2,-(sp)
;	long newest;
;	
;	newest = AD7716_data_to_long (high, low);
~ newest d2 "l"
~~ high 8 "I"
~~ low 10 "I"
^^^	move.w	10(sp),-(sp)
	move.w	10(sp),-(sp)
	jsr	_AD7716_data_to_long
	move.l	d0,d2
;	AD7716.c2_total += newest;
^	add.l	d2,_AD7716+46
;	AD7716.c2_n_averaged++;
^	add.w	#1,_AD7716+58
;	if (AD7716.c2_n_averaged >= AD7716.n_to_average)  {
^	move.w	_AD7716+58,d0
	cmp.w	_AD7716+36,d0
	add.w	#4,sp
	blt	.10060
;		AD7716.c2_total /= AD7716.n_to_average;
^	move.l	_AD7716+46,d0
	move.w	_AD7716+36,a0
	move.l	a0,d1
	jsr	.divs#
	move.l	d0,_AD7716+46
;		AD7716_push_data_to_buff (0x01 | (AD7716.c2_total&0xFFFFFFFC));
^	move.l	_AD7716+46,d0
	and.l	#-4,d0
	bset.l	#0,d0
	move.l	d0,-(sp)
	jsr	_AD7716_push_data_to_buff
;		AD7716.c2_total = 0;
^	clr.l	_AD7716+46
;		AD7716.c2_n_averaged = 0;
^	clr.w	_AD7716+58
;	}
^;	return;
	add.w	#4,sp
.10060
^.63
	movem.l	(sp)+,d2
	rts
;}
^.62
;	
;	
;		
;
;
;void AD7716_filter_chan_three (unsigned short high, unsigned short low)  {
# 1485
| .64
	xdef	_AD7716_filter_chan_three
_AD7716_filter_chan_three:
	movem.l	d2,-(sp)
;	long newest;
;	
;	newest = AD7716_data_to_long (high, low);
~ newest d2 "l"
~~ high 8 "I"
~~ low 10 "I"
^^^	move.w	10(sp),-(sp)
	move.w	10(sp),-(sp)
	jsr	_AD7716_data_to_long
	move.l	d0,d2
;	AD7716.c3_total += newest;
^	add.l	d2,_AD7716+50
;	AD7716.c3_n_averaged++;
^	add.w	#1,_AD7716+60
;	if (AD7716.c3_n_averaged >= AD7716.n_to_average)  {
^	move.w	_AD7716+60,d0
	cmp.w	_AD7716+36,d0
	add.w	#4,sp
	blt	.10061
;		AD7716.c3_total /= AD7716.n_to_average;
^	move.l	_AD7716+50,d0
	move.w	_AD7716+36,a0
	move.l	a0,d1
	jsr	.divs#
	move.l	d0,_AD7716+50
;		AD7716_push_data_to_buff (0x03 | AD7716.c3_total);
^	move.l	_AD7716+50,d0
	or.l	#3,d0
	move.l	d0,-(sp)
	jsr	_AD7716_push_data_to_buff
;		AD7716.c3_total = 0;
^	clr.l	_AD7716+50
;		AD7716.c3_n_averaged = 0;
^	clr.w	_AD7716+60
;	}
^;	return;
	add.w	#4,sp
.10061
^.65
	movem.l	(sp)+,d2
	rts
;}
^.64
;	
;	
;		
;
;
;
;
;/*	AD7716_SPI_buffer_open (long n_points)
; *  Internal use only
; *
; *  Allocates and initializes the buffer used by the SPI interrupt
; *  handler routine to store incoming points.  n_longs is the number
; *  of long integers (one per channel saved) which the buffer can hold,
; *  while n_points is the number of short integers which the buffer
; *  can hold.
; *
; *  Arguments: size of buffer (in points, one long per point)
; *  Returns: 0 on success; negative on failure
; *  Failures: only on memory allocation failure
; *
;*/ 
;int AD7716_SPI_buffer_open (long n_longs)  {
# 1520
| .66
	xdef	_AD7716_SPI_buffer_open
_AD7716_SPI_buffer_open:
;	//  REVIEW - is this true on a warm reboot?
;	//  don't allow memory leaks
;	ASSERT (SPI_buffer.data_start == NULL);
~~ n_longs 8 "l"
^^^;	ASSERT (AD7716.AD7716_open_flag == 1);
^;
;	//  n_points refers to number of 4 byte longs
;	SPI_buffer.n_points = n_longs;
^^^	move.l	4(sp),_SPI_buffer+4
;	SPI_buffer.data_start = (long*) malloc (sizeof (long) * SPI_buffer.n_points);
^	move.l	_SPI_buffer+4,d0
	asl.l	#2,d0
	move.l	d0,-(sp)
	jsr	_malloc
	move.l	d0,_SPI_buffer
;	if (SPI_buffer.data_start == NULL)  {
^	tst.l	_SPI_buffer
	add.w	#4,sp
	bne	.10062
;		SPI_buffer.next_in = NULL;
^	clr.l	_SPI_buffer+12
;		SPI_buffer.next_out = NULL;
^	clr.l	_SPI_buffer+16
;		SPI_buffer.data_end = NULL;
^	clr.l	_SPI_buffer+8
;		SPI_buffer.n_points = 0;
^	clr.l	_SPI_buffer+4
;		#ifdef DEBUG
;			printf ("AD7716_SPI_buffer_open: Memory malloc (%ld) failure\n", (sizeof (long)*n_longs));
;			mem_find_max_malloc ();	
;		#endif
;		return -1;
^^^^^	move.l	#-1,d0
.67
	rts
;	}
^;	
;	//  the buffer empty routine sets values for data_end, next_in, and next_out
;	AD7716_SPI_buffer_empty ();
.10062
^^^	jsr	_AD7716_SPI_buffer_empty
;	return 0;
^	move.l	#0,d0
	bra	.67
;}
^.66
;
;
;
;
;//  AD7716_SPI_buffer_empty
;//  Internal use only
;//
;//  Marks the SPI buffer as empty;  the buffer must be allocated before
;//  the routine call be called.
;//
;void AD7716_SPI_buffer_empty (void)  {
# 1555
| .68
	xdef	_AD7716_SPI_buffer_empty
_AD7716_SPI_buffer_empty:
;	#ifdef DEBUG
;		//  if debugging, init buffer to known values
;		long n;
;		ASSERT (AD7716.AD7716_open_flag == 1);
;		ASSERT (SPI_buffer.data_start != NULL);
;		
;		for (n = 0;  n < SPI_buffer.n_points;  n++)
;			SPI_buffer.data_start[n] = 0xCF;
;	#endif		
;	SPI_buffer.next_in = SPI_buffer.data_start;
^^^^^^^^^^	move.l	_SPI_buffer,_SPI_buffer+12
;	SPI_buffer.next_out = SPI_buffer.data_start;
^	move.l	_SPI_buffer,_SPI_buffer+16
;	//  Note that data_end points one past the end of the actual buffer
;	//  I suppose this might be a problem with some compilers or memory
;	//  ranges, but it seems to work fine here.
;	SPI_buffer.data_end = &SPI_buffer.data_start[SPI_buffer.n_points];
^^^^	move.l	_SPI_buffer+4,d0
	asl.l	#2,d0
	add.l	_SPI_buffer,d0
	move.l	d0,_SPI_buffer+8
;	SPI_buffer.overflow = 0;
^	clr.w	_SPI_buffer+20
;}
^.69
	rts
.68
;
;
;
;
;//  AD7716_SPI_buffer_delete (void)
;//  Internal use only
;//
;//  Deletes an SPI buffer which was allocated above
;//
;void AD7716_SPI_buffer_delete (void)  {
# 1582
| .70
	xdef	_AD7716_SPI_buffer_delete
_AD7716_SPI_buffer_delete:
;	ASSERT (AD7716.AD7716_open_flag == 1);
^;	if (SPI_buffer.data_start == NULL)
^;		return;
	tst.l	_SPI_buffer
	bne	.10063
^.71
	rts
;
;	SPI_buffer.overflow = -1;
.10063
^^	move.w	#-1,_SPI_buffer+20
;	#ifdef DEBUG
;		//  if debugging, reset pointers to illegal values so as to
;		//  catch errors later.
;		SPI_buffer.next_in = NULL;
;		SPI_buffer.next_out = NULL;
;		SPI_buffer.data_end = NULL;
;		SPI_buffer.n_points = 0;
;	#endif
;	ASSERT (SPI_buffer.data_start != NULL);
^^^^^^^^^;	free (SPI_buffer.data_start);
^	move.l	_SPI_buffer,-(sp)
	jsr	_free
;	SPI_buffer.data_start = NULL;
^	clr.l	_SPI_buffer
;	return;
^	add.w	#4,sp
	bra	.71
;}
^.70
;
;
;
;
;
;
;//	AD7716_push_data_to_buff
;//	Internal use only
;//
;//  Puts the given data into the circular SPI buffer.  Continously
;//	wraps around end of buffer.
;//
;//	This routine only checks the buffer pointer to see if it wrapped
;//	after the data is added to the buffer.
;//
;//	Arguments: a long which is to be added to the buffer
;//	Returns, failures: none
;//
;void AD7716_push_data_to_buff (long value)        
;	{
# 1619
^| .72
	xdef	_AD7716_push_data_to_buff
_AD7716_push_data_to_buff:
;	*SPI_buffer.next_in++ = value;
~~ value 8 "l"
^	move.l	_SPI_buffer+12,a0
	add.l	#4,_SPI_buffer+12
	move.l	4(sp),(a0)
;	AD7716.data_pushed++;
^	add.l	#1,_AD7716+12
;
;	if(SPI_buffer.next_in == SPI_buffer.data_end)  {
^^	move.l	_SPI_buffer+12,a0
	cmp.l	_SPI_buffer+8,a0
	bne	.10064
;		//  We've reached the end of the buffer, so wrap to start
;		SPI_buffer.next_in = &SPI_buffer.data_start[0];
^^	move.l	_SPI_buffer,_SPI_buffer+12
;	}
^;		
;	//  If this fails, we are about to overwrite data; this would occur
;	//  if we failed to remove data from the buffer fast enough.
;	//  We need to make the buffer length long enough and the code fast
;	//  enough to avoid this, but if it happens, it is important to catch
;	//  it and handle it properly
;	if (SPI_buffer.next_in == SPI_buffer.next_out)
.10064
^^^^^^^;		SPI_buffer.overflow = 1;
	move.l	_SPI_buffer+12,a0
	cmp.l	_SPI_buffer+16,a0
	bne	.10065
^	move.w	#1,_SPI_buffer+20
;}
.10065
^.73
	rts
.72
;
;
;
;
;short AD7716_check_for_overflow (void)  {
# 1641
| .74
	xdef	_AD7716_check_for_overflow
_AD7716_check_for_overflow:
;
;	//  overflow equals -1 if ad7716 is closed
;	if (SPI_buffer.overflow == 1)
^^^;		return 1;
	cmp.w	#1,_SPI_buffer+20
	bne	.10066
^	move.l	#1,d0
.75
	rts
;	else
.10066
;		return 0;
^^	move.l	#0,d0
	bra	.75
;}
^.74
;
;
;void AD7716_clear_overflow (void)  {
# 1651
| .76
	xdef	_AD7716_clear_overflow
_AD7716_clear_overflow:
;	//  don't clear unless we are open
;	if (AD7716.AD7716_open_flag != 0)
^^;		SPI_buffer.overflow = 0;
	tst.w	_AD7716
	beq	.10067
^	clr.w	_SPI_buffer+20
;}
.10067
^.77
	rts
.76
;
;
;
;
;//  AD7716_get_data_point (long* value)
;//  User callable
;//
;//  Collects the oldest data point from the SPI buffer and returns it to
;//  to the user through the pointer passed.  The result returned
;//  is a 24 bit result.  The lower two bits are the channel information
;//  as defined in the AD7716 data sheet, and are a constant for a given
;//  channel.  This results in an insignificant (and constant) offset
;//  added to each channel.
;//
;//  Arguments: pointer to a long where the data will be put (if available)
;//  Returns: 0 if data was returned;
;//			 -1 if there is no data waiting
;//  Failures: no failures, though data may not be returned
;//
;int AD7716_get_data_point (long* value)        
;	{
# 1675
^| .78
	xdef	_AD7716_get_data_point
_AD7716_get_data_point:
	link	a6,#.79
	movem.l	d2/d3/d4,-(sp)
;	time_tt now;
;	long n_samples;
;	double old_rate, fraction;
;	#ifdef SIMULATE_DATA
;		static long sim_data = 0;
;		static short chan_count;
;	#endif	
;	
;	if (AD7716.AD7716_open_flag == 0)
~ ''
~ 2 2 8
~ secs 0 "L"
~ ticks 4 "l"
~ now -8 ":" 2
~ n_samples d4 "l"
~ old_rate -16 "d"
~ fraction -24 "d"
~~ value 8 "#l"
^^^^^^^^^;		return -1;
	tst.w	_AD7716
	bne	.10068
^	move.l	#-1,d0
.80
	movem.l	(sp)+,d2/d3/d4
	unlk	a6
	rts
;
;	#ifdef SIMULATE_DATA
;		#ifdef SHORT_SCIENCE_DATA
;			*value = sim_data++ << 8;
;			if (sim_data > 32766)
;				sim_data = -32766;
;			*value |= AD7716.sim_chan[chan_count++];
;			if (chan_count >= AD7716.n_channels)
;				chan_count = 0;
;			AD7716.data_pushed++;	
;			AD7716.n_simulated++;
;			return 0;
;		#else
;			ASSERT(0);
;			*value = 0x0FCFCFCF;
;			return 0;
;		#endif
;	#endif
;		
;	/*  check if there are any numbers in the buffer; if not, return
;	 *  negative number; if debugging, assign an impossible value to
;	 *  the users pointer
;	*/ 
;	if (SPI_buffer.next_out == SPI_buffer.next_in)  {
.10068
^^^^^^^^^^^^^^^^^^^^
^^^^	move.l	_SPI_buffer+16,a0
	cmp.l	_SPI_buffer+12,a0
	bne	.10069
;		#ifdef DEBUG
;			*value = 0x0FCFCFCF;
;		#endif	
;		return -1;
^^^^	move.l	#-1,d0
	bra	.80
;	}
^;	
;	*value = *SPI_buffer.next_out++;
.10069
^^	move.l	_SPI_buffer+16,a0
	add.l	#4,_SPI_buffer+16
	move.l	8(a6),a1
	move.l	(a0),(a1)
;	if (SPI_buffer.next_out == SPI_buffer.data_end)
^;		SPI_buffer.next_out = SPI_buffer.data_start;
	move.l	_SPI_buffer+16,a0
	cmp.l	_SPI_buffer+8,a0
	bne	.10070
^	move.l	_SPI_buffer,_SPI_buffer+16
;
;	//  After returning a certain number of data points we recalculate
;	//  the actual measured conversion rate.
;	//
;	//  Rate calculation works as follows:
;	//  The rate is calculated by recording a starting time, and a starting number
;	//  of interrupts.  When the threshold is passed, the code calculates how much
;	//  time has passed, how many interrupt occured, and the interrupts/second.
;	//  The code recalculates the conversion rate after every threshold data points
;	//  are returned to the user.  If we have reason to believe that the current
;	//  data might be bad (for example, the interrupt processing was paused, and we
;	//  have no way of knowing whether it was restarted in time), then we can
;	//  temporarily suppress a calculation by setting the start time seconds to
;	//  0 which is obviously an illegal value.  In this case, the software will save
;	//  a new start time and interrupt count, use the old conversion rate, and
;	//  recalculate the exact conversion rate next time around.  If we want to
;	//  suppress the use of the calculated conversion rate till a new value is
;	//  calculated, (as we would if the conversion rate is changed) then we set
;	//  the measured_rate to be less than or equal to 0.
;	if (AD7716.data_pushed > AD7716.rate_calc_threshold)  {
.10070
^^^^^^^^^^^^^^^^^^^^	move.l	_AD7716+12,d0
	cmp.l	_AD7716+32,d0
	bls	.10071
;		//  wait for the interupt to be serviced and data to be saved
;		AD7716_data_saved ();
^^	jsr	_AD7716_data_saved
;
;		//  collect the data which defines this sample: the current time,
;		//  and the counter which tell us how much data has been saved.
;		now = logger_time_get_time ();
^^^^	lea	-8(a6),a0
	move.l	a0,-(sp)
	jsr	_logger_time_get_time
	move.l	d0,a0
	move.l	(sp)+,a1
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
;		
;		//  The old rate is used for error checking because we are temporarily concerned
;		//  about the real time clock.  The new rate should not differ from the old rate
;		//  by very much.
;		old_rate = AD7716.measured_rate;
^^^^^	move.l	_AD7716+28,-12(a6)
	move.l	_AD7716+24,-16(a6)
;
;//printf ("  Calculating new rate.\n");		
;		//  calculate how many samples were taken between the two times		
;		ASSERT ((AD7716.data_pushed%AD7716.n_channels) == 0);
^^^^;		ASSERT (AD7716_get_n_channels() > 0);
^;		n_samples = AD7716.data_pushed / AD7716_get_n_channels ();
^	jsr	_AD7716_get_n_channels
	move.w	d0,d1
	ext.l	d1
	move.l	_AD7716+12,d0
	jsr	.divu#
	move.l	d0,d4
;//printf ("  n samples is %ld\n", n_samples);
;//printf ("  Start time is %s", logger_time_get_string (&AD7716.start_time));
;//printf ("  Now is %s", logger_time_get_string (&now));
;//printf ("  Difference is %ld ticks\n", (long)ttmcmp (now, AD7716.start_time));
;		AD7716.measured_rate = ((double)n_samples * (double)GetTickRate ());
^^^^^	jsr	_GetTickRate
	jsr	.Pflt#
	move.l	d1,-(sp)
	move.l	d0,-(sp)
	move.l	d4,d0
	jsr	.Pflt#
	move.l	d1,d3
	move.l	d0,d2
	move.l	(sp)+,d0
	move.l	(sp)+,d1
	jsr	.Pmul#
	move.l	d1,_AD7716+28
	move.l	d0,_AD7716+24
;		AD7716.measured_rate /= (double)(ttmcmp (now, AD7716.start_time));
^	sub.w	#8,sp
	move.l	sp,a0
	lea	_AD7716+16,a1
	move.l	(a1)+,(a0)+
	move.l	(a1)+,(a0)+
	sub.w	#8,sp
	move.l	sp,a0
	lea	-8(a6),a1
	move.l	(a1)+,(a0)+
	move.l	(a1)+,(a0)+
	jsr	_ttmcmp
	jsr	.Pflt#
	move.l	d1,d3
	move.l	d0,d2
	move.l	_AD7716+28,d1
	move.l	_AD7716+24,d0
	jsr	.Pdiv#
	move.l	d1,_AD7716+28
	move.l	d0,_AD7716+24
;		//  This print used to be included so that we could track any unexpected gains
;		//  or losses of 1 second, which we suspected at one point.  However, months
;		//  of error free operation has led to the conclusion that our suspicions were
;		//  wrong, and we no longer compile this printf
;//		log_printf ("Rate %.9lf at %s", AD7716.measured_rate, logger_time_get_string (&now));
;
;		//  Check for and log any discontinuity in the calculated rate.  A discontinuity
;		//  could indicate a spurious count of the seconds.  This code will trigger the
;		//  first time through when the old rate is -1.  I leave this in just to test
;		//  its execution.
;		fraction = old_rate / AD7716.measured_rate;
^^^^^^^^^^^	move.l	-12(a6),d1
	move.l	-16(a6),d0
	move.l	_AD7716+28,d3
	move.l	_AD7716+24,d2
	jsr	.Pdiv#
	move.l	d1,-20(a6)
	move.l	d0,-24(a6)
;		fraction -= 1.0;
^	move.l	-20(a6),d1
	move.l	-24(a6),d0
	move.l	#$00000000,d3
	move.l	#$bff00000,d2
	jsr	.Padd#
	move.l	d1,-20(a6)
	move.l	d0,-24(a6)
;		fraction = fabs (fraction);
^	move.l	-20(a6),-(sp)
	move.l	-24(a6),-(sp)
	jsr	_fabs
	move.l	d1,-20(a6)
	move.l	d0,-24(a6)
;		//  Threshold currently set at 0.1 %, which will easily catch a one second
;		//  error over 300 seconds.  Normal uncertainties in the rate should be of
;		//  the order of ppm.
;		if (fraction > 0.001)  {
^^^^	move.l	-20(a6),d1
	move.l	-24(a6),d0
	move.l	#$d2f1a9fc,d3
	move.l	#$3f50624d,d2
	jsr	.Pcmp#
	lea	24(sp),sp
	ble	.10072
;			log_printf ("A/D conversion rate is %.8f\n", AD7716.measured_rate);
^	move.l	_AD7716+28,-(sp)
	move.l	_AD7716+24,-(sp)
	pea	.1+0
	jsr	_log_printf
;			if (old_rate != -1)
^;				log_printf ("That was an unexpected rate jump! (old rate %.9lf)\n", old_rate);
	move.l	-12(a6),d1
	move.l	-16(a6),d0
	move.l	#$00000000,d3
	move.l	#$bff00000,d2
	jsr	.Pcmp#
	lea	12(sp),sp
	beq	.10073
^	move.l	-12(a6),-(sp)
	move.l	-16(a6),-(sp)
	pea	.1+29
	jsr	_log_printf
;		}		
	lea	12(sp),sp
.10073
^;		
;		//  and set up for next time
;		AD7716_data_saved ();
.10072
^^^	jsr	_AD7716_data_saved
;		AD7716.start_time = logger_time_get_time ();
^	lea	_AD7716+16,a0
	move.l	a0,-(sp)
	jsr	_logger_time_get_time
	move.l	d0,a0
	move.l	(sp)+,a1
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
;		AD7716.data_pushed = 0;
^	move.l	#0,_AD7716+12
;	}
^;
;	return 0;
.10071
^^	move.l	#0,d0
	bra	.80
;}
^.78
.79	equ	-24
.1
	dc.b	65,47,68,32,99,111,110,118,101,114,115,105,111,110,32
	dc.b	114,97,116,101,32,105,115,32,37,46,56,102,10,0,84
	dc.b	104,97,116,32,119,97,115,32,97,110,32,117,110,101,120
	dc.b	112,101,99,116,101,100,32,114,97,116,101,32,106,117,109
	dc.b	112,33,32,40,111,108,100,32,114,97,116,101,32,37,46
	dc.b	57,108,102,41,10,0
	ds	0
;
;
;
;
;//	AD7716_data_to_long
;//  Internal use only
;//
;//  Converts two's-complement data from AD7716 (22 bits+10 status bits) 
;//  to long integer format. Looks at overflow bit and assigns 
;//  overflowed data to full scale value (with polarity as defined
;//  by MSB of data).
;//
;//	Changed from Tom's original code in that the result returned is
;//	now 24 bits, with the lower two bits being the channel number as
;//	defined in the 7716 data sheet.  This changes the scaling and
;//	produces an offset on each channel.  The offset is constant
;//	and small enough to ignore.  This allows us to always know what
;//	channel a piece of data came from.
;//
;//	Arguments: high = the high 16 bits of the two word input
;//			   low = the low 16 bits
;//  Returns: the long data, as described above
;//  Failures: none
;//
;long AD7716_data_to_long (unsigned short high, unsigned short low)
;	{
# 1817
^| .82
	xdef	_AD7716_data_to_long
_AD7716_data_to_long:
	movem.l	d2/d3/d4/d5,-(sp)
	move.w	20(sp),d4
	move.w	22(sp),d5
;	long result;
;	short chan;
;	//  verify that the Device Address and the Pace Detect are both 0
;//	ASSERT ((low&0x00F0) == 0);
;
;	/*  start by checking for overflow; no need to look at data if
;	 *  overflowed; just set to min or max according to sign
;	 */
;	if(low & 0x0008)  {
~ result d2 "l"
~ chan d3 "i"
~~ high d4 "I"
~~ low d5 "I"
^^^^^^^^^	move.w	d5,d0
	and.w	#8,d0
	beq	.10074
;		/*  when making up the overflow number, make sure we keep
;		 *  the channel information correct.
;		*/ 
;		chan = (low >> 8) & 0x03;
^^^^	move.w	d5,d0
	lsr.w	#8,d0
	move.w	d0,d3
	and.w	#3,d3
;
;		/*  if overflowed, then next question is sign of data  */
;		if(high & 0x8000)
^^^;			/*  NEGATIVE FULL SCALE  */
;			result = ((-1*0x200000) << 2) | chan;
	move.w	d4,d0
	and.w	#32768,d0
	beq	.10075
^^	move.w	d3,d0
	ext.l	d0
	move.l	d0,d2
	or.l	#-8388608,d2
;		else
	bra	.10076
.10075
;			/*  POSITIVE FULL SCALE  */
;			result = (0x1FFFFF << 2) | chan;
^^^	move.w	d3,d0
	ext.l	d0
	move.l	d0,d2
	or.l	#8388604,d2
.10076
;	}  else  {
^	bra	.10077
.10074
;		/*  not overflowed, so get the real data  */
;//		result = ((0x0FFFFL & (long)high) << 8) | (0x00FFL & (((long)low) >> 8));	
;		result = ((0x0FFFFL & (long)high) << 8) | (0x00FFL & (long)(low >> 8));	
^^^	move.l	#0,d0
	move.w	d4,d0
	and.l	#65535,d0
	asl.l	#8,d0
	move.w	d5,d1
	lsr.w	#8,d1
	and.l	#65535,d1
	and.l	#255,d1
	move.l	d0,d2
	or.l	d1,d2
;				
;		/*  now adjust the sign of the data if necessary */
;		if(high & 0x8000)
^^^;/*		
;			this was not adjusted when I went to a 24 bit result
;			result = -1*(~(Channel1Data-1)-0xFFC00000);
;*/	
;			result |= 0xFF000000;
	move.w	d4,d0
	and.w	#32768,d0
	beq	.10078
^^^^^	or.l	#-16777216,d2
;	}
.10078
^.10077
;	return result;
^	move.l	d2,d0
.83
	movem.l	(sp)+,d2/d3/d4/d5
	rts
;}
^.82
;
;
;
;
;
;
;//	AD7716_get_data_point_time (void)
;//  User callable
;//
;//	Returns the time at which the AD converter converted the data point
;//  most recently returned by the AD7716_get_data_point() routine.  This
;//  is necessary in order for the user to accurately determine the time
;//  a particular data point was acquired.
;//
;//
;time_tt AD7716_get_data_point_time (void)  {
# 1870
	bss	.10079,8
| .84
	xdef	_AD7716_get_data_point_time
_AD7716_get_data_point_time:
	link	a6,#.85
	movem.l	d2/d3/d4/d5/d6,-(sp)
;	time_tt last_time;
;	long n_waiting, secs, ticks;
;	double delta_t;
;	ASSERT (AD7716.AD7716_open_flag == 1);
~ last_time -8 ":" 2
~ n_waiting d5 "l"
~ secs d4 "l"
~ ticks d6 "l"
~ delta_t -16 "d"
^^^^;	
;	//  Improve the accuracy of this routine by waiting for data to
;	//  be saved before doing the calculations.  This eliminates 
;	//  random noise which would range from 0 to a conversion time.
;	//  Probably irrelavent, but we may as well do it.
;	//  REVIEW - we probably also should make sure we are still taking
;	//  data - otherwise this routine is meaningless.
;	AD7716_data_saved ();
^^^^^^^^	jsr	_AD7716_data_saved
;	last_time = logger_time_get_time (); 
^	lea	-8(a6),a0
	move.l	a0,-(sp)
	jsr	_logger_time_get_time
	move.l	d0,a0
	move.l	(sp)+,a1
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
;	n_waiting = AD7716_get_n_waiting ();
^	jsr	_AD7716_get_n_waiting
	move.l	d0,d5
;
;	//  The accuracy of the conversion from n_waiting to a delta_t depends
;	//  on the accuracy of the conversion rate, which is only as accurate as
;	//  the ADC crystal accuracy at first, and then quite good once we have
;	//  converted enough data to have computed a measured conversion rate.
;	delta_t = n_waiting / AD7716_get_conversion_rate ();	
^^^^^^	jsr	_AD7716_get_conversion_rate
	move.l	d1,d3
	move.l	d0,d2
	move.l	d5,d0
	jsr	.Pflt#
	jsr	.Pdiv#
	move.l	d1,-12(a6)
	move.l	d0,-16(a6)
;	secs = (long) delta_t;
^	move.l	-12(a6),d1
	move.l	-16(a6),d0
	jsr	.Pfix#
	move.l	d0,d4
;	ticks = (long)(0.5 + GetTickRate()*(delta_t - secs));
^	jsr	_GetTickRate
	jsr	.Pflt#
	move.l	d1,-(sp)
	move.l	d0,-(sp)
	move.l	-12(a6),d1
	move.l	-16(a6),d0
	move.l	d1,-(sp)
	move.l	d0,-(sp)
	move.l	d4,d0
	jsr	.Pflt#
	move.l	d1,d3
	move.l	d0,d2
	move.l	(sp)+,d0
	move.l	(sp)+,d1
	jsr	.Psub#
	move.l	d1,d3
	move.l	d0,d2
	move.l	(sp)+,d0
	move.l	(sp)+,d1
	jsr	.Pmul#
	move.l	#$00000000,d3
	move.l	#$3fe00000,d2
	jsr	.Padd#
	jsr	.Pfix#
	move.l	d0,d6
;	
;	last_time.secs -= secs;
^^	sub.l	d4,-8(a6)
;	last_time.ticks -= ticks;
^	sub.l	d6,-4(a6)
;	if (last_time.ticks < 0)  {
^	tst.l	-4(a6)
	bge	.10080
;		last_time.ticks += GetTickRate ();
^	jsr	_GetTickRate
	add.l	d0,-4(a6)
;		last_time.secs -= 1;
^	sub.l	#1,-8(a6)
;	}
^;	ASSERT ((last_time.ticks >= 0) && (last_time.ticks < GetTickRate ()));
.10080
^;	return last_time;
^	lea	.10079,a0
	lea	-8(a6),a1
	move.l	(a1)+,(a0)+
	move.l	(a1)+,(a0)+
	lea	.10079,a0
	move.l	a0,d0
.86
	movem.l	(sp)+,d2/d3/d4/d5/d6
	unlk	a6
	rts
;}
^.84
.85	equ	-16
;		
;
;
;
;//	AD7716_get_channel_n (long value)
;//  User callable
;//
;//	This routine returns the channel number (1 through 4) from
;//	which this data was taken.  This is more complicated then
;//  it should be because of the goofy way the Analog Devices
;//  people encode the channel number as a bit pattern.  Why they
;//  couldn't use (n-1) I don't know.  This routine may be called
;//  even when the logger is not opened
;//
;//  Arguments: a A/D value as returned by AD7716_get_data_point()
;//  Returns: The channel number from which the data was taken; the
;//				channels are numbered 0-3, unlike the AD7716 docs,
;//				which call them 1-4
;//  Failures: none possible.  A return of -1 should be impossible
;//		unless this code is broken.
;//
;int AD7716_get_channel_num (long value)  {
# 1924
| .87
	xdef	_AD7716_get_channel_num
_AD7716_get_channel_num:
	movem.l	d2,-(sp)
	move.l	8(sp),d2
;	value &= 0x03;
~~ value d2 "l"
^	and.l	#3,d2
;	
;    switch (value)  {
^^	move.l	d2,d0
	bra	.10081
;    	case 0:
^.10083
;    		return 0;
^	move.l	#0,d0
.88
	movem.l	(sp)+,d2
	rts
;    		
;    	case 0x02:
^^.10084
;    		return 1;
^	move.l	#1,d0
	bra	.88
;    		
;    	case 0x01:
^^.10085
;    		return 2;
^	move.l	#2,d0
	bra	.88
;    		
;    	case 0x03:
^^.10086
;    		return 3;
^	move.l	#3,d0
	bra	.88
;    		
;    	default:
^^.10087
;    		ASSERT (0);
^;    		break;
^	bra	.10082
;    }						
^.89
	dc.w	.10083-.90-2
	dc.w	.10085-.90-2
	dc.w	.10084-.90-2
	dc.w	.10086-.90-2
.10081
	cmp.l	#4,d0
	bcc	.10087
	add.w	d0,d0
	move.w	.89(pc,d0.w),d0
.90
	jmp	(pc,d0.w)
.10082
;    return -1;
^	move.l	#-1,d0
	bra	.88
;}	
^.87
;
;
;
;
;unsigned long AD7716_get_icount (void)  {
# 1950
| .91
	xdef	_AD7716_get_icount
_AD7716_get_icount:
;	unsigned long icount;
;	
;	return AD7716.icounter;
^^^	move.l	_AD7716+8,d0
.92
	rts
;}
^.91
;
;
;
;
;//  REVIEW
;//
;//	The original code caught a compiler bug.  The compiler seems to use
;//  logical shift right to divide by 2 (or sizeof short).  This works fine
;//  as long as the number being divided is positive.  Fails miserably if
;//  number is negative.  A logical shift replaces the leading sign bit with
;//  a zero and converts from a negative number to a very large positive number
;//
;//  From the assembler code printout we see that the compiler does the
;//  following:
;//  	;	n_waiting /= sizeof(short); 
;//		^	lsr.l	#1,d4
;//  A collection of printf statements produced the following:
;//		n_waiting before division = -30676
;//		n_waiting after division = 2147468310
;//
;//  Write this routine so we never divide a negative number by 2
;//
;//
;//  REVIEW
;//  In theory this calculation could be screwed if an AD7716 interrupt occured in
;//  the middle of the subtraction below, but this seems essentially impossible at
;//  any usable clock speed (as long as there are NO other routines interrupting), so we don't
;//  bother disabling interrupts here.  If other routines will interrupt (such as the
;//  disk) then we should disable interrupts before we get the time.
;//
;//  Should really fix this so that overflows are properly indicated.
;long AD7716_get_n_waiting (void)  {
# 1986
| .93
	xdef	_AD7716_get_n_waiting
_AD7716_get_n_waiting:
	movem.l	d2,-(sp)
;	long result;
;
;	if (AD7716.AD7716_open_flag != 1)
~ result d2 "l"
^^^;		return 0;
	cmp.w	#1,_AD7716
	beq	.10088
^	move.l	#0,d0
.94
	movem.l	(sp)+,d2
	rts
;
;	#ifdef SIMULATE_DATA
;		//  Fake data routines return data without actually collecting anything
;		//  from the 7716.  Since the data is faked, there is always plenty waiting.
;		return 100;
;	#endif	
;/*
;printf ("n_points = %ld\n", SPI_buffer.n_points);		
;printf ("Next in = %ld\n", (long)SPI_buffer.next_in);
;printf ("Next out = %ld\n", (long)SPI_buffer.next_out);		
;*/
;
;	result = ((long)(SPI_buffer.next_in) - (long)(SPI_buffer.next_out));
.10088
^^^^^^^^^^^^^	move.l	_SPI_buffer+12,d2
	sub.l	_SPI_buffer+16,d2
;	ASSERT ((result%4) == 0);
^;	if (result < 0)
^;		result += (sizeof (long) * SPI_buffer.n_points);
	tst.l	d2
	bge	.10089
^	move.l	_SPI_buffer+4,d0
	asl.l	#2,d0
	add.l	d0,d2
;
;	//  convert from number of bytes to number of long words
;	ASSERT (result >= 0);
.10089
^^^;	result /= sizeof (long);
^	lsr.l	#2,d2
;	ASSERT (result <= SPI_buffer.n_points);	
^;
;	//  finally, one more division to account for the number of channels
;	//  we are saving
;	result /= AD7716.n_channels;
^^^^	move.l	d2,d0
	move.w	_AD7716+6,a0
	move.l	a0,d1
	jsr	.divs#
	move.l	d0,d2
;	return result;
^	move.l	d2,d0
	bra	.94
;}	
^.93
;
;
;
;
;
;#ifdef DEBUG
;void AD7716_critical_data_dump (void)  {
;	long n, m, set, sets_pulled;
;	long pushed;
;	long pulled;
;	long start, stop;
;	long data_index;
;	if (AD7716.AD7716_open_flag != 1)  {
;		printf ("AD7716 closed; no data to dump.\n");
;		return;
;	}	
;	
;	PConfInp(F,4);
;	printf ("AD7716 Critical Data Dump:\n");
;	printf (" AD7716: data_start = 0x%08lX = %ld\n", (long)SPI_buffer.data_start,
;													  (long)SPI_buffer.data_start);
;	printf (" AD7716: n_points   = %ld [number of longs]\n", SPI_buffer.n_points);
;	printf (" AD7716: data_end   = 0x%08lX = %ld\n", (long)SPI_buffer.data_end,
;												 	(long)SPI_buffer.data_end);
;	printf (" AD7716: next_in    = 0x%08lX = %ld\n", (long)SPI_buffer.next_in, 
;													(long)SPI_buffer.next_in);
;	printf (" AD7716: next_out   = 0x%08lX = %ld\n", (long)SPI_buffer.next_out,
;														(long)SPI_buffer.next_out);
;	printf (" AD7716: interrupt count = %ld\n", AD7716_get_icount ());
;	
;	printf ("AD7716 Inferred data:\n");
;	pushed = ((long)(SPI_buffer.next_in)-(long)(SPI_buffer.data_start))/sizeof(long); 
;	printf (" AD7716: number of words pushed = %ld\n", pushed);
;	pulled = ((long)(SPI_buffer.next_out)-(long)(SPI_buffer.data_start))/sizeof(long); 
;	printf (" AD7716: number of words pulled = %ld\n\n", pulled);
;	printf ("Actual data:\n");
;	sets_pulled = pulled/2;
;	if (sets_pulled >= 3)  {
;		start = sets_pulled - 3;
;		stop = sets_pulled + 1;
;	}  else  {
;		start = 0;
;		stop = 4;
;	}
;
;    /*
;	start = 0;
;	stop = 4;
;	data_index = start*2*AD7716.n_channels;		
;	for (set = start;  set < stop;  set += 1)  {
;		for (m = 0;  m < 8;  m++)  {
;			if (m == 0)
;				printf (" AD7716: ");
;			else
;				printf ("         ");	 
;			printf ("SPI[%ld] = 0x%04X;", m+set*8L, SPI_copy[m+set*8L]);
;			switch (m)  {
;				case 0:
;				case 1:
;					if (AD7716.save_channels&0x01)  {
;						printf ("  data[%ld] = 0x%04X",
;							 data_index, SPI_buffer.data_start[data_index]);
;						if ((m%2) != 0)  {
;							printf (";  value = 0x%08lX\n", (long)
;								AD7716_data_to_long (SPI_buffer.data_start[data_index-1],
;														SPI_buffer.data_start[data_index]));
;						}  else
;							printf ("\n");
;						data_index++;
;					}  else
;						printf ("\n");
;					break;
;					
;				case 2:
;				case 3:
;					if (AD7716.save_channels&0x02)  {
;						printf ("  data[%ld] = 0x%04X",
;							 data_index, SPI_buffer.data_start[data_index]);
;						if (m%2 != 0)  {
;							printf (";  value = 0x%08lX\n", (long)
;								AD7716_data_to_long (SPI_buffer.data_start[data_index-1],
;														SPI_buffer.data_start[data_index]));
;						}  else
;							printf ("\n");
;						data_index++;
;					}  else
;						printf ("\n");
;					break;
;					
;				case 4:
;				case 5:
;					if (AD7716.save_channels&0x04)  {
;						printf ("  data[%ld] = 0x%04X",
;							 data_index, SPI_buffer.data_start[data_index]);
;						if (m%2 != 0)  {
;							printf (";  value = 0x%08lX\n", (long)
;								AD7716_data_to_long (SPI_buffer.data_start[data_index-1],
;														SPI_buffer.data_start[data_index]));
;						}  else
;							printf ("\n");
;						data_index++;
;					}  else
;						printf ("\n");
;					break;
;					
;				case 6:
;				case 7:
;					if (AD7716.save_channels&0x08)  {
;						printf ("  data[%ld] = 0x%04X",
;							 data_index, SPI_buffer.data_start[data_index]);
;						if (m%2 != 0)  {
;							printf (";  value = 0x%08lX\n", (long)
;								AD7716_data_to_long (SPI_buffer.data_start[data_index-1],
;														SPI_buffer.data_start[data_index]));
;						}  else
;							printf ("\n");
;						data_index++;
;					}  else
;						printf ("\n");
;					break;
;					
;				default:
;					printf ("\n");
;			}			
;		}		
;	}															
;	*/
;}
;#endif	
;
;
;void AD7716_icount_print (void)  {
# 2149
| .95
	xdef	_AD7716_icount_print
_AD7716_icount_print:
;	printf ("interrupt count is %ld\n", AD7716.icounter);
^	move.l	_AD7716+8,-(sp)
	pea	.81+0
	jsr	_printf
;	printf ("data push counter is %ld\n", AD7716.data_pushed);
^	move.l	_AD7716+12,-(sp)
	pea	.81+24
	jsr	_printf
;}
^	lea	16(sp),sp
.96
	rts
.95
.81
	dc.b	105,110,116,101,114,114,117,112,116,32,99,111,117,110,116
	dc.b	32,105,115,32,37,108,100,10,0,100,97,116,97,32,112
	dc.b	117,115,104,32,99,111,117,110,116,101,114,32,105,115,32
	dc.b	37,108,100,10,0
	ds	0
;	
;
# 2153
|
~ 'SPI_buffer'
~ 3 6 22
~ data_start 0 "#l"
~ n_points 4 "l"
~ data_end 8 "#l"
~ next_in 12 "#l"
~ next_out 16 "#l"
~ overflow 20 "i"
~ _SPI_buffer * ":" 3
~ 'AD7716'
~ 4 19 64
~ AD7716_open_flag 0 "i"
~ convert_rate 2 "i"
~ save_channels 4 "i"
~ n_channels 6 "i"
~ icounter 8 "L"
~ data_pushed 12 "L"
~ start_time 16 ":" 2
~ measured_rate 24 "d"
~ rate_calc_threshold 32 "l"
~ n_to_average 36 "i"
~ c0_total 38 "l"
~ c1_total 42 "l"
~ c2_total 46 "l"
~ c3_total 50 "l"
~ c0_n_averaged 54 "i"
~ c1_n_averaged 56 "i"
~ c2_n_averaged 58 "i"
~ c3_n_averaged 60 "i"
~ SPI_finished 62 "i"
~ _AD7716 * ":" 4
~ _AD7716_filter_chan_three * "(v"
~ _AD7716_filter_chan_two * "(v"
~ _AD7716_filter_chan_one * "(v"
~ _AD7716_filter_chan_zero * "(v"
~ _AD7716_software_SPI_write * "(v"
~ _AD7716_program_hardware * "(v"
~ _AD7716_data_saved * "(i"
~ _AD7716_interrupt_serviced * "(i"
~ _AD7716_push_data_to_buff * "(v"
~ _AD7716_data_to_long * "(l"
~ _AD7716_rupt_handler * "(v"
~ _AD7716_command * "(v"
~ _AD7716_reset * "(v"
~ _AD7716_SPI_read_data * "(v"
~ _AD7716_SPI_rupt_handler * "(v"
~ _AD7716_SPI_master_in * "(v"
~ _AD7716_SPI_master_out * "(v"
~ _AD7716_SPI_interface_init * "(v"
~ _AD7716_SPI_buffer_empty * "(v"
~ _AD7716_SPI_buffer_delete * "(v"
~ _AD7716_SPI_buffer_open * "(i"
~ _log_printf * "(i"
~ 'text_log'
~ 5 5 1068
~ filename 0 "[32c"
~ data 32 "[1024c"
~ n_data 1056 "i"
~ n_filled 1058 "i"
~ oldest_data 1060 ":" 2
~ _logger_time_get_time * "(:" 2
~ EARLIEST_LOGGER_TIME _EARLIEST_LOGGER_TIME ":" 2
~ LATEST_LOGGER_TIME _LATEST_LOGGER_TIME ":" 2
~ _AD7716_icount_print * "(v"
~ _AD7716_get_n_waiting * "(l"
~ _AD7716_get_icount * "(L"
~ _AD7716_clear_overflow * "(v"
~ _AD7716_check_for_overflow * "(i"
~ _AD7716_get_data_point_time * "(:" 2
~ _AD7716_get_channel_num * "(i"
~ _AD7716_get_data_point * "(i"
~ _AD7716_resume_data * "(v"
~ _AD7716_pause_data * "(v"
~ _AD7716_stop_data * "(v"
~ _AD7716_start_data * "(v"
~ _AD7716_get_n_channels * "(i"
~ _AD7716_get_channels * "(i"
~ _AD7716_set_channels * "(v"
~ _AD7716_get_conversion_rate * "(d"
~ _AD7716_set_averaging * "(i"
~ _AD7716_set_conversion_rate * "(d"
~ _AD7716_close * "(v"
~ _AD7716_open * "(i"
~ _AD7716_turn_power_on * "(v"
~ _AD7716_turn_power_off * "(v"
~ _AD7716_power_on_init * "(v"
~ _fabs * "(d"
~ ''
~ 6 2 8
~ quot 0 "l"
~ rem 4 "l"
~ ''
~ 7 2 4
~ quot 0 "i"
~ rem 2 "i"
~ _malloc * "(#v"
~ _free * "(v"
~ ldiv_t ":" 6
~ div_t ":" 7
~ '__stdio'
~ 8 8 22
~ _bp 0 "#C"
~ _bend 4 "#C"
~ _buff 8 "#C"
~ _flags 12 "I"
~ _unit 14 "c"
~ _bytbuf 15 "C"
~ _buflen 16 "L"
~ _tmpnum 20 "I"
~ _printf * "(i"
~ FILE ":" 8
~ fpos_t "l"
~ va_list "#c"
~ ''
~ 9 13 46
~ libVersion 0 "l"
~ ramBase 4 "#c"
~ ramSize 8 "l"
~ ramWaits 12 "i"
~ flashBase 14 "#c"
~ flashSize 18 "l"
~ flashWaits 22 "i"
~ heapBot 24 "#v"
~ heapTop 28 "#v"
~ heapCur 32 "#v"
~ statusReg 36 "I"
~ vectorBase 38 "#v"
~ stackPtr 42 "#v"
~ infoAction "c"
~ TT8info ":" 9
~ _TPUSetPin * "(v"
~ UeeErr "c"
~ _GetTickRate * "(l"
~ _ttmcmp * "(l"
~ time_tt ":" 2
~ XmdmErr "c"
~ FlashErr "c"
~ _InstallHandler * "(#(v"
~ ''
~ 10 4 24
~ eSR 0 "I"
~ ePC 2 "L"
~ vectofs 6 "I"
~ states 8 "[8I"
~ ExcCFramePtr "#:" 1
~ ExcCFrame ":" 1
~ ExcStackFrame ":" 10
~ 'tm'
~ 11 10 20
~ tm_sec 0 "i"
~ tm_min 2 "i"
~ tm_hour 4 "i"
~ tm_mday 6 "i"
~ tm_mon 8 "i"
~ tm_year 10 "i"
~ tm_wday 12 "i"
~ tm_yday 14 "i"
~ tm_isdst 16 "i"
~ tm_hsec 18 "i"
~ time_t "L"
~ clock_t "L"
~ wchar_t "c"
~ ptrdiff_t "l"
~ size_t "L"
~ bool "c"
~ vfptr "#(v"
~ ptr "#c"
~ ulpv "#L"
~ ulong "L"
~ uspv "#I"
~ unsint "I"
~ ushort "I"
~ ucpv "#C"
~ uchar "C"
	xref	_log_printf
	xref	_logger_time_get_time
	xref	_fabs
	xref	_malloc
	xref	_free
	xref	_printf
	xref	_TPUSetPin
	xref	_GetTickRate
	xref	_ttmcmp
	xref	_InstallHandler
	xref	.begin
	dseg
	global	_SPI_buffer,22
	global	_AD7716,64
	end
