//=============================================================================
//=============================================================================
//
// Routines to run the XOS X-Beam Filter Wheel under Windows. Requires the GiveIo 
// device to be installed which allows port I/O access with _inp() and _outp(), 
// and thus requires NT, 2000, or XP. GiveIo is not required for Windows 3.1, 95,
// or ME. The GiveIo service can be downloaded as GiveIoNT2000XP.zip from 
// www.aethermachines.com under Software and Downloads.
//
// Copyright (c) 2005 AetherMachines Inc. This software may be freely modified
// and distributed by the end user provided AetherMachines Inc. is cited as the
// source of the original code. For instance :
//
// 0.0.0 Derived from AetherMachines original source
// 1.0.0 Added feature A
// 2.0.0 Added feature B
//
// or
//
// "The following AetherMachines Inc. code is provided free of charge"
//
// Revisions :
// ----------------------------------------------------------------------------
//
// 0.0.0 MDM Initial 9/7/05.
// 1.0.0 Changed DB-25 pin assignments as per XOS/Seiko 10/27/05 MDM.
// 1.1.0 Added dither in test steps to avoid finding the Home Sensor 
// just before moving in the opposite direction 12/12/05 MDM.
// 1.2.0 Made the step calculation floating point instead of integer 1/9/05 MDM.
//
//=============================================================================
//=============================================================================



#include <stdio.h>
#include <windows.h>
#include <math.h>
#include <conio.h>
#include <ctype.h>

#define PARALLEL_PORT_WRITE		0x378
#define PARALLEL_PORT_READ		0x379


//*****************************************************************************
// New pin definitions ...
//
//      98765432     PARALLEL PORT PINS
//      76543210     PARALLEL PORT BITS

//      00000000     CW_FALLING_EDGE
//      00000010     CW_RISING_EDGE
//      00000100     CCW_FALLING_EDGE
//      00000110     CCW_RISING_EDGE

//      00001110     INHIBIT_MOTOR


#define CCW_FALLING_EDGE		4
#define CCW_RISING_EDGE			6
#define CW_FALLING_EDGE			0
#define CW_RISING_EDGE			2

#define MAX_FILTER_NUMBER		8
#define FILTER_STEP_CONSTANT	29.143

#define INHIBIT_MOTOR			14



//*****************************************************************************
//*****************************************************************************
//
// InhibitMotor() turns off all phases of the stepper with the INH pin.
// Holding torque is then just whatever mechanical torque exists intrinsically
// in the motor; no magnetic flux is generated.
//
//
// Copyright (c) 2005 AetherMachines Inc. This software may be freely modified
// and distributed by the end user provided AetherMachines Inc. is cited as the
// source of the original code. For instance :
//
// 0.0.0 Derived from AetherMachines original source
// 1.0.0 Added feature A
// 2.0.0 Added feature B
//
// or
//
// "The following AetherMachines Inc. code is provided free of charge"
//
// Revisions :
// ----------------------------------------------------------------------------
//
// 0.0.0 MDM Initial 9/7/05.
//
//*****************************************************************************
//*****************************************************************************

void InhibitMotor(void)
{
	_outp(PARALLEL_PORT_WRITE, INHIBIT_MOTOR);

}
//*****************************************************************************
//*****************************************************************************



//*****************************************************************************
//*****************************************************************************
//
// StepCCW() takes a counter clockwise step when looking down at the filter wheel
// assembly. The negative going /STEP pulse is held high for 10ms and then 
// transitions low. PulseWait milliseconds are waited before the next step
// of multiple steps or before a single step call to StepCCW() returns.
//
//
// Copyright (c) 2005 AetherMachines Inc. This software may be freely modified
// and distributed by the end user provided AetherMachines Inc. is cited as the
// source of the original code. For instance :
//
// 0.0.0 Derived from AetherMachines original source
// 1.0.0 Added feature A
// 2.0.0 Added feature B
//
// or
//
// "The following AetherMachines Inc. code is provided free of charge"
//
// Revisions :
// ----------------------------------------------------------------------------
//
// 0.0.0 MDM Initial 9/7/05.
//
//*****************************************************************************
//*****************************************************************************

void StepCCW(int NumberOfSteps, int PulseWait)
{

int i;

for (i = 0; i < NumberOfSteps; i++) {

		_outp(PARALLEL_PORT_WRITE, CCW_RISING_EDGE);

		Sleep(10);

		_outp(PARALLEL_PORT_WRITE, CCW_FALLING_EDGE);

		Sleep(PulseWait);

		}
}
//*****************************************************************************
//*****************************************************************************



//*****************************************************************************
//*****************************************************************************
//
// StepCW() takes a clockwise step when looking down at the filter wheel
// assembly. The negative going /STEP pulse is held high for 10ms and then 
// transitions low. PulseWait milliseconds are waited before the next step
// of multiple steps or before a single step call to StepCW() returns.
//
//
// Copyright (c) 2005 AetherMachines Inc. This software may be freely modified
// and distributed by the end user provided AetherMachines Inc. is cited as the
// source of the original code. For instance :
//
// 0.0.0 Derived from AetherMachines original source
// 1.0.0 Added feature A
// 2.0.0 Added feature B
//
// or
//
// "The following AetherMachines Inc. code is provided free of charge"
//
// Revisions :
// ----------------------------------------------------------------------------
//
// 0.0.0 MDM Initial 9/7/05.
//
//*****************************************************************************
//*****************************************************************************

void StepCW(int NumberOfSteps, int PulseWait)
{

int i;

for (i = 0; i < NumberOfSteps; i++) {

		_outp(PARALLEL_PORT_WRITE, CW_RISING_EDGE);

		Sleep(10);

		_outp(PARALLEL_PORT_WRITE, CW_FALLING_EDGE);

		Sleep(PulseWait);

		}
}
//*****************************************************************************
//*****************************************************************************



//*****************************************************************************
//*****************************************************************************
//
// ReadHomeSensor() returns whether the Home Mark is currently under the Home
// Sensor (0 not visible, 1 visible). The Home Mark is typically visible for 
// 1-3 7.5 degree steps.
//
// Copyright (c) 2005 AetherMachines Inc. This software may be freely modified
// and distributed by the end user provided AetherMachines Inc. is cited as the
// source of the original code. For instance :
//
// 0.0.0 Derived from AetherMachines original source
// 1.0.0 Added feature A
// 2.0.0 Added feature B
//
// or
//
// "The following AetherMachines Inc. code is provided free of charge"
//
// Revisions :
// ----------------------------------------------------------------------------
//
// 0.0.0 MDM Initial 9/7/05.
//
//*****************************************************************************
//*****************************************************************************

int ReadHomeSensor(void)
{

return((_inp(PARALLEL_PORT_READ) & 0x08) >> 3);

}
//*****************************************************************************
//*****************************************************************************



//*****************************************************************************
//*****************************************************************************
//
// FindHome() steps the Filter Wheel CCW until it finds and passes over the 
// Home Mark. Stepping decelerates over the Home Mark and 1/2 of the width of
// the Home Mark is stepped in the opposite directio to locate the exact center
// of the Home Mark. If the Home Mark appears too long or short, three tries
// of backing up and resensing are allowed, at which point a failure is declared.
// 
//
// Copyright (c) 2005 AetherMachines Inc. This software may be freely modified
// and distributed by the end user provided AetherMachines Inc. is cited as the
// source of the original code. For instance :
//
// 0.0.0 Derived from AetherMachines original source
// 1.0.0 Added feature A
// 2.0.0 Added feature B
//
// or
//
// "The following AetherMachines Inc. code is provided free of charge"
//
// Revisions :
// ----------------------------------------------------------------------------
//
// 0.0.0 MDM Initial 9/7/05.
//
//*****************************************************************************
//*****************************************************************************

int FindHome(void)
{

#define FILTER_OFFSET 0

int HomeSensor;
int HomeCounts;
int Steps;
int FindMiddle;
int FindTries;

HomeSensor = 0;
Steps = 0;
FindTries = 0;

//*****************************************************************************
// Dither the wheel CCW away from the home sensor ...

	StepCCW(10,10);

ReFind:

HomeCounts = 0;
Steps = 0;

//*****************************************************************************
// Search for a string of home sensor detections ...

	do {

		StepCCW(1, 10);

		HomeSensor = ReadHomeSensor();

		Steps++;

	} while (HomeSensor == 0 && Steps < 250);


		HomeSensor = ReadHomeSensor();
		HomeCounts = HomeCounts + HomeSensor;
		Steps = 0;


	do {

		StepCCW(1, 100);

		HomeSensor = ReadHomeSensor();
		HomeCounts = HomeCounts + HomeSensor;

		Steps++;

	} while (HomeSensor == 1 && Steps < 250);


//*****************************************************************************
// Wait a bit for any 'intertia' effects and prepare for a falling edge ...

		Sleep(500);

		_outp(PARALLEL_PORT_WRITE, CW_RISING_EDGE);


//*****************************************************************************
// Return CW to the center of the Home Mark plus an offset (if desired) ...

		FindMiddle = HomeCounts / 2;

		if (FindMiddle == 0) {

			FindMiddle++;
			}

	for (Steps = 0; Steps < (FindMiddle + FILTER_OFFSET); Steps++) {

		StepCW(1, 100);
		}


//*****************************************************************************
// Error/refind conditions are currently a glitch or abnormal prolonged detection ...


if (FindTries > 2) {

	printf("FindHome() failed ...\r\n");

	return(FindTries);
	}

//printf("H->%d\r\n", HomeCounts);


if (HomeCounts < 1 || HomeCounts > 5 && FindTries < 3) {


	for (Steps = 0; Steps < 10; Steps++) {

		StepCW(1, 100);
		}

	FindTries++;

	goto ReFind;
}


return(FindTries);

}
//*****************************************************************************
//*****************************************************************************



//*****************************************************************************
//*****************************************************************************
//
// InsertFilter() finds the Home Mark and then rotates to the desired filter, 
// specified via an integer 1 <= i <= 8.
//
// Copyright (c) 2005 AetherMachines Inc. This software may be freely modified
// and distributed by the end user provided AetherMachines Inc. is cited as the
// source of the original code. For instance :
//
// 0.0.0 Derived from AetherMachines original source
// 1.0.0 Added feature A
// 2.0.0 Added feature B
//
// or
//
// "The following AetherMachines Inc. code is provided free of charge"
//
// Revisions :
// ----------------------------------------------------------------------------
//
// 0.0.0 MDM Initial 9/7/05.
//
//*****************************************************************************
//*****************************************************************************

int InsertFilter(int FilterNumber)
{

#define INSERT_FILTER_OFFSET 0

int FindHomeRetries;

double NumberOfSteps;


FindHomeRetries = 0;


//*****************************************************************************
// Check for valid filter ...

if (FilterNumber > 0 && FilterNumber <= MAX_FILTER_NUMBER) {


FindHomeRetries = FindHome();

Sleep(500);

	if (FindHomeRetries < 2) {

		NumberOfSteps = (((FilterNumber - 1) * FILTER_STEP_CONSTANT) + INSERT_FILTER_OFFSET);

		printf("@%f\r\n", NumberOfSteps);

		StepCCW((int) NumberOfSteps, 10);
		}
	} 
	else {

		FindHomeRetries = -1;
		}


	return(FindHomeRetries);
}
//*****************************************************************************
//*****************************************************************************



//*****************************************************************************
//*****************************************************************************
//
// TestFilterWheel() flashes LEDs 1-3 5 times each, rotates CCW and CW to pick
// up the Home Mark, and finally performs the initial FindHome() call.
//
// Copyright (c) 2005 AetherMachines Inc. This software may be freely modified
// and distributed by the end user provided AetherMachines Inc. is cited as the
// source of the original code. For instance :
//
// 0.0.0 Derived from AetherMachines original source
// 1.0.0 Added feature A
// 2.0.0 Added feature B
//
// or
//
// "The following AetherMachines Inc. code is provided free of charge"
//
// Revisions :
// ----------------------------------------------------------------------------
//
// 0.0.0 MDM Initial 9/7/05.
// 1.0.0 Added dither of ten steps away in the other direction when testing
// CW and CCW 12/12/05 MDM.
//
//*****************************************************************************
//*****************************************************************************

int TestFilterWheel(void) {

	int i;
	int Steps;
	int FindHomeTries;


	Steps = 0;
	FindHomeTries = 0;


//*****************************************************************************
// Print a basic banner ...

	printf("*******************************************************************************\r\n");

	printf("FilterWheel.exe v1.2.0  Copyright (c) 2005 AetherMachines Inc.\r\n\r\n\r\n");

	printf("                    ***** TESTING FILTER WHEEL *****\r\n\r\n");


//*****************************************************************************
// Turn off all LEDs ...

	_outp(PARALLEL_PORT_WRITE, 7);

	Sleep(500);



//*****************************************************************************
// Flash LED 1 (/STEP) ...

	for (i = 0; i < 5; i++)
	{

	_outp(PARALLEL_PORT_WRITE, 12);

	Sleep(250);

	printf(".");

	_outp(PARALLEL_PORT_WRITE, 14);

	Sleep(250);
	}


	printf("\r\n");


//*****************************************************************************
// Flash LED 2 (DIRECTION) ...

	for (i = 0; i < 5; i++)
	{

	_outp(PARALLEL_PORT_WRITE, 10);

	Sleep(250);

	printf(".");

	_outp(PARALLEL_PORT_WRITE, 14);

	Sleep(250);
	}


	printf("\r\n");


//*****************************************************************************
// Flash LED 3 (INHIBIT) ...

	for (i = 0; i < 5; i++)
	{

	_outp(PARALLEL_PORT_WRITE, 6);

	Sleep(250);

	printf(".");

	_outp(PARALLEL_PORT_WRITE, 14);

	Sleep(250);
	}


	printf("\r\n");


//*****************************************************************************
// Rotate until the Home Mark is found ...

	StepCCW(10,10);

	do {

	StepCCW(1,10);

	Steps++;

	} while (Steps < 260 && ReadHomeSensor() == 0);


	if (Steps > 250) {

		printf("CCW seek problem ...\r\n");
		} 
		else {

			printf(".\r\n");
			}


	Steps = 0;


	Sleep(1000);


//*****************************************************************************
// Rotate until the Home Mark is found ...

	StepCW(10,10);

	do {

	StepCW(1,10);

	Steps++;

	} while (Steps < 260 && ReadHomeSensor() == 0);


	if (Steps > 250) {

		printf("CW seek problem ...\r\n");
		} 
		else {

			printf(".\r\n");
			}


	Sleep(1000);

//*****************************************************************************
// Find Home and print user instructions ...

	FindHomeTries = FindHome();


	if (FindHomeTries < 2) {

		printf("\r\nOK ...\r\n");

		printf("\r\nEnter 1,2, ... 8 for desired filter\r\n");
		printf("Enter l/L for low power hold\r\n");

		}

	
	printf("\r\n\r\n\r\n");


	return(FindHomeTries);

}
//*****************************************************************************
//*****************************************************************************



//=============================================================================
//=============================================================================
//
// main() attaches to the GiveIo device (service), runs TestFilterWheel() and
// enters the main loop where the user specifies which filters to use.
//
// Copyright (c) 2005 AetherMachines Inc. This software may be freely modified
// and distributed by the end user provided AetherMachines Inc. is cited as the
// source of the original code. For instance :
//
// 0.0.0 Derived from AetherMachines original source
// 1.0.0 Added feature A
// 2.0.0 Added feature B
//
// or
//
// "The following AetherMachines Inc. code is provided free of charge"
//
// Revisions :
// ----------------------------------------------------------------------------
//
// 0.0.0 MDM Initial 9/7/05.
//
//=============================================================================
//=============================================================================

int main()
{
	int ch;

	HANDLE hGiveIo;


//*****************************************************************************
// Attach to the GiveIo device ...

    hGiveIo = CreateFile("\\\\.\\giveio", GENERIC_READ, 0, NULL,
					OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if(hGiveIo == INVALID_HANDLE_VALUE) {
        printf("GiveIo device unavailable ...\r\n");
        return -1;
    }
	CloseHandle(hGiveIo);


//*****************************************************************************
// Test Filter Wheel operation ...

	TestFilterWheel();


//*****************************************************************************
// Enter the main loop ...

	do {

		printf("FilterWheel-> ");

		ch = toupper(getche());

		printf("\r\n");


		if (ch == 'l' || ch == 'L') {

			InhibitMotor();
			}
			else {

				InsertFilter(ch - 48);
				}

	} while(1);

return (0);
}
//=============================================================================
//=============================================================================


