/*
 * l16bitio.h
 * 
 * Latch16Bit (low lewel) IO routines. 
 * Driver for the Latch16Bit board. 
 * 
 * Copyright (c) 2003 by Wolfgang Wieser (wwieser@gmx.de) 
 * 
 * This file may be distributed and/or modified under the terms of the 
 * GNU General Public License version 2 as published by the Free Software 
 * Foundation. 
 * 
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 * 
 */

#ifndef _LATCH16BITIO_H_
#define _LATCH16BITIO_H_

#include "lpportio.h"

#include <stdio.h>  // for NULL,... uh


// This is the basic Latch-16bit IO driver. 
// It uses class LPPortIO for the low level port IO. 
// You may specify which lines are used as "strobe" and "control select" 
// on the latch16bit board. 
// Positive logic is assumed (i.e. bit set means HIGH level on the board). 
class Latch16BitIO
{
	public:
		enum
		{
			WCDoSave=0x01,
			WCDoRestore=0x02,
			WCSetData=0x04,
		};
		
	private:
		// These are the data bits to be set/cleared for the control 
		// latch on the latch16bit board: 
		enum
		{
			L_OA_TRANSP= 0x01,   /* out port A: H=transparent, L=latch */
			L_OB_TRANSP= 0x04,   /* out port B: H=transparent, L=latch */
			L_OA_HIGHZ=  0x40,   /* out port A: H=high Z, L=output on */
			L_OB_HIGHZ=  0x10,   /* out port B: H=high Z, L=output on */
			L_IA_TRANSP= 0x20,   /* in port A: H=transparent, L=latch */
			L_IB_TRANSP= 0x80,   /* in port B: H=transparent, L=latch */
			L_IA_BUSEN=  0x08,   /* in port A: H=output enable, L=high Z */
			L_IB_BUSEN=  0x02    /* in port B: H=output enable, L=high Z */
		};
		
		LPPortIO *pio;  // low level port access class
		
		// "strobe" and "control select" bits for the board; 
		// positive logic (set bit on port means HIGH level). 
		// Note that the L_CTLSEL is also used as data direction 
		// flag: when LPPortIO::C_INPEN is set, data direction is 
		// INPUT, otherwise it is OUTPUT. 
		uchar L_STROBE;
		uchar L_CTLSEL;
		
		// Currently set control bits (at the control latch): 
		// (Do not mix up with LPPortIO::control_bits which is the 
		// lp port control register content.) 
		uchar control_bits;
		
		// Set control latch output to a specified value: 
		// val is stored in control_bits. 
		// do_save_restore: controls whether the data bits shall 
		// be saved and/or restored; OR of WCDoSave, WCDoRestore, 
		// WCSetData. Special value WCSetData can be used to put 
		// set_data on the data lines before taking control select 
		// high. 
		void _WriteControl(register uchar val,
			uchar do_save_restore=WCDoSave|WCDoRestore,
			uchar set_data=0x00);
		
		// Modify control bits (control latch): 
		void _SetControlBits(register uchar mask)
			{  _WriteControl(control_bits | mask);  }
		void _ClrControlBits(register uchar mask)
			{  _WriteControl(control_bits & ~mask);  }
		void _ChgControlBits(register uchar set,register uchar clr,
			uchar do_save_restore=WCDoSave|WCDoRestore,
			uchar set_data=0x00)
			{  _WriteControl((control_bits | set) & ~clr,
				do_save_restore,set_data);  }
		
	public:
		// MUST CALL Init() after construction. 
		Latch16BitIO(LPPortIO *_pio);
		~Latch16BitIO();  // <-- calls Deactivate()
		
		// Initialize latch16bit board. You have to pass which 
		// lines are used as "strobe" and "control select". 
		// Sets board in inactive state (calling Deactivate()).  
		// Return value: 
		//   0 -> OK
		int Init(uchar strobe_line,uchar crlsel_line);
		
		// Set board in inactive state; disable all outputs, 
		// make all latches non-transparent. 
		void Deactivate()
			{  _WriteControl(L_OA_HIGHZ|L_OB_HIGHZ);  }
		
		// Note: for single input/output operations, functions 
		// further down may be more apropriate. 
		
		// Control the channel output, i.e. if the channels 
		// A and/or B shall be in high Z state. 
		// channel: 1 -> channel A, 2 -> channel B, 3 -> both
		// enable: 0 -> high Z; 1 -> enable output
		void CtlChannelOutput(int channel,uchar enable);
		
		// Make output channel transparent or non-transparent. 
		// Once the channel is transparent, you can use 
		// DataOutb() to put data on the chanel (provided that 
		// it was enbled using CtlChannelOutput()). 
		// channel: 1 -> channel A, 2 -> channel B, 3 -> both
		// transparent: 0 -> latched; 
		//              1 -> transparent; also set data direction to OUTPUT 
		void CtlOutChannelTransparent(int channel,uchar transparent);
		
		// Simply put the passed value on the data bus. 
		// Mainly useful if some output channel was made transparent. 
		// Must make sure that data direction was set to OUTPUT (e.g. by 
		// CtlOutChannelTransparent()). 
		inline void DataOutb(register uchar x)
			{  pio->data_outb(x);  }
		
		// Control the input channel latch outputs (i.e. which latch 
		// may send data to the bus). Be sure to switch that off 
		// before attempting to write data to the bus. 
		// This also writes 0 to the bus if any channel was selected. 
		// channel: 
		//    0 -> select no channel
		//    1 or 2 -> select channel A or B
		void SelectInputChannel(int channel);
		
		// Make input channel transparent or non-transparent. 
		// Once the channel is transparent, you can use 
		// DataInb() to get data from the chanel (provided that 
		// you put this channel on the bus using SelectInputChannel()). 
		// channel: 1 -> channel A, 2 -> channel B, 3 -> both
		// transparent: 0 -> latched; 
		//              1 -> transparent; also set data direction to INPUT
		void CtlInChannelTransparent(int channel,uchar transparent);
		
		// Simply read input data. Must make sure data direction was 
		// set to INPUT by using CtlInChannelTransparent(). 
		inline uchar DataInb()
			{  return(pio->data_inb());  }
		
		// No matter which state we're currently in, switch to 
		// reading the data which is currently present on the 
		// specified input channel (which may require making that 
		// latch transparent) and switch back to the previous state. 
		// channel: 1 or 2 -> channel A or B
		// disable_out: disable corresponding output channel while 
		//    reading (useful if in and out channel are connected 
		//    for bus IO). 
		uchar ReadSingleByte(int channel,uchar disable_out=0);
		
		// This is just like ReadSingleByte(), i.e. independent of 
		// the state. Will write the passed byte and latch it in 
		// the specified output latch(es). It will NOT enable the 
		// output latch's output; you have to do that using 
		// CtlChannelOutput(). 
		// NOTE that after a call to WriteSingleByte() the byte 
		//  will stay latched in the specified channel(s), so the 
		//  state may not be completely the same as before (i.e. 
		//  the specified channel is no longer transparent). 
		// channel: 1 -> A, 2 -> B, 3 -> both
		void WriteSingleByte(int channel,uchar byte);
};

#endif  /* _LATCH16BITIO_H_ */

