Example #1
0
/**
 * @Function RunRoachFSM(ES_Event ThisEvent)
 * @param ThisEvent - the event (type and param) to be responded.
 * @return Event - return event (type and param), in general should be ES_NO_EVENT
 * @brief This is the function that implements the actual state machine; in the
 *        roach case, it is a simple ping pong state machine that will form the
 *        basis of your more complicated exploration. This function will be called
 *        recursively to implement the correct order for a state transition to be:
 *        exit current state -> enter next state using the ES_EXIT and ES_ENTRY
 *        events.
 * @author Gabriel H Elkaim, 2013.09.26 15:33 */
ES_Event RunMotorYFSM(ES_Event ThisEvent) {
    uint8_t makeTransition = FALSE;
    Motor_Y_State_t nextState;
    ES_Tattle(); // trace call stack
    static unsigned int eventParam = 0;
    static unsigned int i = 0;
    static unsigned int j = 0;

    switch (CurrentState) {
        case InitQState:
            if (ThisEvent.EventType == ES_INIT) {
                nextState = selfCalibrateY;
                makeTransition = TRUE;
            }
            break;

        case selfCalibrateY:
            switch (ThisEvent.EventType) {
                case ES_ENTRY:
                    break;

                case CALIBRATED:
                    if (ThisEvent.EventParam == MOTOR_X) {
                        Stepper_Init(MOTOR_Y, 77);
                        reverseY(4000);
                        ES_Timer_InitTimer(MOTOR_Y_TIMER, 5000);
                    }
                    break;

                case Y_LIMIT:
                    if (ThisEvent.EventParam == Y_MIN_MASK) {
                        initialY = getFilteredAD(Y_SLIDER);
                        newPosition = AD_SCALE_Y * initialY;
                        currentPosition = 0;
                        setStepsTaken(MOTOR_Y, 0);
                        positionDifference = currentPosition - newPosition;

                        if (positionDifference < 0) {
                            //forwardX(abs(positionDifference));
                        } else if (positionDifference > 0) {
                            1; //do nothing, already at zero
                        }
                        Stepper_Halt(MOTOR_Y);
                    }
                    break;
                    //case Y_LIMIT:
                case ES_TIMEOUT:
                    if (ThisEvent.EventParam == MOTOR_Y_TIMER) {
                        initialY = getFilteredAD(Y_SLIDER);
                        //Stepper_Resume(MOTOR_Y);
                        newPosition = AD_SCALE_Y * initialY;
                        currentPosition = 0;
                        setStepsTaken(MOTOR_Y, 0);
                        positionDifference = currentPosition - newPosition;

                        if (positionDifference < 0) {
                            //forwardY(abs(positionDifference));
                        } else if (positionDifference > 0) {
                            1; //do nothing, already at zero
                        }
                        nextState = waitingY;
                        makeTransition = TRUE;

                    }
                    break;

                case ES_EXIT:
                    Stepper_Halt(MOTOR_Y);
                    ES_Timer_StopTimer(MOTOR_Y_TIMER);
                    break;

                default:
                    break;
            }
            break;

        case waitingY:
            if (ThisEvent.EventType != ES_NO_EVENT) {
                switch (ThisEvent.EventType) {
                    case ES_ENTRY:

                        break;

                    case XY_CHANGE:
                        nextState = movingBufferY;
                        makeTransition = TRUE;
                        memEventY = ThisEvent;
                        break;

                    case PRESETCHANGE:
                        //Coming from presetFSM
                        //nextState = movingY_Preset;
                        //makeTransition = TRUE;
                        break;

                    case ES_EXIT:
                        Stepper_Resume(MOTOR_Y);
                        setStepsRate(MOTOR_Y, 77);
                        //ES_Timer_StopTimer(MOTOR_Y_TIMER);
                        break;

                    default:
                        break;
                }
            }
            break;

        case movingBufferY:
            if (ThisEvent.EventType != ES_NO_EVENT) {
                switch (ThisEvent.EventType) {
                    case ES_ENTRY:
                        ES_Timer_InitTimer(MOTOR_Y_TIMER, 200);
                        break;

                    case XY_CHANGE:
                        nextState = movingBufferY;
                        makeTransition = TRUE;
                        memEventY = ThisEvent;
                        break;

                    case ES_TIMEOUT:
                        if (ThisEvent.EventParam = MOTOR_Y_TIMER) {
                            nextState = movingY;
                            makeTransition = TRUE;
                        }
                        break;

                    case ES_EXIT:
                        setStepsRate(MOTOR_Y, 77);
                        break;

                    default:
                        break;
                }
            }
            break;

        case movingY:
            switch (ThisEvent.EventType) {
                case ES_ENTRY:
                    Stepper_Init(MOTOR_Y, 77);
                    newPosition = AD_SCALE_Y * memEventY.EventParam;
                    currentPosition = getStepsTaken(MOTOR_Y);
                    positionDifference = currentPosition - newPosition;
                    if (positionDifference < 0) {
                        yDirection = FORWARD;
                        forwardY(abs(positionDifference));
                    } else {
                        yDirection = REVERSE;
                        reverseY(abs(positionDifference));
                    }

                    break;

                case ALMOSTOUTOFSTEPS:
                    setStepsRate(MOTOR_Y, 15);
                    break;

                case OUTOFSTEPS:
                    Stepper_Halt(MOTOR_Y);
                    ES_Timer_InitTimer(MOTOR_Y_TIMER, 50);
                    setStepsRate(MOTOR_Y, 77);

                    break;

                case ES_TIMEOUT:
                    if (ThisEvent.EventParam == MOTOR_Y_TIMER) {
                        Stepper_Halt(MOTOR_Y);
                        nextState = waitingY;
                        makeTransition = TRUE;
                    }
                    break;

                case XY_CHANGE:
                    nextState = movingBufferY; 
                    makeTransition = TRUE;
                    memEventY = ThisEvent;
                    break;

                case ES_EXIT:
                    lastYDirection = yDirection;
                    setStepsRate(MOTOR_Y, 77);
                    ES_Timer_StopTimer(MOTOR_Y);
                    break;

                default:
                    nextState = waitingY;
                    makeTransition = TRUE;
                    break;
            }
            break;

        case movingBufferY2:
            //ThisEvent = RunmovingYSubFSM(ThisEvent);
            if (ThisEvent.EventType != ES_NO_EVENT) {
                switch (ThisEvent.EventType) {
                    case ES_ENTRY:
                        //printf("movingBuffer Enter:%d\n", memEventY.EventParam);
                        ES_Timer_InitTimer(MOTOR_Y_TIMER, 200);
                        break;


                    case XY_CHANGE:
                        //printf("Y_CHANGE\n");

                        //determine if a change of direction is about to occur
                        newPosition = AD_SCALE_Y * ThisEvent.EventParam;
                        currentPosition = getStepsTaken(MOTOR_Y);
                        positionDifference = currentPosition - newPosition;
                        if (positionDifference < 0) {
                            yDirection = FORWARD;
                        } else {
                            yDirection = REVERSE;
                        }
                        //if direction change, start slowing down

                        memEventY = ThisEvent;
                        break;

                    case ES_TIMEOUT:
                        if (ThisEvent.EventParam = MOTOR_Y_TIMER) {
                            printf("yDirection:%d, lastYDirection:%d\n", yDirection, lastYDirection);
                            if (yDirection != lastYDirection) {
                                printf("directionChange!\n");
                                //setStepsRate(MOTOR_Y, 15);
                                //make an event instead!
                                //ES_Timer_InitTimer(MOTOR_Y, 150);
                                //while (!(getStepsRate(MOTOR_Y) < 20));
                                nextState = changingDirection;
                                makeTransition = TRUE;
                            } else {
                                nextState = movingY;
                                makeTransition = TRUE;
                            }
                        }
                        break;

                    case ES_EXIT:
                        //Stepper_Init(MOTOR_Y,500);
                        break;

                    default:
                        break;
                }
            }
            break;

        case changingDirection:
            switch (ThisEvent.EventType) {
                case ES_ENTRY:
                    //printf("movingBuffer Enter:%d\n", memEventY.EventParam);
                    //ES_Timer_InitTimer(MOTOR_Y_TIMER, 50);
                    Stepper_ChangeStepRate(MOTOR_Y, 15);
                    break;

                case SPEEDMATCH:
                    printf("speedmatch!\n");
                    nextState = movingY;
                    makeTransition = TRUE;
                    break;

                case XY_CHANGE:
                    //printf("Y_CHANGE\n");
                    nextState = movingBufferY2;
                    makeTransition = TRUE;
                    memEventY = ThisEvent;
                    break;

                case ES_TIMEOUT:
                    if (ThisEvent.EventParam = MOTOR_Y_TIMER) {
                        nextState = movingY;
                        makeTransition = TRUE;
                    }
                    break;

                case ES_EXIT:
                    //Stepper_Init(MOTOR_Y,500);
                    break;

                default:
                    break;
            }
            break;

        default:
            break;
    }

    if (makeTransition == TRUE) {
        RunMotorYFSM(EXIT_EVENT);
        lastState = CurrentState;
        CurrentState = nextState;
        RunMotorYFSM(ENTRY_EVENT);
    }
    //printf("Leaving RunMotorYFSM with CurrentState = %d\n", CurrentState);
    ES_Tail(); // trace call stack end
    return ThisEvent;
}
/**
 * @Function RunRamSubHSM(ES_Event ThisEvent)
 * @param ThisEvent - the event (type and param) to be responded.
 * @return Event - return event (type and param), in general should be ES_NO_EVENT
 * @brief This function is where you implement the whole of the heirarchical state
 *        machine, as this is called any time a new event is passed to the event
 *        queue. This function will be called recursively to implement the correct
 *        order for a state transition to be: exit current state -> enter next state
 *        using the ES_EXIT and ES_ENTRY events.
 * @note Remember to rename to something appropriate.
 *       The lower level state machines are run first, to see if the event is dealt
 *       with there rather than at the current level. ES_EXIT and ES_ENTRY events are
 *       not consumed as these need to pass pack to the higher level state machine.
 * @author J. Edward Carryer, 2011.10.23 19:25
 * @author Gabriel H Elkaim, 2011.10.23 19:25 */
ES_Event RunTapeSubHSM(ES_Event ThisEvent)
{
    uint8_t makeTransition = FALSE; // use to flag transition
    TapeState_t nextState;

    EventStorage args;

    ES_Tattle(); // trace call stack

    switch (CurrentState) {
    case Tape_Init:
        if (ThisEvent.EventType == ES_INIT)
        {
	    // Make sure timer isnt going to be running
	    ES_Timer_StopTimer(TAPE_SUB_HSM_TIMER);

            // now put the machine into the actual initial state
            CurrentState = Ram_Begin;
            makeTransition = FALSE;
            ThisEvent.EventType = ES_NO_EVENT;
        }
        break;

    case Tape_Searching:
        if (ThisEvent.EventType != ES_NO_EVENT) {
            switch (ThisEvent.EventType) {
            case ES_ENTRY:
		// Drive forward
		Drive_Forward(MOTOR_SPEED_CRAWL);

		// Set up frustration timer
		ES_Timer_InitTimer(TAPE_SUB_HSM_TIMER, TAPE_FRUSTRATION_TIMER);
                break;

            case ES_EXIT:
		// Stop
		Drive_Stop();

		// Stop timer
		ES_Timer_StopTimer(TAPE_SUB_HSM_TIMER);
                break;

	    case ES_TIMEOUT:
		if (ThisEvent.EventParam == TAPE_SUB_HSM_TIMER) {
		    nextState = Tape_Reversing;
		    makeTransition = TRUE;

		    // Consume
		    ThisEvent.EventType = ES_NO_EVENT;
		}
		break;

	    case TAPE:
		args.val = ThisEvent.EventParam;

		// Cancel timer for now, tape has been seen
		ES_Timer_StopTimer(TAPE_SUB_HSM_TIMER);

		if (args.bits.event & args.bits.type & TAPE_CENTER) {
		    // If center connects, begin to follow the tape
		    nextState = Tape_Follow_Front;
		    makeTransition = TRUE;
		} else if ((args.bits.event & args.bits.type & TAPE_FRONT_LEFT) &&
			    (~args.bits.type & TAPE_FRONT_RIGHT)) {
		    // If front left entered tape and right is off tape
		    Drive_Left(MOTOR_SPEED_CRAWL);
		} else if ((args.bits.event & args.bits.type & TAPE_FRONT_RIGHT) &&
			    (~args.bits.type & TAPE_FRONT_LEFT)) {
		    // If front right entered tape and left is off tape
		    Drive_Right(MOTOR_SPEED_CRAWL);
		} else if (~args.bits.type & (TAPE_FRONT_RIGHT | TAPE_FRONT_LEFT)) {
		    // If front right and left are both off tape
		    Drive_Forward(MOTOR_SPEED_CRAWL);
		}
		break;

            default: // all unhandled events pass the event back up to the next level
                break;
            }
        }
        break;

    case Tape_Reversing:
        if (ThisEvent.EventType != ES_NO_EVENT) {
            switch (ThisEvent.EventType) {
            case ES_ENTRY:
		// Start reversing
		Drive_Forward(-MOTOR_SPEED_CRAWL);

		// Set timer
		ES_Timer_InitTimer(TAPE_SUB_HSM_TIMER, 1000);
                break;

            case ES_EXIT:
		// Stop
		Drive_Stop();
                break;

	    case ES_TIMEOUT:
		if (ThisEvent.EventParam == TAPE_SUB_HSM_TIMER) {
		    nextState = Tape_Turning;
		    makeTransition = TRUE;

		    // Consume
		    ThisEvent.EventType = ES_NO_EVENT;
		}
		break;

            default: // all unhandled events pass the event back up to the next level
                break;
            }
        }
        break;

    case Tape_Turning:
        if (ThisEvent.EventType != ES_NO_EVENT) {
            switch (ThisEvent.EventType) {
            case ES_ENTRY:
		// Start turning CW 45
		Drive_TankRight(MOTOR_SPEED_EXPLORE);

		// Set timer
		ES_Timer_InitTimer(TAPE_SUB_HSM_TIMER, MOTOR_TURN_EX_45);
                break;

            case ES_EXIT:
		// Stop
		Drive_Stop();
                break;

	    case ES_TIMEOUT:
		if (ThisEvent.EventParam == TAPE_SUB_HSM_TIMER) {
		    nextState = Tape_Searching;
		    makeTransition = TRUE;

		    // Consume
		    ThisEvent.EventType = ES_NO_EVENT;
		}

            default: // all unhandled events pass the event back up to the next level
                break;
            }
        }
        break;

    case Tape_Follow_Front:
        if (ThisEvent.EventType != ES_NO_EVENT) {
            switch (ThisEvent.EventType) {
            case ES_ENTRY:
		// Start driving straight
		Drive_Forward(MOTOR_SPEED_CRAWL);
                break;

            case ES_EXIT:
		// Do nothing
                break;

	    case TAPE:
		args.val = ThisEvent.EventParam;

		if (args.bits.event & args.bits.type & TAPE_FRONT_LEFT) {
		    // If front left on tape
		    Drive_Left(MOTOR_SPEED_CRAWL);
		} else if (args.bits.event & args.bits.type & TAPE_FRONT_RIGHT) {
		    // If front right on tape
		    Drive_Right(MOTOR_SPEED_CRAWL);
		} else if (args.bits.event & ~args.bits.type &
			(TAPE_FRONT_LEFT | TAPE_FRONT_RIGHT)) {
		    // If front left off tape
		    Drive_Forward(MOTOR_SPEED_CRAWL);
		}
		break;

            default: // all unhandled events pass the event back up to the next level
                break;
            }
        }
        break;

    case Tape_Follow_Back:
        if (ThisEvent.EventType != ES_NO_EVENT) {
            switch (ThisEvent.EventType) {
            case ES_ENTRY:
                break;

            case ES_EXIT:
                break;

            default: // all unhandled events pass the event back up to the next level
                break;
            }
        }
        break;

    case Tape_Done_State:
        if (ThisEvent.EventType != ES_NO_EVENT) {
            switch (ThisEvent.EventType) {
            case ES_ENTRY:
                break;

            case ES_EXIT:
                break;

            default: // all unhandled events pass the event back up to the next level
                break;
            }
        }
        break;

    default: // all unhandled states fall into here
        break;
    } // end switch on Current State

    if (makeTransition == TRUE) { // making a state transition, send EXIT and ENTRY
        // recursively call the current state with an exit event
        RunTapeSubHSM(EXIT_EVENT);
        CurrentState = nextState;
        RunTapeSubHSM(ENTRY_EVENT);
    }

    ES_Tail(); // trace call stack end
    return ThisEvent;
}
/**
 * @Function RunTemplateSubHSM(ES_Event ThisEvent)
 * @param ThisEvent - the event (type and param) to be responded.
 * @return Event - return event (type and param), in general should be ES_NO_EVENT
 * @brief This function is where you implement the whole of the heirarchical state
 *        machine, as this is called any time a new event is passed to the event
 *        queue. This function will be called recursively to implement the correct
 *        order for a state transition to be: exit current state -> enter next state
 *        using the ES_EXIT and ES_ENTRY events.
 * @note Remember to rename to something appropriate.
 *       The lower level state machines are run first, to see if the event is dealt
 *       with there rather than at the current level. ES_EXIT and ES_ENTRY events are
 *       not consumed as these need to pass pack to the higher level state machine.
 * @author J. Edward Carryer, 2011.10.23 19:25
 * @author Gabriel H Elkaim, 2011.10.23 19:25 */
ES_Event RunAlignCollect_SubHSM(ES_Event ThisEvent) {
    uint8_t makeTransition = FALSE; // use to flag transition
    SubAlignCollect_SubHSMState_t nextState; // <- change type to correct enum

    ES_Tattle(); // trace call stack
    ES_Event Tcontrol;

    static int aligning_start_time, aligning_end_time;
    static int aligning_difference_time = 0;
    static int  back_tape_flag = 0;

    switch (CurrentState) {
        case InitPSubState: // If current state is initial Psedudo State
            if (ThisEvent.EventType == ES_INIT)// only respond to ES_Init
            {
                nextState = Buffer_State;
                makeTransition = TRUE;
                ThisEvent.EventType = ES_NO_EVENT;
            }
            break;

        case Buffer_State:
            if (ThisEvent.EventType != ES_NO_EVENT) { // An event is still active
                switch (ThisEvent.EventType) {

                    case ES_ENTRY:
                        //PivotRight(newspeed);
                        break;

                    case ES_EXIT:
                        break;

                    case FORCED:
                        nextState = Checking;
                        makeTransition = TRUE;
                        ThisEvent.EventType = ES_NO_EVENT;
                        //                        ThisEvent.EventParam = ThisEvent.EventParam;
                        break;


                    case ES_TIMEOUT:
                        //                        makeTransition = TRUE;
                        //                        ThisEvent.EventType = ES_NO_EVENT;
                        break;

                    default:
                        break;
                }
            }
            break;

        case Checking:
            if (ThisEvent.EventType != ES_NO_EVENT) { // An event is still active
                switch (ThisEvent.EventType) {

                    case ES_ENTRY:
                         PivotRight(speed*1.2);//(speed*.5);
                        //                        TurnRight(speed);
                        //                        StraightForward(speed);
                        //                        ES_Timer_InitTimer(replungetimer, 300);
                        break;

                    case ES_EXIT:
                        break;

                    case TAPE:
                        if ((ThisEvent.EventParam & 0x01) == 0x01) { // B
                            printf("\nback on\n");
                            aligning_start_time = ES_Timer_GetTime();
                            back_tape_flag = 1;
                            int i;
                            for(i = 0; i < 100000; i++)
                            {
                                asm("nop");
                            }
                            //                            nextState = Pivoting_Right_AC;
                            //                            makeTransition = TRUE;
                            ThisEvent.EventType = ES_NO_EVENT;
                        } else if (((ThisEvent.EventParam & 0b000001) == 0b000000) && back_tape_flag)   { // Back tape off T

                            aligning_end_time = ES_Timer_GetTime();
                            FullStop();
                            printf("\nback tape off\n");
                            int i;
                            for(i = 0; i < 100000; i++)
                            {
                                asm("nop");
                            }
                            aligning_difference_time = aligning_end_time - aligning_start_time;
//                            printf("\n\naligning_diff_time %d\n", aligning_difference_time);
                            nextState = Pivoting_Left_AC;
                            makeTransition = TRUE;
                            ThisEvent.EventType = ES_NO_EVENT;
                        }//                        if ((ThisEvent.EventParam & 0b110000) == 0b110000) { // LL, L: if miss most of the stem/land on T top
                            //                            nextState = Pivoting_Right_AC;
                            //                            makeTransition = TRUE;
                            //                            ThisEvent.EventType = ES_NO_EVENT;
                            //                        }
                            //                        else if ((ThisEvent.EventParam & 0b111100) == 0b111100) { // LL, L,F, R: if hit T stem head-on
                            //                            nextState = Turning_Right_AC;
                            //                            makeTransition = TRUE;
                            //                            ThisEvent.EventType = ES_NO_EVENT;
                            //                        } else if ((ThisEvent.EventParam & 0b100000) == 0b100000) { // LL entry
                            //                            nextState = Turning_Left_AC;
                            //                            makeTransition = TRUE;
                            //                            ThisEvent.EventType = ES_NO_EVENT;
                            //                        }
                        else {
                            ThisEvent.EventType = ES_NO_EVENT;
                        }
                        //                        else if ((ThisEvent.EventParam & T_Left) == T_Left) {
                        //                            nextState = Pivoting_Right;
                        //                            makeTransition = TRUE;
                        //                            ThisEvent.EventType = ES_NO_EVENT;
                        //                        } else if ((ThisEvent.EventParam & T_Right) == T_Right) {
                        //                            nextState = Pivoting_Left;
                        //                            makeTransition = TRUE;
                        //                            ThisEvent.EventType = ES_NO_EVENT;
                        //                        }
                        break;
                    case ES_TIMEOUT:
                        //                         nextState = Pivoting_Right_AC;
                        //                            makeTransition = TRUE;
                        //                            ThisEvent.EventType = ES_NO_EVENT;
                        //                        makeTransition = TRUE;
                        //                        ThisEvent.EventType = ES_NO_EVENT;
                        break;

                    default:
                        break;
                }
            }
            break;

        case Pivoting_Right_AC:
            if (ThisEvent.EventType != ES_NO_EVENT) {
                switch (ThisEvent.EventType) {
                    case ES_ENTRY:
                        PivotRight(tspeed * 1);
                        ES_Timer_InitTimer(replungetimer, 900);
                        break;

                        //                    case TAPE:
                        //                        if ((ThisEvent.EventParam & 0x01) == 0x01) { // B
                        //                            nextState = Reverse_Adjusting_Right;
                        //                            makeTransition = TRUE;
                        //                            ThisEvent.EventType = ES_NO_EVENT;
                        //                        }
                        //                        else {
                        //                            ThisEvent.EventType = ES_NO_EVENT;
                        //                        }
                        //                        break;


                    case ES_EXIT:
                        FullStop();
                        break;

                    case ES_TIMEOUT:
                        //                        nextState = Lost;
                        //                        makeTransition = TRUE;
                        //                        ThisEvent.EventType = ES_NO_EVENT;
                        if (ThisEvent.EventParam == replungetimer) {
                            nextState = Reverse_Adjusting_Right;
                            makeTransition = TRUE;
                            ThisEvent.EventType = ES_NO_EVENT;
                        }
                        break;

                    default:
                        break;
                }
            }
            break;

        case Pivoting_Left_AC:
            if (ThisEvent.EventType != ES_NO_EVENT) {
                switch (ThisEvent.EventType) {
                    case ES_ENTRY:
                        PivotLeft_WH(speed * .7);
                        int spintime = aligning_difference_time / 2;
                        //                        printf("\n\n%dcheck spin time\n", spintime);
                        ES_Timer_InitTimer(replungetimer, spintime);
                        break;

                    case ES_EXIT:
                        FullStop();
                        break;

                    case ES_TIMEOUT:
                        //                        nextState = Lost;
                        //                        makeTransition = TRUE;
                        //                        ThisEvent.EventType = ES_NO_EVENT;
                        if (ThisEvent.EventParam == replungetimer) {
                            FullStop();
                            //                            printf("\n\ncheck\n");
                            nextState = Reverse_Adjusting_Right;
                            makeTransition = TRUE;
                            ThisEvent.EventType = ES_NO_EVENT;
                        }
                        break;

                    default:
                        break;
                }
            }
            break;

        case Turning_Left_AC:
            //ThisEvent = Run_AA_LineFollowing_SubHSM(ThisEvent); // run sub-state machine for this state
            if (ThisEvent.EventType != ES_NO_EVENT) {
                switch (ThisEvent.EventType) {
                    case ES_ENTRY:
                        TurnLeft(speed);
                        break;

                    case TAPE:
                        if ((ThisEvent.EventParam & 0b000100) == 0b000100) { // R
                            nextState = Turning_Right_AC; //TODO: straight on
                            makeTransition = TRUE;
                            ThisEvent.EventType = ES_NO_EVENT;
                        } else {
                            ThisEvent.EventType = ES_NO_EVENT;
                        }
                        break;

                    case ES_EXIT:
                        FullStop();
                        break;

                    case ES_TIMEOUT:
                        //                        ThisEvent.EventType = ES_NO_EVENT;

                    default: break;
                }
            }
            break;

        case Turning_Right_AC:
            if (ThisEvent.EventType != ES_NO_EVENT) {
                switch (ThisEvent.EventType) {
                    case ES_ENTRY:
                        TurnRight(speed);
                        break;
                        //        case BUMPED:
                        //                nextState = Wall_Hugging;
                        //                makeTransition = TRUE;
                        //                ThisEvent.EventType = ES_NO_EVENT;
                        //                break;

                    case TAPE:
                        if ((ThisEvent.EventParam & 0x01) == 0x01) { // B
                            nextState = Reverse_Adjusting_Right;
                            makeTransition = TRUE;
                            ThisEvent.EventType = ES_NO_EVENT;
                        } else {
                            ThisEvent.EventType = ES_NO_EVENT;
                        }
                        break;


                    case ES_EXIT:
                        FullStop();
                        break;

                    case ES_TIMEOUT:
                        //                        nextState = Lost;
                        //                        makeTransition = TRUE;
                        //                        ThisEvent.EventType = ES_NO_EVENT;
                        break;

                    default: break;
                }
            }
            break;

        case Stopping_AC:
            FullStop();
            break;

        case Reversing_AC:
            if (ThisEvent.EventType != ES_NO_EVENT) {
                switch (ThisEvent.EventType) {
                    case ES_ENTRY:
                        StraightReverse(speed * 1.3);
                        ES_Timer_InitTimer(ammofindtimer, ammofindtimervalue);
                        break;

                    case ES_EXIT:
                        ES_Timer_StopTimer(ammofindtimer);
                        ES_Timer_StopTimer(portalsearchingtimer);
                        break;

                    case ES_TIMEOUT:
                        if (ThisEvent.EventParam == ammofindtimer) {
                            ES_Timer_InitTimer(portalsearchingtimer, 600);
                            StraightForward(speed);
                            ThisEvent.EventType = ES_NO_EVENT;
                        } else if (ThisEvent.EventParam == portalsearchingtimer) {
                            FullStop();
                            Tcontrol.EventType = AMMO;
                            Tcontrol.EventParam = 0;
                            ThisEvent.EventType = ES_NO_EVENT;
                            PostDagobotHSM(Tcontrol);
                        }

                        break;

                    default:
                        break;
                }
            }
            break;

        case Forwarding_AC:
            if (ThisEvent.EventType != ES_NO_EVENT) {
                switch (ThisEvent.EventType) {
                    case ES_ENTRY:
                        StraightForward(speed);
                        break;

                    case TAPE:
                        if ((ThisEvent.EventParam & 0b001000) == 0b000000) { // Front off the T
                            nextState = Reversing_AC;
                            makeTransition = TRUE;
                            ThisEvent.EventType = ES_NO_EVENT;
                        } else {
                            ThisEvent.EventType = ES_NO_EVENT;
                        }
                        break;

                    case ES_EXIT:
                        break;

                    case ES_TIMEOUT:
                        break;

                    default:
                        break;
                }
            }
            break;

        case Reverse_Adjusting_Right:
            if (ThisEvent.EventType != ES_NO_EVENT) {
                switch (ThisEvent.EventType) {
                    case ES_ENTRY:
                        //                        GentleLeft(-6 - .3); // backwards left = front of robot pivoting right
                        GentleRight(-6 - .3);
                        ES_Timer_InitTimer(replungetimer, replungetimervalue);
                        break;

                        //                    case TAPE:
                        //                        if ((ThisEvent.EventParam & 0b111110) == 0b000000) { // F
                        //                            nextState = Stopping_AC;
                        //                            makeTransition = TRUE;
                        //                            ThisEvent.EventType = ES_NO_EVENT;
                        //                        } else {
                        //                            ThisEvent.EventType = ES_NO_EVENT;
                        //                        }
                        //                        break;

                    case ES_EXIT:
                        ES_Timer_StopTimer(replungetimer);
                        break;

                    case ES_TIMEOUT:
                        if (ThisEvent.EventParam == replungetimer) {
                            nextState = Forwarding_AC;
                            makeTransition = TRUE;
                            ThisEvent.EventType = ES_NO_EVENT;
                        }
                        break;

                    default:
                        break;
                }
            }
            break;

        case Adjusting_Right_AC:
            if (ThisEvent.EventType != ES_NO_EVENT) { // An event is still active
                switch (ThisEvent.EventType) {
                    case ES_ENTRY:
                        GentleRight(speed);
                        break;

                    case TAPE:
                        if ((ThisEvent.EventParam & 0b011100) == 0b011100) { // L, C, R
                            nextState = Reverse_Adjusting_Right;
                            makeTransition = TRUE;
                            ThisEvent.EventType = ES_NO_EVENT;
                        } else {
                            ThisEvent.EventType = ES_NO_EVENT;
                        }
                        break;


                    case ES_EXIT:
                        break;
                }
            }
            break;

        case Reverse_Turning_Left:
            if (ThisEvent.EventType != ES_NO_EVENT) { // An event is still active
                switch (ThisEvent.EventType) {
                    case ES_ENTRY:
                        //ES_Timer_InitTimer(pivotingtimer, pivotingtimervalue);
                        ReverseLeft(speed); // fiz thinks this means reverse right // previously 5
                        ES_Timer_InitTimer(ammofindtimer, ammofindtimervalue);
                        break;

                        //                    case TAPE:
                        //                        if ((ThisEvent.EventParam & 0b011100) == 0b011100){ // L, C, R
                        //                            nextState = Reverse_Adjusting_Right;
                        //                            makeTransition = TRUE;
                        //                            ThisEvent.EventType = ES_NO_EVENT;
                        //                        }
                        //                        break;
                        //
                    case ES_TIMEOUT:
                        if (ThisEvent.EventParam == ammofindtimer) {
                            Tcontrol.EventType = MISSED_T;
                            Tcontrol.EventParam = 0;
                            PostDagobotHSM(Tcontrol);
                            ThisEvent.EventType = ES_NO_EVENT;
                        }
                        //                        else if (plungecount == 4){
                        //                            debug("Oh, shit!");
                        //                            nextState = Stopping_AC;
                        //                            makeTransition = TRUE;
                        //                            ThisEvent.EventType = ES_NO_EVENT;
                        //                            //TODO: Deal with later!
                        //                            // post event to pop into higher state
                        //                        }
                        break;

                    case ES_EXIT:
                        ES_Timer_StopTimer(ammofindtimer);
                        break;
                }
            }
            break;

        default: // all unhandled states fall into here
            break;
    } // end switch on Current State

    if (makeTransition == TRUE) {
        RunAlignCollect_SubHSM(EXIT_EVENT); // <- rename to your own Run function
        CurrentState = nextState;
        RunAlignCollect_SubHSM(ENTRY_EVENT); // <- rename to your own Run function
    }

    ES_Tail(); // trace call stack end
    return ThisEvent;
}
Example #4
0
/**
 * @Function RunExitHSM(ES_Event ThisEvent)
 * @param ThisEvent - the event (type and param) to be responded.
 * @return Event - return event (type and param), in general should be ES_NO_EVENT
 * @brief This function is where you implement the whole of the heirarchical state
 *        machine, as this is called any time a new event is passed to the event
 *        queue. This function will be called recursively to implement the correct
 *        order for a state transition to be: exit current state -> enter next state
 *        using the ES_EXIT and ES_ENTRY events.
 * @note Remember to rename to something appropriate.
 *       The lower level state machines are run first, to see if the event is dealt
 *       with there rather than at the current level. ES_EXIT and ES_ENTRY events are
 *       not consumed as these need to pass pack to the higher level state machine.
 * @author J. Edward Carryer, 2011.10.23 19:25
 * @author Gabriel H Elkaim, 2011.10.23 19:25 */
ES_Event RunExitHSM(ES_Event ThisEvent)
{
	uint8_t makeTransition = FALSE; // use to flag transition
	ExitState_t nextState;

	static uint8_t trackFlag = FALSE;	// used to check if track wire has been found
	static uint8_t turnedFlag = FALSE;  // used to check if we have flipped 180 already
	static uint8_t bounceCount = 0;		// make sure we dont get stuck in align states

	EventStorage args;

	ES_Tattle(); // trace call stack

	switch (CurrentState) {
	case Exit_Init: // If current state is initial Pseudo State
		if (ThisEvent.EventType == ES_INIT)// only respond to ES_Init
		{
			// Handle initialization of modules

			// Initialize sub HSMs

			// Move to real state
			// These are handled in main() instead
			nextState = Exit_Drive;
			makeTransition = TRUE;
			ThisEvent.EventType = ES_NO_EVENT;
			;
		}
		break;

	case Exit_Drive:
		if (ThisEvent.EventType != ES_NO_EVENT) { // An event is still active
			switch (ThisEvent.EventType) {
			case ES_ENTRY:
				// Drive forward
				Drive_Straight(MOTOR_SPEED_CRAWL);

				// Start timer for checking when we have driven far enough to have left the castle
				ES_Timer_InitTimer(EXIT_HSM_TIMER, TIME_EXIT_OUTSIDE);
				break;

			case ES_EXIT:
				// Stop the timer while we handle turns etc, it will restart on entry
				ES_Timer_StopTimer(EXIT_HSM_TIMER);

				Drive_Stop();
				break;

			case TRACK_FOUND:
				trackFlag = TRUE;

				// Consume
				ThisEvent.EventType = ES_NO_EVENT;
				break;

			case BUMPER:
				args.val = ThisEvent.EventParam;

				// if center tripped
				if (args.bits.event  & args.bits.type & BUMP_CENTER) {
					nextState = Exit_Straighten;
					makeTransition = TRUE;

					ThisEvent.EventType = ES_NO_EVENT;

				}
				// else if left tripped
				else if (args.bits.event & args.bits.type & BUMP_LEFT) {
					nextState = Exit_Align_Left;
					makeTransition = TRUE;

					ThisEvent.EventType = ES_NO_EVENT;
				}
				// else if right tripped
				else if (args.bits.event & args.bits.type & BUMP_RIGHT) {
					nextState = Exit_Align_Right;
					makeTransition = TRUE;

					ThisEvent.EventType = ES_NO_EVENT;
				}
				break;

			case ES_TIMEOUT:
				if (ThisEvent.EventParam == EXIT_HSM_TIMER) {
					// Turn 180
					if (turnedFlag) {
						nextState = Exit_Turn90;
					} else {
						nextState = Exit_Turn180;
					}
					makeTransition = TRUE;

					ThisEvent.EventType = ES_NO_EVENT;
				}
				break;

			default: // all unhandled events pass the event back up to the next level
				break;
			}
		}
		break;

	case Exit_Straighten:
		if (ThisEvent.EventType != ES_NO_EVENT) { // An event is active
			switch (ThisEvent.EventType) {
			case ES_ENTRY:
				// Drive straight to recheck bumps
				Drive_Straight(MOTOR_SPEED_CRAWL);

				++bounceCount;

				if (bounceCount == 8) {
					nextState = Exit_Backup;
					makeTransition = TRUE;
				}

				// Set the timeout
				ES_Timer_InitTimer(EXIT_HSM_TIMER, TIME_EXIT_STRAIGHTEN);
				break;

			case ES_EXIT:
				Drive_Stop();

				// Stop timer on exit
				ES_Timer_StopTimer(EXIT_HSM_TIMER);
				break;

			case TRACK_FOUND:
				trackFlag = TRUE;
				
				// Consume
				ThisEvent.EventType = ES_NO_EVENT;
				break;

			case BUMPER:
				args.val = ThisEvent.EventParam;

				// if left bumper and NOT right bumper
				if ((args.bits.type & BUMP_LEFT) && (~args.bits.type & BUMP_RIGHT)) {
					nextState = Exit_Align_Left;
					makeTransition = TRUE;

					ThisEvent.EventType = ES_NO_EVENT;
				}
				// else if right bumper and NOT left bumper
				else if ((args.bits.type & BUMP_RIGHT) && (~args.bits.type & BUMP_LEFT)) {
					nextState = Exit_Align_Right;
					makeTransition = TRUE;

					ThisEvent.EventType = ES_NO_EVENT;
				}
				// else if its right AND left or center it will time out and move to backup
				break;

			case ES_TIMEOUT:
				if (ThisEvent.EventParam == EXIT_HSM_TIMER) {
					if (trackFlag) {
						nextState = Exit_Done_Pause;
					} else {
						nextState = Exit_Backup;
					}
					makeTransition = TRUE;

					// Reset our bounce count, it has resolved a collision
					bounceCount = 0;

					ThisEvent.EventType = ES_NO_EVENT;
				}
				break;

			default: // all unhandled events pass the event back up to the next level
				break;
			}
		}
		break;

	// need a timeout for when the center cant be pressed
	case Exit_Align_Left:
		if (ThisEvent.EventType != ES_NO_EVENT) { // An event is active
			switch (ThisEvent.EventType) {
			case ES_ENTRY:
				// Turn into the wall to align
				Drive_Right(-MOTOR_SPEED_MEDIUM);

				ES_Timer_InitTimer(EXIT_HSM_TIMER, TIME_EXIT_ALIGN);
				break;

			case ES_EXIT:
				// Stop
				Drive_Stop();

				ES_Timer_StopTimer(EXIT_HSM_TIMER);
				break;

			case ES_TIMEOUT:
				if (ThisEvent.EventParam == EXIT_HSM_TIMER) {
					nextState = Exit_Straighten;
					makeTransition = TRUE;

					ThisEvent.EventType = ES_NO_EVENT;
				}
				break;

			default: // all unhandled events pass the event back up to the next level
				break;
			}
		}
		break;

	// need a timeout for when the center cant be pressed
	case Exit_Align_Right:
		if (ThisEvent.EventType != ES_NO_EVENT) { // An event is active
			switch (ThisEvent.EventType) {
			case ES_ENTRY:
				// Turn into the wall to align
				Drive_Left(-MOTOR_SPEED_MEDIUM);

				ES_Timer_InitTimer(EXIT_HSM_TIMER, TIME_EXIT_ALIGN);
				break;

			case ES_EXIT:
				// Stop
				Drive_Stop();

				ES_Timer_StopTimer(EXIT_HSM_TIMER);
				break;

			case ES_TIMEOUT:
				if (ThisEvent.EventParam == EXIT_HSM_TIMER) {
					nextState = Exit_Straighten;
					makeTransition = TRUE;

					ThisEvent.EventType = ES_NO_EVENT;
				}
				break;

			default: // all unhandled events pass the event back up to the next level
				break;
			}
		}
		break;

	case Exit_Backup:
		if (ThisEvent.EventType != ES_NO_EVENT) { // An event is active
			switch (ThisEvent.EventType) {
			case ES_ENTRY:
				Drive_Straight(-MOTOR_SPEED_CRAWL);

				ES_Timer_InitTimer(EXIT_HSM_TIMER, TIME_EXIT_BACKUP);
				break;

			case ES_EXIT:
				Drive_Stop();

				ES_Timer_StopTimer(EXIT_HSM_TIMER);
				break;

			case ES_TIMEOUT:
				if (ThisEvent.EventParam == EXIT_HSM_TIMER) {
					// Turn 90
					nextState = Exit_Turn90;
					makeTransition = TRUE;

					ThisEvent.EventType = ES_NO_EVENT;
				}
				break;

			default: // all unhandled events pass the event back up to the next level
				break;
			}
		}
		break;

	case Exit_Turn90:
		if (ThisEvent.EventType != ES_NO_EVENT) { // An event is active
			switch (ThisEvent.EventType) {
			case ES_ENTRY:
				Drive_TankRight(MOTOR_SPEED_EXPLORE);

				ES_Timer_InitTimer(EXIT_HSM_TIMER, MOTOR_TURN_EX_90);
				break;

			case ES_EXIT:
				Drive_Stop();

				ES_Timer_StopTimer(EXIT_HSM_TIMER);
				break;

			case ES_TIMEOUT:
				if (ThisEvent.EventParam == EXIT_HSM_TIMER) {
					nextState = Exit_Drive;
					makeTransition = TRUE;

					ThisEvent.EventType = ES_NO_EVENT;
				}
				break;

			default: // all unhandled events pass the event back up to the next level
				break;
			}
		}
		break;

	case Exit_Turn180:
		if (ThisEvent.EventType != ES_NO_EVENT) {
			switch (ThisEvent.EventType) {
			case ES_ENTRY:
				Drive_TankRight(MOTOR_SPEED_EXPLORE);

				// Set 180 turn flag true, don't do this state twice
				turnedFlag = TRUE;

				ES_Timer_InitTimer(EXIT_HSM_TIMER, MOTOR_TURN_EX_180);
				break;

			case ES_EXIT:
				Drive_Stop();

				ES_Timer_StopTimer(EXIT_HSM_TIMER);
				break;

			case ES_TIMEOUT:
				if (ThisEvent.EventParam == EXIT_HSM_TIMER) {
					nextState = Exit_Drive;
					makeTransition = TRUE;

					ThisEvent.EventType = ES_NO_EVENT;
				}
				break;

			default: // all unhandled events pass the event back up to the next level
				break;
			}
		}
		break;

	case Exit_Done_Pause:
		switch (ThisEvent.EventType) {
		case ES_ENTRY:
			// Reverse
			Drive_Straight(-MOTOR_SPEED_MEDIUM);

			ES_Timer_InitTimer(EXIT_HSM_TIMER, TIME_EXIT_BACKUP);
			break;

		case ES_EXIT:
			break;

		case ES_TIMEOUT:
			if (ThisEvent.EventParam == EXIT_HSM_TIMER) {
				Drive_Stop();

				ES_Timer_InitTimer(STALL_TIMER, STALL_TIME_IN_MS);

				ThisEvent.EventType = ES_NO_EVENT;
			} else if (ThisEvent.EventParam == STALL_TIMER) {
				nextState = Exit_Done_State;
				makeTransition = TRUE;

				ThisEvent.EventType = ES_NO_EVENT;
			}
			break;

		default:
			break;
		}
		break;
	
	case Exit_Done_State:
		switch (ThisEvent.EventType) {
		case ES_ENTRY:
			// Turn 180
			Drive_TankRight(MOTOR_SPEED_EXPLORE);

			ES_Timer_InitTimer(EXIT_HSM_TIMER, MOTOR_TURN_EX_180 - 10);
			break;

		case ES_EXIT:
			// Do nothing
			Drive_Stop();
			break;

		case ES_TIMEOUT:
			if (ThisEvent.EventParam == EXIT_HSM_TIMER) {
				Drive_Stop();

				ThisEvent.EventType = CHILD_DONE;
			}
			break;

		default: // all unhandled events pass the event back up to the next level
			break;
		}
		break;

	default: // all unhandled states fall into here
		break;
	} // end switch on Current State

	if (makeTransition == TRUE) { // making a state transition, send EXIT and ENTRY
		// recursively call the current state with an exit event
		RunExitHSM(EXIT_EVENT);
		CurrentState = nextState;
		RunExitHSM(ENTRY_EVENT);
	}

	ES_Tail(); // trace call stack end
	return ThisEvent;
}
/**
 * @Function RunEngage_DestroySubHSM(ES_Event ThisEvent)
 * @param ThisEvent - the event (type and param) to be responded.
 * @return Event - return event (type and param), in general should be ES_NO_EVENT
 * @brief This function is where you implement the whole of the heirarchical state
 *        machine, as this is called any time a new event is passed to the event
 *        queue. This function will be called recursively to implement the correct
 *        order for a state transition to be: exit current state -> enter next state
 *        using the ES_EXIT and ES_ENTRY events.
 * @note Remember to rename to something appropriate.
 *       The lower level state machines are run first, to see if the event is dealt
 *       with there rather than at the current level. ES_EXIT and ES_ENTRY events are
 *       not consumed as these need to pass pack to the higher level state machine.
 * @author J. Edward Carryer, 2011.10.23 19:25
 * @author Gabriel H Elkaim, 2011.10.23 19:25 */
ES_Event RunEngage_DestroySubHSM(ES_Event ThisEvent) {
    uint8_t makeTransition = FALSE; // use to flag transition
    SubEngage_DestroyState_t nextState;

    ES_Event eventtopost, donefiring;
    ES_Tattle(); // trace call stack


    switch (CurrentState) {
        case Init_ED: // If current state is initial Psedudo State
            if (ThisEvent.EventType == ES_INIT) {// only respond to ES_Init

                //call all substate run functions here
                InitEngage_Destroy_Wall_Hugging_SubHSM();

                nextState = Engage_Destroy_Searching;
                makeTransition = TRUE;
                ThisEvent.EventType = ES_NO_EVENT;
            }
            break;

        case Engage_Destroy_Searching:
            if (ThisEvent.EventType != ES_NO_EVENT) { // An event is still active
                switch (ThisEvent.EventType) {

                    case ES_ENTRY:
//                        ES_Timer_InitTimer(15, 2500); //TODO: Move to exit from acquiring_ammo
//                        PivotRight(speed);
//                        PivotRight(speed);
                        StraightForward(speed); //speed // move forwards away from the ammo dump
                        //pivot timer
                        // start pivoting
                        Dagobot_SetLoaderServo(1200);
                        ThisEvent.EventType = ES_NO_EVENT;
//                        ThisEvent.EventParam = 0;
//                        PostDagobotHSM(ThisEvent);
                        //TODO: Add flag to only go forwards if just from Acquiring_Ammo?

                        break;

//                    case AMMO:
//                        ThisEvent.EventType = ES_NO_EVENT;
//                        break;

                    case ES_EXIT:
                        FullStop(); // aimed at the enemy: stop and fire
                        ES_Timer_StopTimer(15);
                       // ES_Timer_StopTimer(forwardtimer);
                        break;

                    case SNIPED:
//                        debug("check event");
                         FullStop();
                        nextState = Firing;
                        makeTransition = TRUE;
                        ThisEvent.EventType = ES_NO_EVENT;
                        break;

                    case BUMPED:
                        nextState = Engage_Destroy_Wall_Hugging;
                        makeTransition = TRUE;
                        eventtopost.EventType = BUMP_CHECK;
                        eventtopost.EventParam = ThisEvent.EventParam;
//                          ThisEvent.EventType = BUMP_CHECK;
//                        ThisEvent.EventParam = ThisEvent.EventParam;
                        PostDagobotHSM(eventtopost);
                        break;
//
//                    case TAPE:
//                        nextState = Redirecting;
//                        makeTransition = TRUE;
//                        ThisEvent.EventType = ES_NO_EVENT;
//                        break;

                    case ES_TIMEOUT:
                        //if (ThisEvent.EventParam == forwardtimer) {
                        //    ES_Timer_InitTimer(pivotingtimer, 800);
                        //    PivotRight(newspeed);
                        //}
//                        if (ThisEvent.EventParam == 15) {
//                            FullStop(); // stop after spinning
//                            StraightForward(speed*1.25); // didn't find enemy, head towards obstacle (or at least forwards)
//                        }

//                        ThisEvent.EventType = ES_NO_EVENT;
                        break;

                    default: // all unhandled events pass the event back up to the next level
                        break;
                }
            }
            break;

        case Firing:
            if (ThisEvent.EventType != ES_NO_EVENT) { // An event is active
                switch (ThisEvent.EventType) {
                    case ES_ENTRY:
//                        int AmmoState = Dagobot_ReadLoaderTape();
//                        if (AmmoState == 1) { // have ammo!
//                        debug("check");
                            FullStop();
                            ES_Timer_InitTimer(ammofindtimer, 2000); // head towards deadbot
                            StraightForward(speed);
//                        }
                        break;
                        
//                    case SNIPED:
//                        if(ThisEvent.EventParam == 0)
//                        {
//                            
//                        }

//                    case BUMPED:
//                        if ((ThisEvent.EventParam & FRONT_LEFT_BUMP) == FRONT_LEFT_BUMP) { // front left bump
//
//                                ThisEvent.EventType = ES_NO_EVENT;
//                            } else if ((ThisEvent.EventParam & FRONT_RIGHT_BUMP) == FRONT_RIGHT_BUMP) { // front right bump
//                                nextState = Reversing_WH;
//                                makeTransition = TRUE;
//                                ThisEvent.EventType = ES_NO_EVENT;
//                            } else if ((ThisEvent.EventParam & FRONT_BUMPS) == FRONT_BUMPS) { // both front bumpers
//                                nextState = Reversing_WH;
//                                makeTransition = TRUE;
//                                ThisEvent.EventType = ES_NO_EVENT;
//                            }
//                        else {
//                            ThisEvent.EventType = ES_NO_EVENT;
//                        }
//                        break;

                    case ES_EXIT:
//                        ES_TIMER_StopTimer(motortimer);
                        Dagobot_SetLoaderServo(1200);
                        ES_Timer_StopTimer(shootingtimer);
                        ES_Timer_StopTimer(ammofindtimer);
//                        ThisEvent.EventType = ES_NO_EVENT; //TODO: remove??
                        break;

                    case ES_TIMEOUT:
                        if(ThisEvent.EventParam == ammofindtimer){
                            FullStop();
                            int i;
                            for(i = 0; i < 30000; i++)
                            {
                                asm("nop");
                            }
                            Dagobot_SetLoaderServo(2000); // start running up motor
                            ES_Timer_InitTimer(shootingtimer, shootingtimervalue);
                            ThisEvent.EventType = ES_NO_EVENT;
                        }
//                        if (ThisEvent.EventParam == motortimervalue) {//done spinning up motor
//                            Dagobot_SetLoaderServo(servorelease); // drop balls into shooter
//                            ES_Timer_InitTimer(shootingtimer, shootingtimervalue);
//                        }
                        if (ThisEvent.EventParam == shootingtimer) {
                            donefiring.EventType = DONE_FIRING; // upper level deal with getting to portal
                            donefiring.EventParam = 0;
                            PostDagobotHSM(donefiring);
                            ThisEvent.EventType = ES_NO_EVENT;
                        }
                        break;

                    default: // all unhandled events pass the event back up to the next level
                        break;
                }
            }
            break;

        case Engage_Destroy_Wall_Hugging:
            ThisEvent = RunEngage_Destroy_Wall_Hugging_SubHSM(ThisEvent); // run sub-state machine for this state
            //TODO: make new wall_hugging file/fn?
            // and/or deal with entry from differet events
            
            if (ThisEvent.EventType != ES_NO_EVENT) { // An event is active
                switch (ThisEvent.EventType) {
                    case ES_ENTRY:
                        // this is where you would put any actions associated with the
                        // entry to this state
//                        ES_Timer_InitTimer(wallhuggingtimer, 8000);
                        break;

                    case SNIPED:
                         FullStop();
                        nextState = Firing;
                        makeTransition = TRUE;
                        ThisEvent.EventType = ES_NO_EVENT;
                        break;

//                    case TAPE:
//                        if((ThisEvent.EventParam & 0x000010) != 0x000010) {
//                        nextState = Redirecting;
//                        makeTransition = TRUE;
//                        ThisEvent.EventType = ES_NO_EVENT;
//                        }
//                        break;

                    case ES_EXIT:
                        // this is where you would put any actions associated with the
                        // exit from this state
//                        ES_Timer_StopTimer(wallhuggingtimer);
                        FullStop();
                        break;

                    case ES_TIMEOUT:
//                        if (ThisEvent.EventParam == wallhuggingtimer) { // timer to check for enemy every once in a while while bumping around
//                            //TODO: make new checkin timer?
//                            nextState = Engage_Destroy_Searching; // search
//                            makeTransition = TRUE;
//                            ThisEvent.EventType = ES_NO_EVENT;
//
//                        }
                        break;

                    default: // all unhandled events pass the event back up to the next level
                        break;
                }
            }
            break;

        case Redirecting:
            if (ThisEvent.EventType != ES_NO_EVENT) {
                switch (ThisEvent.EventType) {
                    case ES_ENTRY:
                        PivotRight(speed);
                        ES_Timer_InitTimer(pivotingtimer, pivotingtimervalue);
                        break;



                    case ES_EXIT:
                        ES_Timer_StopTimer(pivotingtimer);
                        //                        ThisEvent.EventType = ES_NO_EVENT;
                        break;

                    case ES_TIMEOUT:
                        if (ThisEvent.EventParam = pivotingtimer) {
                            nextState = Engage_Destroy_Searching; // search
                            makeTransition = TRUE;
                            ThisEvent.EventType = ES_NO_EVENT; // head for whatever's in the future
                        }

                        break;

                    default: // all unhandled events pass the event back up to the next level
                        break;
                }
            }
            break;


        default: // all unhandled states fall into here
            break;
    } // end switch on Current State

    if (makeTransition == TRUE) { // making a state transition, send EXIT and ENTRY
        // recursively call the current state with an exit event
        RunEngage_DestroySubHSM(EXIT_EVENT); // <- rename to your own Run function
        CurrentState = nextState;
        RunEngage_DestroySubHSM(ENTRY_EVENT); // <- rename to your own Run function
    }

    ES_Tail(); // trace call stack end
    return ThisEvent;
}
/**
 * @Function RunLine_FollowingSubHSM(ES_Event ThisEvent)
 * @param ThisEvent - the event (type and param) to be responded.
 * @return Event - return event (type and param), in general should be ES_NO_EVENT
 * @brief This function is where you implement the whole of the heirarchical state
 *        machine, as this is called any time a new event is passed to the event
 *        queue. This function will be called recursively to implement the correct
 *        order for a state transition to be: exit current state -> enter next state
 *        using the ES_EXIT and ES_ENTRY events.
 * @note Remember to rename to something appropriate.
 *       The lower level state machines are run first, to see if the event is dealt
 *       with there rather than at the current level. ES_EXIT and ES_ENTRY events are
 *       not consumed as these need to pass pack to the higher level state machine.
 * @author J. Edward Carryer, 2011.10.23 19:25
 * @author Gabriel H Elkaim, 2011.10.23 19:25 */
ES_Event Run_AA_LineFollowing_SubHSM(ES_Event ThisEvent) {
    uint8_t makeTransition = FALSE; // use to flag transition
    AA_LineFollowing_subHSM_t nextState; // <- change type to correct enum

    ES_Tattle(); // trace call stack

    switch (CurrentState) {
        case Init_AA_LineFollowing: // If current state is initial Psedudo State
            if (ThisEvent.EventType == ES_INIT)// only respond to ES_Init
            {
                nextState = EntryLineFollowing;
                makeTransition = TRUE;
                ThisEvent.EventType = ES_NO_EVENT;
            }
            break;

        case EntryLineFollowing:
            if (ThisEvent.EventType != ES_NO_EVENT) { // An event is still active
                switch (ThisEvent.EventType) {
                    case ES_ENTRY:
                        StraightForward(speed);
                        break;

                    case ES_EXIT:
                        break;

                    case TAPE:
                        if (ThisEvent.EventParam == 0b100000) { // LL: 20, 100000
                            FullStop();
                            nextState = Adjusting_Left;
                            makeTransition = TRUE;
                            ThisEvent.EventType = ES_NO_EVENT;
                        } else if (ThisEvent.EventParam == 0b000010) { // RR: 02
                            FullStop();
                            nextState = Pivoting_Right;
                            makeTransition = TRUE;
                            ThisEvent.EventType = ES_NO_EVENT;
                        } else if ((ThisEvent.EventParam & 0b110010) == 0b110010) { // LL, L,  RR
                            FullStop();
                            nextState = Reversing_Left;
                            makeTransition = TRUE;
                            ThisEvent.EventType = ES_NO_EVENT;
                        } else if ((ThisEvent.EventParam & 0b001001) == 0b001001) { // F, B
                            FullStop();
                            nextState = Adjusting_Right;
                            makeTransition = TRUE;
                            ThisEvent.EventType = ES_NO_EVENT;
                        } else {
                            ThisEvent.EventType = ES_NO_EVENT;
                        }
                        break;
                }
            }
            break;

        case Adjusting_Left:
            if (ThisEvent.EventType != ES_NO_EVENT) { // An event is still active
                switch (ThisEvent.EventType) {
                    case ES_ENTRY:
                        TurnLeft(speed * 1);
                        break;

                    case TAPE:
                        if ((ThisEvent.EventParam & 0b000010) == 0b000010) { // RR (corner)
                            nextState = Pivoting_Right;
                            makeTransition = TRUE;
                            ThisEvent.EventType = ES_NO_EVENT;
                        } else if ((ThisEvent.EventParam & 0b001000) == 0b001000) { //F
                            FullStop();
                            nextState = Adjusting_Right; //Adjusting_Right
                            makeTransition = TRUE;
                            ThisEvent.EventType = ES_NO_EVENT;
                        } else {
                            ThisEvent.EventType = ES_NO_EVENT;
                        }
                        break;

                    case ES_EXIT:
                        break;
                }
            }
            break;

        case Adjusting_Right:
            if (ThisEvent.EventType != ES_NO_EVENT) { // An event is still active
                switch (ThisEvent.EventType) {
                    case ES_ENTRY:
                        TurnRight(speed * 1);
                        break;

                    case TAPE:
                        if ((ThisEvent.EventParam & 0b010000) == 0b010000) { // L
                            FullStop();
                            nextState = Adjusting_Left;
                            makeTransition = TRUE;
                            ThisEvent.EventType = ES_NO_EVENT;
                        } else if ((ThisEvent.EventParam & 0b100000) == 0b100000) { // LL
                            FullStop();
                            nextState = Adjusting_Left;
                            makeTransition = TRUE;
                            ThisEvent.EventType = ES_NO_EVENT;
                        } else if ((ThisEvent.EventParam & 0b000010) == 0b000010) { // RR (corner)
                            nextState = Pivoting_Right;
                            makeTransition = TRUE;
                            ThisEvent.EventType = ES_NO_EVENT;
                        } else if ((ThisEvent.EventParam & 0b000110) == 0b000110) { //R, RR (corner)
                            nextState = Pivoting_Right;
                            makeTransition = TRUE;
                            ThisEvent.EventType = ES_NO_EVENT;
                        } else {
                            ThisEvent.EventType = ES_NO_EVENT;
                        }
                        break;

                    case ES_EXIT:
                        break;
                }
            }
            break;

        case Pivoting_Right:
            if (ThisEvent.EventType != ES_NO_EVENT) { // An event is still active
                switch (ThisEvent.EventType) {
                    case ES_ENTRY:
                        ES_Timer_InitTimer(ammofindtimer, 2000);
                        PivotRight(speed);
                        break;

                    case ES_EXIT:
                        ES_Timer_StopTimer(ammofindtimer);
                        break;

                    case TAPE:

                        if ((ThisEvent.EventParam & 0b110010) == 0b110010) { // LL, L, RR
                            nextState = Reversing_Left;
                            makeTransition = TRUE;
                            ThisEvent.EventType = ES_NO_EVENT;
                        } else if ((ThisEvent.EventParam & 0b010000) == 0b010000) { // L
                            FullStop();
                            nextState = Adjusting_Left;
                            makeTransition = TRUE;
                            ThisEvent.EventType = ES_NO_EVENT;
                        } else if ((ThisEvent.EventParam & 0b100001) == 0b100001) { // LL, B
                            nextState = Adjusting_Left;
                            makeTransition = TRUE;
                            ThisEvent.EventType = ES_NO_EVENT;
                        } else if ((ThisEvent.EventParam & 0b100000) == 0b100000) { // LL
                            nextState = Adjusting_Left;
                            makeTransition = TRUE;
                            ThisEvent.EventType = ES_NO_EVENT;
                        }
                        else {
                            ThisEvent.EventType = ES_NO_EVENT;
                        }
                        break;

                    case ES_TIMEOUT:
                        if (ThisEvent.EventParam == ammofindtimer) {
                            nextState = EntryLineFollowing;
                            makeTransition = TRUE;
                            ThisEvent.EventType = ES_NO_EVENT;
                        }
                        break;
                }
            }
            break;

        case Reversing_Left:
            if (ThisEvent.EventType != ES_NO_EVENT) { // An event is still active
                switch (ThisEvent.EventType) {
                    case ES_ENTRY:
                        ES_Timer_InitTimer(turningtimer, turningtimervalue);
                        TurnLeft(-(speed));
                        break;

                    case ES_EXIT:
                        ES_Timer_StopTimer(turningtimer);
                        break;

                    case ES_TIMEOUT:
                        nextState = Adjusting_Left;
                        makeTransition = TRUE;
                        ThisEvent.EventType = ES_NO_EVENT;


                    case TAPE:
                        if ((ThisEvent.EventParam & 0b100000) == 0b100000) { // LL
                            nextState = Adjusting_Left;
                            makeTransition = TRUE;
                            ThisEvent.EventType = ES_NO_EVENT;
                        } else {
                            ThisEvent.EventType = ES_NO_EVENT;
                        }
                        break;
                }
            }
            break;

        default: // all unhandled states fall into here
            break;
    } // end switch on Current State


    if (makeTransition == TRUE) { // making a state transition, send EXIT and ENTRY
        // recursively call the current state with an exit event
        Run_AA_LineFollowing_SubHSM(EXIT_EVENT);
        CurrentState = nextState;
        Run_AA_LineFollowing_SubHSM(ENTRY_EVENT);
    }

    ES_Tail(); // trace call stack end
    return ThisEvent;
}