/*---------Copyright (C) 1992 Dallas Semiconductor Corporation--------------
 *
 * TOUCHIO2.C - C program module containing Low level I/O 1-Wire
 *             functions for DALLAS Touch devices.
 *
 *     'setup' initializes the com port for use.
 *
 *     'TouchReset','TouchByte' and 'TouchBit' are Link-Level 1-Wire
 *           routines.
 *
 *     'Finddevices','RomData'are Network-Level 1-Wire routines.
 *
 *     'crc16' and 'dowcrc' are cyclic redundancy routines.
 *
 * Compiler: Borland C++ Builder
 *
 */

#include <vcl.h>
#include <time.h>
#include <io.h>
#include <winbase.h>

#define FALSE        0
#define TRUE         1
#define SAMPLE_T     0xFE   // Sampling at ~20uS


#define DTR_ON      0x01
#define RTS_ON      0x02
#define DTR_RTS_ON  0x03
#define DTR_RTS_OFF 0x00

#define DATA_READY  0x01

unsigned char receive_zero_val;
char *const com_poort[] =
{
"    ",
"COM1",
"COM2",
"COM3",
"COM4",
"COM5",
"COM6",
"COM7",
"COM8"
};

DCB dcb;

/* External Variables declared in calling program */
extern int   com_port;
unsigned int  CRC16;
unsigned char DOWCRC;

/* Function Prototypes */
int SetupPort( unsigned char );
int TouchByte( unsigned char );
int TouchReset( void );
int TouchBit(unsigned char);
unsigned char FindDevices( void );
unsigned char * RomData( void );
unsigned int  crc16(int);
unsigned char dowcrc(unsigned char);

void control_rts_dtr();
int  read_rts_dtr();
unsigned char inportb(unsigned short int port);
void outportb(unsigned short int port, unsigned char value);
void CloseComport();

/* Global Variables for TOUCHIO.C */
HANDLE channel;

unsigned char ROM[8];
unsigned char LD = 0;  								/* Last bit discrepancy in previous Next */
static unsigned char LastOne    = 0;
static unsigned char to_rts_dtr = 0;

unsigned short int SPA;
clock_t M;


/*--------------------------------------------------------------------------
 * The setup functions makes sure that the com port number passed to it
 * is from 1 to 8 and has a valid address associated with it.
 */
int SetupPort(unsigned char ComPort)
{
	switch(ComPort)
	{
		case 1: SPA = 0x3F8;
						break;
		case 2: SPA = 0x2F8;
						break;
		case 3: SPA = 0x3E8;
						break;
		case 4: SPA = 0x2E8;
						break;
		case 5: SPA = 0x268;
						break;
		case 6: SPA = 0x3E0;
						break;
		case 7: SPA = 0x2E0;
						break;
		case 8: SPA = 0x260;
						break;
	}
															// check to see if it is a valid com port number and address
	if (ComPort < 1 || ComPort > 8 || !SPA )
		return FALSE;

    channel = CreateFile(com_poort[ComPort],
    	        GENERIC_READ | GENERIC_WRITE,
    	        0,                      // exclusive access
    	        NULL,                   // no security attrs
        	    OPEN_EXISTING,
    	        FILE_ATTRIBUTE_NORMAL,  //FILE_FLAG_OVERLAPPED,
    	        NULL
    	        );

    if(channel == INVALID_HANDLE_VALUE)
    {
	    return false;               // Deal with the error.
    }
	else
    {
	    if(!GetCommState(channel, &dcb))
        {
	        CloseHandle(channel);
            return false;
		}
    }
	outportb((unsigned short)(SPA+3),0x87);  		// set DLAB
	outportb(SPA  ,0x01);  		                    // bit rate is 115200
	outportb((unsigned short)(SPA+3),0x07);  		// 8 dta, 2 stp, no par
	outportb((unsigned short)(SPA+1),0x00);  		// no interrupts

	control_rts_dtr();

	return TRUE;
}


void control_rts_dtr()
{
	to_rts_dtr = 0x03;
	outportb((unsigned short)(SPA+4),to_rts_dtr);
}

int read_rts_dtr()
{
	return (int)inportb((unsigned short)(SPA+4));
}

/*--------------------------------------------------------------------------
 * Do a reset on the 1 wire port and return  0 no presence detect
 *                                           1 presence pulse no alarm
 *                                           2 alarm followed by a presence
 *                                           3 short circuit to ground
 *                                           4 no com port found
 *                                           5 timed out!!
 * The global variable 'com_port' must be set to the com port that
 * the serial brick is attached to before calling this routine.
 *
 */
int TouchReset( void )
{
	int X,Y,tmp,trst=1;

	M = clock() + 100;     							// Initialize the time limit 1mS steps
	while ((inportb(SPA+5) & DATA_READY) && (clock() <= M) )
    {                                               // Flush input
        X = inportb(SPA);
    }
	outportb((unsigned short)(SPA+3),0x83);  		// set DLAB
	outportb((unsigned short)(SPA+1),0x00);  		// baud rate is 9600
	outportb(SPA,0x0C);   							// Low time is 5x104uS = 520uS
	outportb((unsigned short)(SPA+3),0x03);  		// 8 dta, 1 stp, no par
 	outportb(SPA,0xF0);  						 	// send the reset pulse

	do                     							// wait until character back or timeout
	{
		Y = inportb((unsigned short)(SPA+5));
	}
	while( !(Y & DATA_READY) && (clock() <= M) );

	if((Y & DATA_READY) && (Y != 0xFF))
		X = inportb(SPA);
	else
		return 5;

	if (X != 0xF0)       								// if more bits back than sent then there is a
	{                    								// device  if framing error or break
	    trst = 1;
 		if ( (Y & 0x18) != 0 )
		{
			trst = 2;
            do                      					// loop to clear the buffers
			{
				tmp = inportb((unsigned short)(SPA+5)) & 0x60;
			} while ((tmp != 0x60) && (clock() <= M));

			do                						   	// wait until character back or timeout
			{
				Y = inportb((unsigned short)(SPA+5));
			} while ( !(Y & DATA_READY) && (clock() <= M) );

			if (Y & DATA_READY)
				X = inportb(SPA);
			else
				return 3;
		}
	}
	else
	{
	    trst = 0;
	}

	outportb((unsigned short)(SPA+3),0x87);  			// set DLAB
	outportb(SPA  ,0x01);  								// 0x01  bit rate is 115200
	outportb((unsigned short)(SPA+3),0x07);  			// 8 dta, 2 stp, no par

	return trst;
}

/*-----------------------------------------------------------------------
 * This is the 1-Wire routine 'TouchByte' or sometimes called 'databyte'.
 * It transmits 8 bits on to the 1-Wire data line and receives 8 bits
 * concurrently. The comport must be set to 115200 baud, 8 dta, 1 stp,
 * and no parity.  This routine returns the unsigned char 8 bit value received.
 * If it times-out waiting for a character then -1 is returned.
 */

int TouchByte(unsigned char outchar)
{
	unsigned char inchar=0,sendbit,Mask=1,receivebyte;

	M = clock() + 100;        									// Initialize the time limit
	do
	{
		if ( clock() > M )    									// return if out of time
			return -1;
	}
	while ( (inportb((unsigned short)(SPA+5)) & 0x60) != 0x60 ); // wait to TBE and TSRE

	while ( (inportb((unsigned short)(SPA+5)) & DATA_READY) ) 	// flush input
	{
		inportb(SPA);
		if ( clock() > M )    									// return if out of time
			return -1;
	}

	do                        							// loop to send and receive 8 bits
	{
		sendbit = (outchar & Mask) ? 0xFF : 0x80;

		outportb(SPA,sendbit);  							// send out the bit

		Mask <<= 1;             							// get next bit ready to go out

		inchar >>= 1;           							// shift input char over ready for next bit

		for (;;)                							// loop to look for the incoming bit
		{
			if ( inportb((unsigned short)(SPA+5)) & DATA_READY )
			{
				receivebyte = inportb(SPA); 			// the input byte

				if(receivebyte > SAMPLE_T)  			// Sample at 2,5 T
					inchar |= 0x80;
				else
				{
					if(receivebyte > 0xE0)
						receive_zero_val = receivebyte;
					inchar &= ~0x80;
				}
				break;                            // Byte received break for() loop
			}
			if ( clock() > M )    							// return if out of time
				return -1;
		}

	} while (Mask);

	return inchar;   													// return the input char
}


/*--------------------------------------------------------------------------
 * This is the 1-wire routine 'TouchBit'.  It is used in the search rom
 * and match rom operations.  It sends out one bit on the 1-wire and
 * returns one bit. The comport must be set to 115200 baud, 8 dta, 1 stp,
 * and no parity.  If this routine times-out waiting for the bit character
 * then -1 is returned.
 */
int TouchBit(unsigned char outbit)
{
	unsigned char sendbit,receivebit,receivebyte;


	M = clock() + 100;        									// Initialize the time limit
	do
	{
		if ( clock() > M )    									// return if out of time
			return -1;
	}
	while ( (inportb((unsigned short)(SPA+5)) & 0x60) != 0x60 );// wait to TBE and TSRE

	while ( (inportb((unsigned short)(SPA+5)) & DATA_READY) ) 	// flush input
	{
		inportb(SPA);
		if ( clock() > M )    									// return if out of time
			return -1;
	}

	sendbit = (outbit & 0x1) ? 0xFF : 0x80; 	// get bit ready to go out

	outportb(SPA,sendbit);  									// send out the bit

	for (;;)                          				// loop to look for the incoming bit
	{
		if( inportb((unsigned short)(SPA+5)) & DATA_READY )
		{
			receivebyte = inportb(SPA); 					// return the input byte
			if(receivebyte > SAMPLE_T)  					// Sample at 2,5 T
				receivebit = 1;
			else
			{
				receivebit = 0;
			}
			return (receivebit);
		}
		if( clock() > M )    										// return if out of time
			return -1;
	}
}



/*--------------------------------------------------------------------------
 * This function searchs for the next device on the 1-wire. 
 */
unsigned char FindDevices( void )
{
	unsigned char Bit=1,Byte=0,Mask=1,LO=0,G,NXT;
	unsigned char ROMNEW[8];

	int i, x;
	int tries;

	NXT    = FALSE;   			// set the next flag to false
	DOWCRC = 0;     		    // reset the DOWCRC
																// if the last call was not the last one
	tries = 0;                  // bij een storing probeer een aantal keren
	if (!LastOne)
	{
Storing:
		Bit=1;Byte=0;Mask=1;LO=0;DOWCRC=0;NXT=FALSE;
		x = TouchReset();				// reset the 1-wire

		if ((x == 0 || x == 5))
		{               				// if there are no parts or alarming parts on 1-wire, return FL
			LD = 0;       				// reset the search
			return FALSE;
		}
//		TouchReset();					// reset the 1-wire
//		TouchReset();					// reset the 1-wire

		if(TouchByte(0xF0) == -1)       // issue the search rom command
		{
			goto Storing;
		}

		do                   			// loop to do the search rom at the bus
		{
			x  = TouchBit(1) << 1;	    // read a bit and its compliment
			x |= TouchBit(1);

			if (x == 3)				   	// there are no devices on 1-wire
			{
				if(tries++ > 20)
					break;              // Teveel storing
				else
					goto Storing;
			}
			else
			{
				if (x > 0)           	// all devices coupled have 0 or 1
					G = !(x & 0x01);  	// bit write value for search
				else
				{
																// if this discrepancy if before the Last Discrepancy
																// on a previous next then pick the same as last time
					if (Bit < LD)
						G = ((ROM[Byte] & Mask) > 0);
					else              	// if equal to last pick 1
						G = (Bit == LD);// if not then pick 0

																// if 0 was picked then record its position in LO
					if (G == 0) LO = Bit;
				}

				if (G == 1)             // set or clear the bit in the ROM byte J with mask K
					ROMNEW[Byte] |= Mask;
				else
					ROMNEW[Byte] &= ~Mask;

				G = TouchBit(G);        // rom search write

				Bit++;                  // increment the byte counter I and shift the mask K
				Mask = Mask << 1;

				if (Mask == 0)          // if the mask is 0 then go to new ROM byte J and reset mask
				{
					dowcrc(ROMNEW[Byte]);	// accumulate the CRC
					Byte++;             // Next byte in the ROM-code
					Mask = 1;           // Mask byte
				}
			}
		} while(Byte < 8);     		    // loop until through all ROM bytes 0-7

		if (Bit < 65 || DOWCRC)         // if the search was unsuccessful then
			LD = 0;              		// reset the Last Discrepancy to 0
		else
		{
																// search successful to set LD,LastOne,NXT
			LD = LO;
			LastOne = (LD == 0);
			NXT = TRUE;
			for(i=0;i<8;i++)
				ROM[i] = ROMNEW[i];     // ROM[x] is used by the program
		}
	}
																// if no device found then reset counters so next 'next' will be
																// like a first
	if (!NXT)
	{
		LD = 0;
		LastOne = FALSE;
	}
	return NXT;
}

// The folowing routine access some resources directly
// it only works under WINDOWS 95 / 98, not under NT!!
// It returns from a given port-address a value
unsigned char inportb(unsigned short int port)
{
  unsigned char value;
  __emit__(0x8b, 0x95, &port);
  __emit__(0x66, 0xec);
  __emit__(0x88, 0x85, &value);
  return value;
}

// The folowing routine access some resources directly
// it only works under WINDOWS 95 / 98, not under NT!!
// It gives a port-address a value
void outportb(unsigned short int port, unsigned char value)
{
  __emit__(0x8b, 0x95, &port);
  __emit__(0x8a, 0x85, &value);
  __emit__(0x66, 0xee);
}

void CloseComport()
{
    CloseHandle(channel);
}


/*--------------------------------------------------------------------------
 * The 'RomData' function returns the pointer to the ROM DATA.
 */
unsigned char * RomData( void )
{
	return &ROM[0];
}


/*--------------------------------------------------------------------------
 * Calculate a new CRC16 from the input data integer.  Return the current
 * CRC16 and also update the global variable CRC16.
 */
static int oddparity[16] = { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 };

unsigned int crc16(int data)
{
	data = (data ^ (CRC16 & 0xff)) & 0xff;
	CRC16 >>= 8;

	if (oddparity[data & 0xf] ^ oddparity[data >> 4])
		CRC16 ^= 0xc001;

	data <<= 6;
	CRC16 ^= data;
	data <<= 1;
	CRC16 ^= data;

	return CRC16;
}


unsigned char dscrc_table[] = {
				0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65,
			157,195, 33,127,252,162, 64, 30, 95,  1,227,189, 62, 96,130,220,
			 35,125,159,193, 66, 28,254,160,225,191, 93,  3,128,222, 60, 98,
			190,224,  2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255,
			 70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89,  7,
			219,133,103, 57,186,228,  6, 88, 25, 71,165,251,120, 38,196,154,
			101, 59,217,135,  4, 90,184,230,167,249, 27, 69,198,152,122, 36,
			248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91,  5,231,185,
			140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205,
			 17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80,
			175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238,
			 50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115,
			202,148,118, 40,171,245, 23, 73,  8, 86,180,234,105, 55,213,139,
       87,  9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22,
      233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168,
      116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53};


/*--------------------------------------------------------------------------
 * Update the Dallas Semiconductor One Wire CRC (DOWCRC) from the global
 * variable DOWCRC and the argument.  Return the updated DOWCRC.
 */
unsigned char dowcrc(unsigned char x)
{
   DOWCRC = dscrc_table[DOWCRC ^ x];
   return DOWCRC;
}



