/******************************************************************************\
**	Max146.c				QPB Driver for MAX146/147 SPI A-D		
**	
**	First release:			Sunday, May 17, 1998
**	1.2 release:			Monday, September 14, 1998
*****************************************************************************
**	
**	Licensed by:	Persistor Instruments Inc. for the Peristor CF1
**	info@persistor.com - http://www.persistor.com
**	
*****************************************************************************
**	
**	Developed by:	John H. Godley dba Peripheral Issues
**	jhgodley@periph.com - http://www.periph.com
**	Copyright (C) 1996-1998 Peripheral Issues.	All rights reserved.
**	
*****************************************************************************
**	
**	Copyright and License Information
**	
**	Peripheral Issues (hereafter, PERIPH) grants you (hereafter, Licensee)
**	a non-exclusive, non-transferable license to use the software source
**	code contained in this single source file. Licensee may distribute
**	binary derivative works using this software to third parties without
**	fee or restrictions.
**	
**	PERIPH MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
**	BINARY SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
**	THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
**	PURPOSE, OR NON-INFRINGEMENT. PERIPH SHALL NOT BE LIABLE FOR ANY DAMAGES
**	SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE
**	BINARY SOFTWARE OR ITS DERIVATIVES.
**	
**	By using or copying this Software, Licensee agrees to abide by the
**	copyright law and all other applicable laws of the U.S. including, but
**	not limited to, export control laws, and the terms of this license. PERIPH
**	shall have the right to terminate this license immediately by written
**	notice upon Licensee's breach of, or non-compliance with, any of its
**	terms. Licensee may be held legally responsible for any copyright
**	infringement or damages resulting from Licensee's failure to abide by
**	the terms of this license. 
**	
\******************************************************************************/

#include	<cf1bios.h>		// Persistor CF1 BIOS and I/O Definitions
#include	<cf1pico.h>		// Persistor CF1 PicoDOS Definitions
#include	<Max146.h>		// MAX146/147 SPI A-D QPB Driver for CF1 


const uchar Max146SglChSel[8] = 	// convert chan to single-ended selector
		{ 0x00, 0x40, 0x10, 0x50, 0x20, 0x60, 0x30, 0x70 };
const uchar Max146DifChSel[8] = 	// convert chan to differential selector
		{ 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70 };

/******************************************************************************\
**	Max146Init		Initialize a Max146 QPB slot
\******************************************************************************/
bool Max146Init(ushort qslot)
	{

	if (qslot >= QPBSLOTS)		// sanity check
		return false;

	MAX146DevTemplate.qslot = qslot;	// the one template field we must fill
	Max146Table[qslot] = QPBInitSlot(&MAX146DevTemplate);

	return true;

	}	//____ Max146Init() ____//


/******************************************************************************\
**	Max146Lock		Lock the QPB for exclusive A-D use
\******************************************************************************/
bool Max146Lock(ushort qslot)
	{

	return QPBLockSlot(Max146Table[qslot]);
	
	}	//____ Max146Lock() ____//


/******************************************************************************\
**	Max146Unlock	Unlock the QPB for exclusive A-D use
\******************************************************************************/
bool Max146Unlock(ushort qslot)
	{

	return QPBUnlockSlot(Max146Table[qslot]);

	}	//____ Max146Unlock() ____//


/******************************************************************************\
**	Max146Sample		Sample the specified channel and return the raw results
\******************************************************************************/
short Max146Sample(ushort qslot, ushort chan, bool uni, bool sgl, bool pd)
	{
	ushort		adcmd[3];
	short		count = 2;

//	Setup the command word we send to the Max146 which is a combination of
//	selector bits that pick the channel, mode, and clocking.
	adcmd[0] = adcmd[1] =
			 		(sgl	? (Max146SglChSel[chan] | Max146SGL)
							: (Max146DifChSel[chan] | Max146DIF))
				|	(uni	? Max146UNI : Max146BIP)
				|	Max146CMD;

	adcmd[0] |= Max146EXT;
	if (pd)
		{
		adcmd[1] |= Max146PDFast;
		adcmd[count++] = 0;
		}
	else
		adcmd[1] |= Max146EXT;
		
//	Perform a QSPI transaction with two transfers, the first sets up the next
//	conversion, and the second value clocks out the previous channel results.
//	We don't set the QPBASync bit in the command count so the function will
//	wait for the conversion to complete before returning.

	QPBTransact(Max146Table[qslot], 0, count, adcmd);
//	The rcvData array contains the real result in its second word since word
//	one is the result of some previous conversion.

	return Max146Table[qslot]->dev->rcvData[1];

	}	//____ Max146Sample() ____//


/******************************************************************************\
**	Max146Repeat		Sample quickly repeating last Max146Sample parameters
\******************************************************************************/
short Max146Repeat(ushort qslot)
	{
		
	if (QPBTransact(Max146Table[qslot], 0, 0, 0) < 0)
		return -1;		// didn't work

	return Max146Table[qslot]->dev->rcvData[1];

	}	//____ Max146Sample() ____//


/******************************************************************************\
**	Max146SampleBlock	Sample multiple channels and return a pointer to array
\******************************************************************************/
short *Max146SampleBlock(ushort qslot, ushort first, ushort count, 
	 vfptr asyncf, bool uni, bool sgl, bool pd)
	{
	short			i, j;
	ushort			adcmd[10];
	
//	Setup the command words we send to the Max146 which is a combination of
//	selector bits that pick the channel, mode, and clocking.
//	for (i = first; i < count; i++)		// 98/09/13 bug --jhg
	for (i = 0, j = first; i < count; i++, j++)
//		adcmd[i] =	(sgl	? (Max146SglChSel[i] | Max146SGL)
//							: (Max146DifChSel[i] | Max146DIF))
		adcmd[i] =	(sgl	? (Max146SglChSel[j] | Max146SGL)
							: (Max146DifChSel[j] | Max146DIF))
						|	(uni	? Max146UNI : Max146BIP)
						|	Max146CMD
						|	Max146EXT;
//	If one of the power down modes is requested, we'll need to add one
//	final cycle of zero data to clock out the final conversion and let
//	the converter drop into low power mode.
	if (pd)
		{
		adcmd[count++] = Max146CMD | Max146PDFast;	// just clocks in previous data
		adcmd[count++] = 0;	// final cycle to invoke power down mode
		}
	else
		adcmd[count++] = Max146CMD | Max146EXT;		

//	Perform a QSPI transaction with count+1 transfers, the first sets up the 
//	next conversions, and the subsequent value clocks out the previous channels
//	results. By specifying a structure (not a pointer to a structure), the
//	compiler will efficiently push the appropriate parameters for the call.
	QPBTransact(Max146Table[qslot], asyncf, count, adcmd);

//	If the caller specified a completion function then the results will have
//	to wait until the series of conversions completes and thier function gets
//	called to collect the data asynchronously.
	if (asyncf)
		return 0;

//	Return a pointer to the second entry in the results array. Remember the
//	first value is garbage from some previous conversion.
	return &Max146Table[qslot]->dev->rcvData[1];
	
	}	//____ Max146SampleBlock() ____//


/******************************************************************************\
**	Max146PowerDown		Put the Max146 into power down mode
**	
**	Use Max146PDFull for full powerdown, but up to 20ms wake recovery
**	Use Max146PDFast for full powerdown, but up to 20ms wake recovery
\******************************************************************************/
void Max146PowerDown(ushort qslot, bool pdfull)
	{
	ushort			adcmd[2];		// requires two commands ...

	// first, tell it which power down mode
	adcmd[0] = Max146CMD | (pdfull ? Max146PDFull : Max146PDFast);
	adcmd[1] = 0;	// next, send zero data and clocks to complete
	// it will power down at the end of the conversion

	QPBTransact(Max146Table[qslot], 0, 2, adcmd);
	
	}	//____ Max146PowerDown() ____//


