/****************************************************************************

 Module

   CrewService.c


 Revision

   1.0.1


 Description

   This is a template file for implementing a simple service under the

   Gen2 Events and Services Framework.


 Notes


 History

 When           Who     What/Why

 -------------- ---     --------

 01/16/12 09:58 jec      began conversion from TemplateFSM.c

****************************************************************************/

/*----------------------------- Include Files -----------------------------*/

/* include header files for this state machine as well as any machines at the

   next lower level in the hierarchy that are sub-machines to this machine

*/

//This Module

#include "CrewService.h"


#include "ES_Configure.h"

#include "ES_Framework.h"

#include "dbprintf.h"

#include "DebouncingService.h"

#include "MasterService.h"

#include "LEDService.h"

#include "Servo.h"

#include "PIC32_AD_Lib.h"


/*----------------------------- Module Defines ----------------------------*/

#define ONE_SEC 1000

#define CREW_UPDATE_FREQUENCY 10

#define CREW_UPDATE_SEC (ONE_SEC /CREW_UPDATE_FREQUENCY)


#define MAX_POSITION 6400

#define MIN_POSITION 0

#define NEUTRAL_POSITION ((MAX_POSITION + MIN_POSITION)/2)

#define MAX_SPEED 5000

#define MAX_MIC_VOLUME 1023

#define MIN_MIC_VOLUME 0

#define ROWS_LEDMATRIX 32


#define AD_CHANNEL (1<<5)

#define NUM_AD_CHANNELS 1

/*---------------------------- Module Functions ---------------------------*/

/* prototypes for private functions for this service.They should be functions

   relevant to the behavior of this service

*/


/*---------------------------- Module Variables ---------------------------*/

// with the introduction of Gen2, we need a module level Priority variable

static uint8_t MyPriority;

static int32_t CurrentAD_Value[NUM_AD_CHANNELS];

static int16_t MicVolume = 0;

static int16_t NormalizedCrewPosition = 16;


Crew_Movement_t CrewMovement;

CrewServiceState_t CurrentState = InitCrew;

CrewServiceState_t NextState = InitCrew;

/*------------------------------ Module Code ------------------------------*/


/****************************************************************************

 Function

     InitCrewService


 Parameters

     uint8_t : the priorty of this service


 Returns

     bool, false if error in initialization, true otherwise


 Description

     Saves away the priority, and does any

     other required initialization for this service

 Notes


 Author

     J. Edward Carryer, 01/16/12, 10:00

****************************************************************************/

bool InitCrewService(uint8_t Priority)

{

    Declare ThisEvent as ES_Event_t

    Set MyPriority to Priority


    Configure ADC for AutoScan on AD_CHANNEL

    Call ADC_MultiRead(CurrentAD_Value)


    Initialize CrewMovement:

        Set Direction to Stop

        Set Position to NEUTRAL_POSITION

        Set Speed to MAX_SPEED divided by 10


    Set ThisEvent.EventType to ES_INIT

    If ES_PostToService(MyPriority, ThisEvent) returns true:

        Return true

    Else:

        Return false

    EndIf

}


/****************************************************************************

 Function

     PostCrewService


 Parameters

     EF_Event_t ThisEvent ,the event to post to the queue


 Returns

     bool false if the Enqueue operation failed, true otherwise


 Description

     Posts an event to this state machine's queue

 Notes


 Author

     J. Edward Carryer, 10/23/11, 19:25

****************************************************************************/

bool PostCrewService(ES_Event_t ThisEvent)

{

  return ES_PostToService(MyPriority, ThisEvent);

}


/****************************************************************************

 Function

    RunCrewService


 Parameters

   ES_Event_t : the event to process


 Returns

   ES_Event, ES_NO_EVENT if no error ES_ERROR otherwise


 Description

   add your description here

 Notes


 Author

   J. Edward Carryer, 01/15/12, 15:23

****************************************************************************/

ES_Event_t RunCrewService(ES_Event_t ThisEvent)

{

    Declare ReturnEvent as ES_Event_t

    Set ReturnEvent.EventType to ES_NO_EVENT (assume no errors)

    Declare UserInteract as ES_Event_t


    Switch CurrentState:

        Case InitCrew:

            If ThisEvent is GAME_START:

                Set NextState to Idle

                Set CrewMovement.Direction to Stop

                Set CrewMovement.Position to NEUTRAL_POSITION

                Set CrewMovement.Speed to MAX_SPEED divided by 10


        Case Idle:

            If ThisEvent is LEFT_DOWN:

                Set NextState to Left_Down

                Set CrewMovement.Direction to Left

                Initialize CREWSERVICE_TIMER with CREW_UPDATE_SEC

            Else If ThisEvent is RIGHT_DOWN:

                Set NextState to Right_Down

                Set CrewMovement.Direction to Right

                Initialize CREWSERVICE_TIMER with CREW_UPDATE_SEC

            Else If ThisEvent is USER_LEFT, WIN, or LOSE:

                Set NextState to InitCrew


        Case Left_Down:

            If ThisEvent is LEFT_UP:

                Set NextState to Idle

                Set CrewMovement.Direction to Stop

            Else If ThisEvent is RIGHT_DOWN:

                Set NextState to Both_Down

                Set CrewMovement.Direction to Stop

            Else If ThisEvent is ES_TIMEOUT and Timer is CREWSERVICE_TIMER:

                Set NextState to Left_Down

                Initialize CREWSERVICE_TIMER with CREW_UPDATE_SEC

                Call UpdateCrewPosition()

            If ThisEvent is USER_LEFT, WIN, or LOSE:

                Set NextState to InitCrew

            Set UserInteract to PLAYING

            Post UserInteract to MasterService


        Case Right_Down:

            If ThisEvent is RIGHT_UP:

                Set NextState to Idle

                Set CrewMovement.Direction to Stop

            Else If ThisEvent is LEFT_DOWN:

                Set NextState to Both_Down

                Set CrewMovement.Direction to Stop

            Else If ThisEvent is ES_TIMEOUT and Timer is CREWSERVICE_TIMER:

                Set NextState to Right_Down

                Initialize CREWSERVICE_TIMER with CREW_UPDATE_SEC

                Call UpdateCrewPosition()

            If ThisEvent is USER_LEFT, WIN, or LOSE:

                Set NextState to InitCrew

            Set UserInteract to PLAYING

            Post UserInteract to MasterService


        Case Both_Down:

            If ThisEvent is LEFT_UP:

                Set NextState to Right_Down

                Set CrewMovement.Direction to Right

                Initialize CREWSERVICE_TIMER with CREW_UPDATE_SEC

            Else If ThisEvent.EventType is RIGHT_UP:

                Set NextState to Left_Down

                Set CrewMovement.Direction to Left

                Initialize CREWSERVICE_TIMER with CREW_UPDATE_SEC

            If ThisEvent is USER_LEFT, WIN, or LOSE:

                Set NextState to InitCrew

            Set UserInteract to PLAYING

            Post UserInteract to MasterService


        Default:

            Do nothing


    EndSwitch


    Set CurrentState to NextState

    Return ReturnEvent

}


/***************************************************************************

 private functions

 ***************************************************************************/

void UpdateCrewSpeed(void)

{

    Read microphone input

    Set MicVolume to the absolute value of the first ADC reading


    Calculate CrewMovement.Speed as:

        MAX_SPEED * (MicVolume - MIN_MIC_VOLUME) / (MAX_MIC_VOLUME - MIN_MIC_VOLUME)

    Return

}


void UpdateCrewPosition(void)

{

    Create a new event CrewPositionEvent with default EventParam = 16

    update CrewMovement.Speed


    If CrewMovement.Direction is Left:

        If CrewMovement.Position is larger than MIN_POSITION:

            Decrease CrewMovement.Position by CrewMovement.Speed / CREW_UPDATE_FREQUENCY

        Else:

            Set CrewMovement.Position to MIN_POSITION


    If CrewMovement.Direction is Right:

        If CrewMovement.Position is less than MAX_POSITION:

            Increase CrewMovement.Position by CrewMovement.Speed / CREW_UPDATE_FREQUENCY

        Else:

            Set CrewMovement.Position to MAX_POSITION


    Normalize CrewMovement.Position to fit the LED matrix range:

        NormalizedCrewPosition = (ROWS_LEDMATRIX - 1) * CrewMovement.Position / (MAX_POSITION - MIN_POSITION)


    Set CrewPositionEvent.EventType to NEW_CREW_POSITION

    Set CrewPositionEvent.EventParam to NormalizedCrewPosition


    Post CrewPositionEvent to LEDService and ServoService


    Return

}

/*------------------------------- Footnotes -------------------------------*/

/*------------------------------ End of file *------------------------------*/