/*
 * camctl-test.c 
 * $Revision: 1.3 $
 * $Date: 2004/02/13 15:12:10 $
 *
 * This is a replacement program for camctl.c that tests each of the commands;
   driving discrete devs, and motors one at a time.
 *
 $Log: camctl-test.c,v $
 Revision 1.3  2004/02/13 15:12:10  Brad
 misc changes.

 Revision 1.2  2004/02/05 23:38:51  Brad
 fixed channel problems, motorDrive

 Revision 1.1  2004/02/04 01:09:54  Brad
 Initial version, used for testing.

 *
 *
 */


#include "hc11e9.h"
#include "sci.h"
#include "camctl.h"


/*************************************************************
 void main(void)

 param : none
 return: none

 This function just waste some clock cycles, introducing 
 a bit of delay
*************************************************************/
void waste_time() {
	 
	 unsigned int count = 65535;
	 
	 while (count-- > 0) { 
	 	   asm("nop\n"); 
	 }
}


/* variables used in MAIN */
int count;
unsigned char cmd[7];

/*************************************************************
 void main(void)

 param : none
 return: none

 This function is the main logic of the motor controller board.
 It implements a while(true) loop accepting all commands
*************************************************************/
void main(void) {

	unsigned char command;  /* command passed by SCI */
	signed char param; 			/* parameter passed as part of a command */

/*	Set up Port C as output, turn all motors off	*/

	DDRC = 0xFF;  // portc all outputs 
	PORTC = 0x00; // turn motors off 
	PORTB = 0xFF;  // set rate of all motors to 0.

/* 	Initialize the SCI interface	*/
	initSCI();

/*	Initialize the SPI interface	*/

/* set directions for PORTD pins
 * 5,4,3 output; 2,1,0 input */
	DDRD = DDD5|DDD4|DDD3;

/* configure SPI
 * enable spi, set as master */
	SPCR = SPE|MSTR;

/*	Enable interrupts	*/
	asm("cli");

/* shutdown all motors, in case they are enabled */
	shutdown(); 

	
#ifdef DEBUG
	serial_print("cam ctl online, starting control loop\r\n");
#endif

/*	
 * main control loop from camctl.c has been changed from a while(), to a for().
 * This allows us to automate the testing process. We loop, executing one
 * one command each time, outputting to serial which command we are executing.
 *
 * NOTE: all reads from the fifo have been commented out because we override
 * those values with the command we want to execute.
*/

// setup values to be output
cmd[0] = CAM_ZOOM;
cmd[1] = CAM_FOCUS;
cmd[2] = CAM_FSTOP;
cmd[3] = CAM_PAN;
cmd[4] = CAM_TILT;
cmd[5] = TOG_CAM_PWR;
cmd[6] = TOG_CAM_LIGHT;
cmd[6] = HALT_ALL;
param = -15; // always use this param, for testing anyways.

//do this once for each command
for(count=0;count<8;count++) {
	//set the new command value
	command=cmd[count];

	//depending on which we are testing, 
    if (count==0) { serial_print("ZOOM\r\n"); }
    else if (count==1) { serial_print("FOCUS\r\n"); }
    else if (count==2) { serial_print("FSTOP\r\n"); }
    else if (count==3) { serial_print("PAN\r\n"); }
    else if (count==4) { serial_print("TILT\r\n"); }
    else if (count==5) { serial_print("PWR CAM\r\n"); }
    else if (count==6) { serial_print("PWR LIGHT\r\n"); }
    else if (count==7) { serial_print("HALT ALL\r\n"); }

/*
  	while (TRUE) {
		// wait for a sync byte from the fifo 
		while (fifoRead() != SYNC_BYTE) {};

#ifdef DEBUG		
		//echo to serial
		serial_send(SYNC_BYTE);
#endif
		
		// next byte is a command 
		command = fifoRead();
*/
		
#ifdef DEBUG	
		//echo to serial
		serial_send(command);
#endif

/*
		// next byte is a param 
		param = fifoRead();
*/
#ifdef DEBUG		
		//echo to serial
		serial_send(param);
#endif
	
		// process commands 
		switch (command) {
			case CAM_TILT:
#ifdef DEBUG
				serial_print("cam_tilt_mask\r\n");
#endif
				// tilt driver on channel B 
				motorDrive(CAM_TILT_MASK,0,param);
				break;

			case CAM_PAN:
#ifdef DEBUG
				serial_print("cam_pan_mask\r\n");
#endif
				// pan driver on channel A 
				motorDrive(CAM_PAN_MASK,param,0);
				break;

			case CAM_FOCUS:
#ifdef DEBUG
				serial_print("cam_focus_mask\r\n");
#endif
				// focus driver on channel B 
				motorDrive(CAM_FOCUS_MASK,0,param);
				break;

			case CAM_ZOOM:
#ifdef DEBUG
				serial_print("cam_zoom_mask\r\n");
#endif
				// zoom driver on channel B 
				motorDrive(CAM_ZOOM_MASK,0,param);
				break;

			case CAM_FSTOP:
#ifdef DEBUG
				serial_print("cam_fstop_mask\r\n");
#endif
				// fstop driver on channel B 
				motorDrive(CAM_FSTOP_MASK,0,param);
				break;

			case TOG_CAM_PWR:
#ifdef DEBUG
				serial_print("cam_pwr_mask\r\n");
#endif
				switchDevice(CAM_PWR_MASK,param);
				break;

			case TOG_CAM_LIGHT:
#ifdef DEBUG
				serial_print("cam_light_mask\r\n");
#endif
				switchDevice(CAM_LIGHT_MASK,param);
				break;

			case HALT_ALL:
#ifdef DEBUG
				serial_print("halt all\r\n");
#endif
				// shutdown all devices
				shutdown();	 
				break;
		} //end  switch/case

#ifdef DEBUG		
		serial_print("end of loop\r\n");
#endif
		waste_time();

//	} //end while true

	} //end for
	
} //end main

/*************************************************************
 void shutdown(void)

 param : none
 return: none

 This function shuts down all motors, and switched devices
*************************************************************/
void shutdown(void)
{

/* 	brake all motors */
	PORTC = 0xFF;
	PORTB = 0;

/* 	switch off all devices here */
	switchDevice(ALL_SWITCHED_DEVS,SWITCH_DEV_OFF);
}

/*************************************************************
 void motorDrive(unsigned char mask, signed char speedChanA, signed char
 						speedChanB)

 param : unsigned char mask
         signed char speedChanA
         signed char speedChanB
 return: none

 This function controls the motor drivers on the motor controller board.
 It sets the direction bit, generates the two channel speed byte, then
 writes the brake buts using the mask passed in. The motor drivers are
 the LMD18245's on the board.
*************************************************************/
void motorDrive(unsigned char mask, signed char speedChanA, signed char speedChanB)
{

#ifdef DEBUG
 	int count;
	unsigned char mask_test = 0x80;
	unsigned char speed;
#endif

/*	There are two independent speed channels, A and B
	that can be controlled with the current configuration	*/

/*	if speed is negative, set mask appropriately.
	note: mask usage and PORTC described in camctl.h */
	if (speedChanA < 0) {
		mask &= ~0x80; //turn off bit7
		speedChanA = ~speedChanA + 1;
#ifdef DEBUG
	   	serial_send(speedChanA);
		serial_print("=chan_a < 0 \r\n");
#endif
	}
#ifdef DEBUG
	else {
	   	serial_send(speedChanA);
		serial_print("=chan_a > 0 \r\n");
	}
#endif	

	if (speedChanB < 0)	{
		mask &= ~0x40;   //turn off bit6
		speedChanB = ~speedChanB + 1;
#ifdef DEBUG
		serial_send(speedChanB);
		serial_print("=chan_b < 0\r\n");
#endif		
	} 
#ifdef DEBUG
	else {
	   	serial_send(speedChanB);
		serial_print("=chan_b > 0\r\n");
	}
#endif
	 

/*		Brake byte is written to PORT C */
	if ((speedChanA == 0) && (speedChanB == 0))
	    mask |= ~mask; //if both are zero, then we want to set the brake bit high
	PORTC = mask;
	
#ifdef DEBUG
	serial_print("mask=");
	for (count=0;count < 8;count++) {
		serial_send((mask&mask_test)?0x31:0x30);
		mask_test >>= 1;
	}
	serial_print("\r\n");
#endif

/*		speed of channel A and B written to PORTB in the following form
        PORTB = |7 |6 |5 |4 |3 |2 |1 |0 |
                 -----------------------
                |spdChA     |spdChB     |  */
	PORTB = (speedChanA << 4) | speedChanB;

#ifdef DEBUG
	mask_test = 0x80;
	speed = (speedChanA << 4) | speedChanB;
	serial_print("speed=");
	for (count=0;count < 8;count++) {
		serial_send((speed&mask_test)?0x31:0x30);
		mask_test >>= 1;
	}
	serial_print("\r\n");
#endif
	
}

/*************************************************************
 void switchDevice(unsigned char mask, signed char param)

 param : unsigned char mask
               signed char parm
 return: none

This function interfaces to the MC33298 to switch peripheral
devices on and off.

MC33298 notes:
	 * SS is set as a general purpose IO pin on this board:
	 * referring to m68hc11 reference manual, pg 2-19 -
	 * when the SPI system is enabled (SPE pin on SPCR)
	 * PD5/SS(bar) pin can be used as general-purpose output by
	 * setting the DDRC(5) bit to output, when the SPI system
	 * is configured in master mode of operation (MSTR on SPCR)
	 *
	 * SS(bar) is 'switch select' - used to enable the mc3398
*************************************************************/
void switchDevice(unsigned char mask, char param)
{

/* 		used to keep track of the state of the switches*/
	static unsigned char switch_state = 0xFF;

/*		MC33298 uses inverse logic */

	if (param == SWITCH_DEV_ON)
		switch_state &= ~mask;		/* turn on, set bit low	*/
    else if (param == SWITCH_DEV_OFF)
    	switch_state |= mask;	/* turn off, set bit hi	*/
    else
    	switch_state ^= mask;					/* toggle	*/

/*	To use this chip, you must transfer 8 bits to it serially.

	 * pull SS line low to select the MC33298 octal switch
	 * Then use SPI to transmit the switch states (0 enable, 1 disable)
	 * to the device. Wait for transfer completion by checking the SPIF
	 * bit in the SPSR, serial peripheral status reg, then disable
	 * the mc33298 by setting SS high on PORTD

*/

	PORTD &= ~SS;				/* enable data transfer, set SS bit lo */
	SPDR = switch_state;		/* transfer	data to the 33298*/
	while((SPSR & SPIF) == 0);	/* wait for completion		*/
	PORTD |= SS;				/* disable data transfer	*/

}




/*
void command_send (unsigned char cmd, char param) {
	 
	 fifoWrite(SYNC_BYTE);
	 fifoWrite(cmd);
	 fifoWrite(param);

}
*/

