/*
 * Assignment #C, CS154 Spring 2001
 * Name         :   SooYoung Jung
 * Date         :   April, 2, 2001
 * File         :   sy.cc
 * 
 */


/*
 * All numbers of motors and sensors
 */
int 	LEFT_MOTOR      = 0;   
int 	RIGHT_MOTOR     = 1;
int 	FAN_MOTOR       = 3;

int 	IR_SENSOR       = 0;
int 	LEFT_LIGHT      = 3;
int 	RIGHT_LIGHT     = 6;

int 	LEFT_BUMP       = 7;
int 	RIGHT_BUMP      = 10;
int 	BACK_BUMP       = 15;

/*
 * Direction of robot
 */
int 	LEFT_FOWARD     = 1;
int 	RIGHT_FOWARD    = 1;

int 	LEFT         	= 0;
int 	RIGHT        	= 1;

int 	STOP        	= 0;
int 	FOWARD      	= 1;
int 	BACKWARD    	= -1;


/*
 * Speed of motors.
 * According to handyboard manual, there are 7 degrees of power so I decided 
 * to increase/decrease motor power by 30.
 */
int 	MOTOR_DEGREE 	= 30;

int 	LEVEL_1 		= 1;
int 	LEVEL_2 		= 2;
int 	LEVEL_3 		= 3;

int 	FOWARD_1    	= 30;
int 	FOWARD_2    	= 60;
int 	FOWARD_3    	= 90;

int 	REVERSE_1   	= -30;
int 	REVERSE_2   	= -60;
int 	REVERSE_3   	= -90;

/*
 * The value of IR sensor when it sees flame
 */
int     NO_FIRE         = 245;
int     FOUND_FIRE      = 200;
int     NEAR_FIRE       = 25;

/*
 * The value of light sensors.
 * I have to use different valuse for light sensors
 * because two light sensors sense differenty with same situation.
 */
int  	L_LIGHT_FACING 	= 15;
int  	R_LIGHT_FACING 	= 30;

/*
 * When the flame is at the center of them, the values would be these.
 */
int  	L_LIGHT_GOOD 	= 18;
int  	R_LIGHT_GOOD 	= 45;

/*
 * This is time(second). But the motor will make 180 degree for 1 second turn.
 */
float   DEGREE_5  		= 0.05;
float   DEGREE_45  		= 0.25;
float   DEGREE_75  		= 0.2;
float   DEGREE_90  		= 0.5;
float   DEGREE_180 		= 1.0;

/*
 * When the fire is extinguished, the value will be set to 1
 */
int     extinguished 	= 0;

/*
 * Process id numbers
 */
int 	endPID;
int 	bumpPID;
int 	firePID;


/*
 * Main does not that much work. but it will produce processes to make the
 * program work.
 */
void main() 
{
    printf("\nYellowy\n");
    printf("Press Start\n");
    start_press();

    motor(LEFT_MOTOR, FOWARD_3);
    motor(RIGHT_MOTOR, FOWARD_3);

    endPID = start_process(endProcess());
    bumpPID = start_process(bumpCheck());
    firePID = start_process(fireCheck());

    while(!extinguished);

    kill_process(firePID);
    kill_process(endPID);

    printf("Yellowy, Good Job!!!\n");
    alloff();

}

/*
 * This process, fireCheck, will detect the fire.
 * If it detects, it will align with flame and extinguish it and return to 
 * main process. 
 */
void fireCheck()
{
    while(!extinguished)
    {
        /* Yes, it found the fire. Do the work */
        if (analog(IR_SENSOR) < FOUND_FIRE)
        {
	        /* 
	         * While aligning, the bump sensors can touch the candle holder or 
	         * wall. Then it will turn.  This isn't necessary anymore.
	         * So kill the bump process, and align to the fire
	         */
            kill_process(bumpPID);

	        /* 
	         * Shout, Fire!!!! and align, and extinguish it. 
	         */
            foundFire();
       		align();
            extinguish();
        }
    }
}


/*
 * Firstly, the robot will make left-right align, then move forward to be 
 * close enough to extinguish fire.  Then the robot will make left-right align 
 * again, because, the motors cannot make the robot move straight forward.  It 
 * keeps going to a little bit right side.
 *
 * To align, the robot will store the value of IR-sensor, and make a little 
 * left turn first, then check IR-sensor again. If the value shows the robot 
 * is closer(lower than before) than before, then the robot will make more 
 * left turn agian until it gets farther than before. 
 * Then the robot will make right turn and do the same thing as left 
 * alignment.
 *
 * And it will go forward a little bit continuously until the robot can blow 
 * out the flame.
 *
 * Then do left-right alignment again because of fault of motors(?)
 */
int align()
{
    int last_IR;						/* previous IR-sensor value */
    int current_IR 	= analog(IR_SENSOR);
    
    /*
     * boolean value for left-right alignment and forwarding to candle.
     */
    int leftRight 	= 0;
    int closeEnough = 0;

	int left 		= 1;				/* or forward */
	int right 		= 1;				/* or backward */
	
	/*
	 * Before we check IR-sensor, need to make turn or move forward so we can 
	 * compare previous value and current value.
	 */
	int firstTime = 1;

	printf("align start\n");			/* Info that I need */

	/*
	 * left right alignment
	 */
	while (!leftRight)
    {  
    	/*
    	 * The robot is going to closer, or it is first time, 
    	 * so make more turn!
    	 */ 
		if ((current_IR < last_IR) || firstTime)  /* goint to closer */
		{
			last_IR = analog(IR_SENSOR);

			/* 
			 * left alignment first, and right alignment
			 */
			if (left || firstTime)
			{
				angleTurn(LEFT, LEVEL_1, DEGREE_5);
				firstTime = 0;
			}
			else  						/* right alignment */
			{
				angleTurn(RIGHT, LEVEL_1, DEGREE_5);
			}

		}
	
		/*
		 * Going to father, so finish left-alignment and do right alignment
		 * If done both, then wer are done with left-right alignment
		 */
		else							
		{
			last_IR = analog(IR_SENSOR);

			/*
			 * Finish left alignment
			 */
			if (left && right)
			{
				left = 0;				/* no more left */
				angleTurn(RIGHT, LEVEL_1, DEGREE_5);
			}
			else if (right)
			{
				right = 0;
				angleTurn(LEFT, LEVEL_1, DEGREE_5);
			}
		}
        ao();

		/*
		 * Gotta sleep, so the value of IR-sensor can differ, 
		 * otherwise, the robot can read the value while turing.
		 */
		sleep(0.5);
   		current_IR = analog(IR_SENSOR);

		/*
		 * check if we are really done.
		 */
		if (!left && !right)
		{
			leftRight = 1;
		}

		/* Info */
        printf ("L:%d,R:%d,I:%d\n", analog(LEFT_LIGHT), analog(RIGHT_LIGHT),
        							analog(IR_SENSOR));
	}

	firstTime = 1;

	/*
	 * Move forward to make the robot close enough to blow out the candle
	 * The same strategy as left-right alignment but moving forward.
	 */
	while (!closeEnough)
    {   
    	/*
    	 * The robot is going to closer, or it is first time, 
    	 * so make more forward movement!
    	 */ 
		if ((current_IR < last_IR) || firstTime)
		{
			last_IR = analog(IR_SENSOR);

			move(FOWARD, LEVEL_1, DEGREE_5);
			firstTime = 0;
		}
        ao();
		sleep(0.5);
   		current_IR = analog(IR_SENSOR);

		/*
		 * If the robot is close enough, then finish the forward-alignment.
		 */
		if (current_IR < NEAR_FIRE)
		{
			closeEnough = 1;
		}
		
		/*
		 * If the robot sense the bump(s), then do not go more.
		 * Let's assume it is candle holder. 
		 */
		if (digital(LEFT_BUMP) || digital(LEFT_BUMP))
		{
			move(BACKWARD, LEVEL_1, DEGREE_5);
		}
        
        printf ("L:%d,R:%d,I:%d\n", analog(LEFT_LIGHT), analog(RIGHT_LIGHT), 
        							analog(IR_SENSOR));
	}

	left 		= 1;
	right 		= 1;
	firstTime 	= 1;
	leftRight 	= 0;

	/*
	 * left-right alignment again
	 */
	while (!leftRight)
    {  
    	/*
    	 * The robot is going to closer, or it is first time, 
    	 * so make more turn!
    	 */ 
		if ((current_IR < last_IR) || firstTime)  /* goint to closer */
		{
			last_IR = analog(IR_SENSOR);

			/* 
			 * left alignment first, and right alignment
			 */
			if (left || firstTime)
			{
				angleTurn(LEFT, LEVEL_1, DEGREE_5);
				firstTime = 0;
			}
			else  						/* right alignment */
			{
				angleTurn(RIGHT, LEVEL_1, DEGREE_5);
			}

		}
	
		/*
		 * Going to father, so finish left-alignment and do right alignment
		 * If done both, then wer are done with left-right alignment
		 */
		else							
		{
			last_IR = analog(IR_SENSOR);

			/*
			 * Finish left alignment
			 */
			if (left && right)
			{
				left = 0;				/* no more left */
				angleTurn(RIGHT, LEVEL_1, DEGREE_5);
			}
			else if (right)
			{
				right = 0;
				angleTurn(LEFT, LEVEL_1, DEGREE_5);
			}
		}
        ao();

		/*
		 * Gotta sleep, so the value of IR-sensor can differ, 
		 * otherwise, the robot can read the value while turing.
		 */
		sleep(0.5);
   		current_IR = analog(IR_SENSOR);

		/*
		 * check if we are really done.
		 */
		if (!left && !right)
		{
			leftRight = 1;
		}

		/* Info */
        printf ("L:%d,R:%d,I:%d\n", analog(LEFT_LIGHT), analog(RIGHT_LIGHT),
        							analog(IR_SENSOR));
	}

	/*
	 * tell the caller we are successfully done 
	 */
	return closeEnough;					
}

/*
 * This etinguish function will extingush the fire.
 * Check every 5 second they are really gone.
 */
void extinguish()
{
    int done = 0;
    int last_IR;
    
    while(!done)
    {
        last_IR = analog(IR_SENSOR);
        motor(FAN_MOTOR,  FOWARD_3);
        sleep(5.0);
        
        /*
         * both of current and previouse value should not detect fire
         */
        if (analog(IR_SENSOR) > NO_FIRE && last_IR > NO_FIRE)
        {
            ao();
            done 		 = 1;
            extinguished = 1;
        }
    }
}

/*
 * Just say to everybody.
 */
void foundFire()
{
    ao();
    printf("FIRE!!!\n");
    tone(500.0, 1.0);
}   


/*
 * This is another process(thread) that main will check bumper status all the 
 * time.  If there is obstacle on the left, then it will make a right angle 
 * turn to right or vice versus. If the back sensor is detecting something, 
 * then it should happen when they the robot is making left or right turn. so 
 * just stop and make turn.
 *
 * I just realize that this back bumper part whouldn't really work so it 
 * should be separate as another process so it can probably detect when they 
 * are making turn.
 */
void bumpCheck()
{
    while(1)
    {
        if (digital(RIGHT_BUMP) && digital(LEFT_BUMP) || digital(RIGHT_BUMP))
        {
            printf("LEFT && RIGHT Bumps\n");
            move(BACKWARD, LEVEL_3, DEGREE_75);
            angleTurn(LEFT, LEVEL_3, DEGREE_90);
            move(FOWARD, LEVEL_3, DEGREE_75);
        }
        else if (digital(LEFT_BUMP))
        {
            printf("LEFT Bump\n");
            move(BACKWARD, LEVEL_3, DEGREE_75);
            angleTurn(RIGHT, LEVEL_3, DEGREE_90);
            move(FOWARD, LEVEL_3, DEGREE_75);
        }
        else if (digital(BACK_BUMP))
        {
            printf("BACK Bump %d\n", LEVEL_1);
            ao();
            
	        if (digital(RIGHT_BUMP) && digital(LEFT_BUMP) || 
	        	digital(RIGHT_BUMP))
	        {
	            printf("LEFT && RIGHT Bumps\n");
	            angleTurn(LEFT, LEVEL_3, DEGREE_90);
	            move(FOWARD, LEVEL_3, DEGREE_75);
	        }
	        else
	        {
	            printf("LEFT Bump\n");
	            angleTurn(RIGHT, LEVEL_3, DEGREE_90);
	            move(FOWARD, LEVEL_3, DEGREE_75);
	        }
        }
    }
}

/*
 * This angleTurn will take 3 arguments and make the robot turn.
 * Three arguments are 
 *	1. which way the robot should go(left or right)
 *	2. how fast it should go
 *  3. turing angle.
 */
void angleTurn(int whichWay, int powerLevel, float angle)
{
    int motorPower = MOTOR_DEGREE * powerLevel;
    
    if (whichWay == LEFT)
    {
    	/*
    	 * Move both motors so it does faster turn compare to one motor moving
    	 * turn.
    	 */
        motor(RIGHT_MOTOR, motorPower);
        motor(LEFT_MOTOR, motorPower * BACKWARD);
    }
    else if (whichWay == RIGHT)
    {
        motor(LEFT_MOTOR, motorPower);
        motor(RIGHT_MOTOR, motorPower * BACKWARD);
    }
    
    sleep(angle);
}
    
/*
 * This move will take 3 arguments and make the robot move.
 * Three arguments are 
 *	1. which way the robot should go(forward or backward)
 *	2. how fast it should go
 *  3. how long the robot should move.
 * The function will make the robot move at leat third input argument of 
 * seconds.
 * Stoping the robot after movement is caller's responsibility.
 */
void move(int whichWay, int powerLevel, float howlong)
{
    int motorPower = MOTOR_DEGREE * powerLevel * whichWay;
    
    motor(LEFT_MOTOR,  motorPower);
    motor(RIGHT_MOTOR, motorPower);
    sleep(howlong);
}

/*
 * The other process(thread).
 * Whenever stop button is pressed, the robot will stop all motors.
 */
void endProcess() 
{
    while(1) 
    {
        stop_press();
        alloff();
        printf("Stop pressed\n");
    }
}





