Programme carte strategie (disco)

Dependencies:   mbed SerialHalfDuplex SDFileSystem DISCO-F469NI_portrait liaison_Bluetooth ident_crac

Strategie/Strategie.cpp

Committer:
ClementBreteau
Date:
2017-05-22
Revision:
18:cc5fec34ed9c
Parent:
16:7321fb3bb396
Child:
20:de595e4ff01d

File content as of revision 18:cc5fec34ed9c:

 #include "Strategie.h"

E_stratGameEtat     gameEtat  = ETAT_CHECK_CARTE_SCREEN;
E_stratGameEtat     lastEtat  = ETAT_CHECK_CARTE_SCREEN;
unsigned char screenChecktry = 0;
Timer cartesCheker;//Le timer pour le timeout de la vérification des cartes
Timer fakeJack;
Timer gameTimer;
Timer debugetatTimer;
Timer timeoutWarning;
Timer timeoutWarningWaitEnd;
Timeout chronoEnd;//permet d'envoyer la trame CAN pour la fin 

unsigned short waitingAckID = 0;//L'id du ack attendu
unsigned short waitingAckFrom = 0;//La provenance du ack attendu
char modeTelemetre; // Si à 1, indique que l'on attend une reponse du telemetre 
//unsigned short telemetreDistance = 0;
signed char FIFO_lecture=0;//Position du fifo de lecture des messages CAN

signed short x_robot,y_robot,theta_robot;//La position du robot

signed short start_move_x,start_move_y,start_move_theta;//La position du robot lors du début d'un mouvement, utilisé pour reprendre le mouvement apres stop balise

#ifdef ROBOT_BIG
//unsigned short id_check[NOMBRE_CARTES]= {CHECK_BALISE,CHECK_MOTEUR,CHECK_ACTIONNEURS,CHECK_AX12,CHECK_POMPES};
//unsigned short id_alive[NOMBRE_CARTES]= {ALIVE_BALISE,ALIVE_MOTEUR,ALIVE_ACTIONNEURS,ALIVE_AX12,ALIVE_POMPES};

unsigned short id_check[NOMBRE_CARTES]= {CHECK_MOTEUR,CHECK_MOTEUR};
unsigned short id_alive[NOMBRE_CARTES]= {ALIVE_MOTEUR,ALIVE_MOTEUR};

InterruptIn jack(p25); //  entrée analogique en interruption pour le jack
#else
//unsigned short id_check[NOMBRE_CARTES]= {CHECK_BALISE,CHECK_MOTEUR,CHECK_ACTIONNEURS};
//unsigned short id_alive[NOMBRE_CARTES]= {ALIVE_BALISE,ALIVE_MOTEUR,ALIVE_ACTIONNEURS};

unsigned short id_check[NOMBRE_CARTES]= {CHECK_MOTEUR};
unsigned short id_alive[NOMBRE_CARTES]= {ALIVE_MOTEUR};

InterruptIn jack(p25); //  entrée analogique en interruption pour le jack
#endif
unsigned char checkCurrent = 0;
unsigned char countAliveCard = 0; 

unsigned char InversStrat = 1;//Si à 1, indique que l'on part de l'autre cote de la table(inversion des Y)

unsigned char ModeDemo = 0; // Si à 1, indique que l'on est dans le mode demo

unsigned char countRobotNear = 0;//Le nombre de robot à proximité

unsigned char ingnorBaliseOnce = 0;


/****************************************************************************************/
/* FUNCTION NAME: chronometre_ISR                                                       */
/* DESCRIPTION  : Interruption à la fin des 90s du match                                */
/****************************************************************************************/
void chronometre_ISR (void)
{
    SendRawId(ASSERVISSEMENT_STOP);//On stope les moteurs
    SendRawId(GLOBAL_GAME_END);//Indication fin de match
    gameTimer.stop();//Arret du timer

#ifdef ROBOT_BIG
    wait_ms(2000);
    doFunnyAction();
#endif
    
    while(1);//On bloque la programme dans l'interruption
}

/****************************************************************************************/
/* FUNCTION NAME: jack_ISR                                                              */
/* DESCRIPTION  : Interruption en changement d'état sur le Jack                         */
/****************************************************************************************/
void jack_ISR (void)
{
    if(gameEtat == ETAT_GAME_WAIT_FOR_JACK) {
        led4=1;
        gameEtat = ETAT_GAME_START;//On débute le match
    }
}

/****************************************************************************************/
/* FUNCTION NAME: automate_process                                                      */
/* DESCRIPTION  : Automate de gestion de la stratégie du robot                          */
/****************************************************************************************/
void automate_process(void)
{
    static struct S_Instruction instruction;
    static unsigned char AX12_enchainement = 0;
    static unsigned char MV_enchainement = 0;
    signed char localData1 = 0;
    signed short localData2 = 0;
    unsigned short localData3 = 0;
    //signed short localData4 = 0;
    unsigned char localData5 = 0;
    
    if(gameTimer.read_ms() >= 89000) {//Fin du match (On autorise 2s pour déposer des éléments
        gameTimer.stop();
        gameTimer.reset();
        gameEtat = ETAT_END;//Fin du temps
    }
    
    if(lastEtat != gameEtat || debugetatTimer.read_ms() >= 1000) {
        lastEtat = gameEtat;
        debugetatTimer.reset();
        sendStratEtat((unsigned char)gameEtat, (unsigned char)actual_instruction);
    }
    
    switch(gameEtat)
    {
        case ETAT_CHECK_CARTE_SCREEN:
            /*
            Verification de l'état de la carte ecran
            */
            waitingAckFrom = ALIVE_IHM;//On indique que l'on attend un ack de la carte IHM
            SendRawId(CHECK_IHM);//On demande à la carte IHM d'insiquer ça présence
            
            screenChecktry++;//On incrèment le conteur de tentative de 1
            cartesCheker.reset();//On reset le timeOut
            cartesCheker.start();//On lance le timer pour le timeout
            gameEtat = ETAT_CHECK_CARTE_SCREEN_WAIT_ACK;
            
            //gameEtat = ETAT_GAME_START;
            
        break;
        case ETAT_CHECK_CARTE_SCREEN_WAIT_ACK:
            /*
            Attente du ALIVE de la carte écran.
            
            Si la carte ne répond pas apres 10ms, on retoune dans l'etat ETAT_CHECK_CARTE_SCREEN
            maximum 3 tentatives
            Si pas de réponse, clignotement de toutes les leds possible
            */
            if(waitingAckFrom == 0) {//C'est bon la carte est en ligne
                cartesCheker.stop();
                screenChecktry = 0;
                gameEtat = ETAT_CHECK_CARTES;
            } else if(cartesCheker.read_ms () > 100) {
                cartesCheker.stop();
                if(screenChecktry >=3) {
                    errorLoop();//Erreur La carte IHM n'est pas en ligne
                } else {
                    gameEtat = ETAT_CHECK_CARTE_SCREEN;
                }
            }
        break;
        case ETAT_CHECK_CARTES:
            /*
            Il faut faire une boucle pour verifier toutes les cartes les une apres les autres
            */
            waitingAckFrom = id_alive[checkCurrent];//On indique que l'on attend un ack de la carte IHM
            SendRawId(id_check[checkCurrent]);//On demande à la carte d'indiquer ça présence
            
            screenChecktry++;//On incrèment le conteur de tentative de 1
            cartesCheker.reset();//On reset le timeOut
            cartesCheker.start();//On lance le timer pour le timeout
            gameEtat = ETAT_CHECK_CARTES_WAIT_ACK;
            
            
            
            
        break;
        case ETAT_CHECK_CARTES_WAIT_ACK:
            /*
            On attend l'ack de la carte en cours de vérification
            */
            //printf("cartesCheker = %d waitingAckFrom = %d\n",cartesCheker.read_ms(), waitingAckFrom);
            if(waitingAckFrom == 0) {//C'est bon la carte est en ligne
                cartesCheker.stop();
                screenChecktry = 0;
                countAliveCard++;
                checkCurrent++;
                if(checkCurrent >= NOMBRE_CARTES) {
                    //printf("all card check, missing %d cards\n",(NOMBRE_CARTES-countAliveCard));
                    if(countAliveCard >= NOMBRE_CARTES) {
                        gameEtat = ETAT_CONFIG;
                        SendRawId(ECRAN_ALL_CHECK);//On dit à l'IHM que toutes les cartes sont en ligne
                        tactile_printf("Selection couleur et strategie");
                    } else {
                        gameEtat = ETAT_WAIT_FORCE;//Passage en attente de forçage du lancement
                        waitingAckFrom = ECRAN_ALL_CHECK;
                    }
                } else {
                    gameEtat = ETAT_CHECK_CARTES;
                }
            } else if(cartesCheker.read_ms () > 100) {
                cartesCheker.stop();
                if(screenChecktry >=3) {
                    //printf("missing card %d\n",id_check[checkCurrent]);
                    screenChecktry = 0;
                    checkCurrent++;
                    
                    if(checkCurrent >= NOMBRE_CARTES) {
                        if(countAliveCard == NOMBRE_CARTES) {
                            gameEtat = ETAT_CONFIG;
                            SendRawId(ECRAN_ALL_CHECK);//On dit à l'IHM que toutes les cartes sont en ligne
                        } else {
                            gameEtat = ETAT_WAIT_FORCE;//Passage en attente de forçage du lancement
                            waitingAckFrom = ECRAN_ALL_CHECK;
                        }
                    } else {
                        gameEtat = ETAT_CHECK_CARTES;
                    }
                } else {
                    gameEtat = ETAT_CHECK_CARTES;
                }
            }
        break;
        case ETAT_WAIT_FORCE:
            /*
            Attente du forçage de la part de la carte IHM
            */
            if(waitingAckFrom == 0) {
                gameEtat = ETAT_CONFIG;
            }
        break;
        case ETAT_CONFIG:
            /*
            Attente de l'odre de choix de mode,
            Il est possible de modifier la couleur et l'id de la stratégie
            Il est aussi possible d'envoyer les ordres de debug
            */
            modeTelemetre = 0;
        break;
        case ETAT_GAME_INIT:
            //On charge la liste des instructions
            loadAllInstruction();//Mise en cache de toute les instructions
            
            gameEtat = ETAT_GAME_WAIT_FOR_JACK;
            SendRawId(ECRAN_ACK_START_MATCH);
            tactile_printf("Attente du JACK.");
            setAsservissementEtat(1);//On réactive l'asservissement
            jack.mode(PullDown); // désactivation de la résistance interne du jack
            jack.fall(&jack_ISR); // création de l'interrupt attachée au changement d'état (front descendant) sur le jack
         
#ifdef ROBOT_BIG //le gros robot n'a pas de recalage bordure pour ce placer au début, on lui envoit donc ça position
            localData2 = POSITION_DEBUT_T;
            localData3 = POSITION_DEBUT_Y;
            if(InversStrat == 1) {
                localData2 = -localData2;//Inversion theta
                localData3 = 3000 - POSITION_DEBUT_Y;//Inversion du Y
            }
            SetOdometrie(ODOMETRIE_BIG_POSITION, POSITION_DEBUT_X,localData3,localData2);
#endif 
#ifdef ROBOT_SMALL
            SetOdometrie(ODOMETRIE_SMALL_POSITION, POSITION_DEBUT_X,POSITION_DEBUT_Y,POSITION_DEBUT_T);
#endif
        break;
        case ETAT_GAME_WAIT_FOR_JACK:
            //On attend le jack
        break;
        case ETAT_GAME_START:
            gameEtat = ETAT_GAME_LOAD_NEXT_INSTRUCTION;
            
            if (ModeDemo == 0){
                chronoEnd.attach(&chronometre_ISR,90);//On lance le chrono de 90s
                gameTimer.start();
            } 
            gameTimer.reset();
            jack.fall(NULL);//On désactive l'interruption du jack
            SendRawId(GLOBAL_START);
            tactile_printf("Start");//Pas vraiment util mais bon
        break;
        case ETAT_GAME_LOAD_NEXT_INSTRUCTION:
            /*
            Chargement de l'instruction suivante ou arret du robot si il n'y a plus d'instruction
            */
            //printf("load next instruction\n");
            
            if(actual_instruction >= nb_instructions || actual_instruction == 255) {
                gameEtat = ETAT_END;
                //Il n'y a plus d'instruction, fin du jeu
            } else {
                instruction = strat_instructions[actual_instruction];
                //On effectue le traitement de l'instruction 
                gameEtat = ETAT_GAME_PROCESS_INSTRUCTION;
            }
            screenChecktry = 0;
        break;
        case ETAT_GAME_PROCESS_INSTRUCTION:
            /*
            Traitement de l'instruction, envoie de la trame CAN
            */
            //debug_Instruction(instruction);
            switch(instruction.order)
            {
                case MV_COURBURE://C'est un rayon de courbure
                    waitingAckID = ASSERVISSEMENT_COURBURE;
                    waitingAckFrom = ACKNOWLEDGE_MOTEUR;
                    if(instruction.nextActionType == ENCHAINEMENT) {
                        MV_enchainement++;
                        localData5 = 1;
                    } else {
                        if(MV_enchainement > 0) {
                            localData5 = 2;
                            MV_enchainement = 0;
                        } else {
                            localData5 = 0;
                        }
                    }
                    localData1 = ((instruction.direction == LEFT)?1:-1);
                    if(InversStrat == 1)
                    {
                        localData1 = -localData1;//Inversion de la direction
                    }
                    
                    BendRadius(instruction.arg1, instruction.arg3, localData1, localData5);
                break;
                case MV_LINE://Ligne droite
                    waitingAckID = ASSERVISSEMENT_RECALAGE;
                    waitingAckFrom = ACKNOWLEDGE_MOTEUR;
                    if(instruction.nextActionType == ENCHAINEMENT) {
                        MV_enchainement++;
                        localData5 = 1;
                    } else {
                        if(MV_enchainement > 0) {//Utilisé en cas d'enchainement, 
                            localData5 = 2;
                            MV_enchainement = 0;
                        } else {
                            localData5 = 0;
                        }
                    }
                    #ifdef ROBOT_BIG
                    if(InversStrat == 1) {
                            /*if (instruction.direction == FORWARD) instruction.direction = BACKWARD;
                            else instruction.direction = FORWARD;*/
                            instruction.direction = ((instruction.direction == FORWARD)?BACKWARD:FORWARD);
                        }
                    #endif    
                    localData2 = (((instruction.direction == FORWARD)?1:-1)*instruction.arg1);
                    GoStraight(localData2, 0, 0, localData5);
                    
                break;
                case MV_TURN: //Rotation sur place
                    if(instruction.direction == RELATIVE) {
                        localData2 = instruction.arg3;
                    } else {//C'est un rotation absolu, il faut la convertir en relative
                        localData2 = instruction.arg3;
                        
                        if(InversStrat == 1) {
                            localData2 = -localData2;
                        }
                        
                        localData2 = (localData2 - theta_robot)%3600;
                        if(localData2 > 1800) {
                            localData2 = localData2-3600;
                        }
                        
                    }
                    
                    Rotate(localData2);
                    waitingAckID = ASSERVISSEMENT_ROTATION;
                    waitingAckFrom = ACKNOWLEDGE_MOTEUR;
                break;
                case MV_XYT:
                    if(instruction.direction == BACKWARD) {
                        localData1 = -1;
                    } else {
                        localData1 = 1;
                    }
                    
                    if(InversStrat == 1) {
                        localData2 = -instruction.arg3;
                        localData3 = 3000 - instruction.arg2;//Inversion du Y
                    } else {
                        localData3 = instruction.arg2;
                        localData2 = instruction.arg3;
                    }
                    GoToPosition(instruction.arg1,localData3,localData2,localData1);
                    waitingAckID = ASSERVISSEMENT_XYT;
                    waitingAckFrom = ACKNOWLEDGE_MOTEUR;
                break;
                case MV_RECALAGE:
                    waitingAckID = ASSERVISSEMENT_RECALAGE;
                    waitingAckFrom = ACKNOWLEDGE_MOTEUR;
                    instruction.nextActionType = WAIT;
                    localData2 = (((instruction.direction == FORWARD)?1:-1)*3000);//On indique une distance de 3000 pour etre sur que le robot va ce recaler
                    
                    if(instruction.precision == RECALAGE_Y) {
                        localData5 = 2;
                        if(InversStrat == 1) {
                            localData3 = 3000 - instruction.arg1;//Inversion du Y
                        } else {
                            localData3 = instruction.arg1;
                        }
                    } else {
                        localData5 = 1;
                        localData3 = instruction.arg1;
                    }
                    
                    GoStraight(localData2, localData5, localData3, 0);
                break;
                case ACTION:
                    int tempo = 0;
                    waitingAckID= SERVO_AX12_ACTION;
                    waitingAckFrom = ACKNOWLEDGE_AX12;
                    tempo = doAction(instruction.arg1,instruction.arg2,instruction.arg3);
                    if(tempo == 1){
                        //L'action est spécifique
                        if((waitingAckFrom == 0 && waitingAckID == 0) || instruction.nextActionType == ENCHAINEMENT) {
                            
                            actual_instruction = instruction.nextLineOK;//On indique que l'on va charger l'instruction suivante
                            gameEtat = ETAT_GAME_LOAD_NEXT_INSTRUCTION;
                        } else {
                            gameEtat = ETAT_GAME_WAIT_ACK;
                        }
                        #ifdef ROBOT_SMALL
                            actual_instruction = instruction.nextLineOK;//On indique que l'on va charger l'instruction suivante
                            gameEtat = ETAT_GAME_LOAD_NEXT_INSTRUCTION;
                        #endif
                        return;
                     #ifdef ROBOT_SMALL   
                    } else if (tempo == 2) {
                        // on est dans le cas de l'avance selon le telemetre
                        waitingAckID = ASSERVISSEMENT_RECALAGE;
                        waitingAckFrom = ACKNOWLEDGE_MOTEUR;
                        
                        localData2 = (((instruction.direction == FORWARD)?1:-1)*instruction.arg1);
                        GoStraight(telemetreDistance, 0, 0, 0);
                        // on reset la distance du telemetre à 0
                        telemetreDistance = 5000;
                        #endif
                    }else{
                        //C'est un AX12 qu'il faut bouger
                        //AX12_setGoal(instruction.arg1,instruction.arg3/10,instruction.arg2);
                        //AX12_enchainement++;
                                                
                    }
                break;
                default:
                    //Instruction inconnue, on l'ignore
                break;
            }    
            
            
            
            if(instruction.nextActionType == JUMP || instruction.nextActionType == WAIT) {
                gameEtat = ETAT_GAME_WAIT_ACK;//Il faut attendre que la carte est bien reçu l'acknowledge
                screenChecktry++;//On incrèment le conteur de tentative de 1
                cartesCheker.reset();//On reset le timeOut
                cartesCheker.start();
                if(AX12_enchainement > 0) {
                    //AX12_processChange();//Il faut lancer le déplacement des AX12
                    //AX12_enchainement = 0;
                }
            } else {//C'est un enchainement
                if(instruction.order == MV_LINE){
                      gameEtat =  ETAT_GAME_WAIT_ACK;
                    
                }else{
                    actual_instruction = instruction.nextLineOK;//On indique que l'on va charger l'instruction suivante
                    gameEtat = ETAT_GAME_LOAD_NEXT_INSTRUCTION;//C'est un enchainement, on charge directement l'instruction suivante
                }
            }
            
        break;
        case ETAT_GAME_WAIT_ACK:
            /*
            Attente de l'ack de l'instruction
            */
            if(waitingAckID == 0 && waitingAckFrom == 0) {//Les ack ont été reset, c'est bon on continu
            //if(true) {
                cartesCheker.stop();
                if(instruction.nextActionType == JUMP) {
                    if(instruction.jumpAction == JUMP_POSITION) {
                        gameEtat = ETAT_GAME_JUMP_POSITION;
                    } else {//Pour eviter les erreurs, on dit que c'est par défaut un jump time
                        gameEtat = ETAT_GAME_JUMP_TIME;
                        cartesCheker.reset();//On reset le timeOut
                        cartesCheker.start();  
                    }
                } else if(instruction.nextActionType == WAIT) {
                    gameEtat = ETAT_GAME_WAIT_END_INSTRUCTION;
                     switch(instruction.order)
                    {
                        case MV_COURBURE:
                            waitingAckID = ASSERVISSEMENT_COURBURE;
                            waitingAckFrom = INSTRUCTION_END_MOTEUR;
                        break;
                        case MV_LINE:
                            waitingAckID = ASSERVISSEMENT_RECALAGE;
                            waitingAckFrom = INSTRUCTION_END_MOTEUR;
                        break;
                        case MV_TURN:
                            waitingAckID = ASSERVISSEMENT_ROTATION;
                            waitingAckFrom = INSTRUCTION_END_MOTEUR;
                        break;
                        case MV_XYT:
                            waitingAckID = ASSERVISSEMENT_XYT;
                            waitingAckFrom = INSTRUCTION_END_MOTEUR;
                        break;
                        case MV_RECALAGE:
                            waitingAckID = ASSERVISSEMENT_RECALAGE;
                            waitingAckFrom = INSTRUCTION_END_MOTEUR;
                        break;
                        case ACTION:
                            
                            if (modeTelemetre == 0){
                                if (telemetreDistance == 0){
                                    waitingAckID = SERVO_AX12_ACTION;// instruction.arg1;  
                                    waitingAckFrom = INSTRUCTION_END_AX12; //SERVO_AX12_DONE;
                                }else if(telemetreDistance == 5000){
                                    // on est dans le cas ou l'on fait une ligne suivant la distance du telemetre
                                    waitingAckID = ASSERVISSEMENT_RECALAGE;
                                    waitingAckFrom = INSTRUCTION_END_MOTEUR;
                                    telemetreDistance = 0;
                                }
                            }else{ // si on attend la reponse du telemetre  
                                //modeTelemetre = 1; 
                                waitingAckID = OBJET_SUR_TABLE;
                                waitingAckFrom = 0; 
                            }
                        break;
                        default:
                        break;
                    }   
                } else {
                    gameEtat = ETAT_GAME_LOAD_NEXT_INSTRUCTION;
                    actual_instruction = instruction.nextLineOK;//On indique que l'on va charger l'instruction suivante
                }
            } else if(cartesCheker.read_ms () > 50){
                cartesCheker.stop();
                if(screenChecktry >=2) {//La carte n'a pas reçus l'information, on passe à l'instruction d'erreur
                    actual_instruction = instruction.nextLineError;
                    gameEtat = ETAT_GAME_LOAD_NEXT_INSTRUCTION;
                } else {
                    gameEtat = ETAT_GAME_PROCESS_INSTRUCTION;//On retourne dans l'etat d'envois de l'instruction
                }
            }
        break;
        
        case ETAT_GAME_JUMP_TIME:
            if(cartesCheker.read_ms () >= instruction.JumpTimeOrX) {
                cartesCheker.stop();//On arrete le timer
                actual_instruction = instruction.nextLineOK;//On indique que l'on va charger l'instruction suivante
                gameEtat = ETAT_GAME_LOAD_NEXT_INSTRUCTION;//On charge l'instruction suivante
            }
        break;
        
        case ETAT_GAME_JUMP_CONFIG:
            signed int depasX = 1, depasY = 1;  // servent à indiquer le sens de dépassement des coordonnées
                                                //  1 si l'instruction est plus grande que la position du robot
                                                // -1 si l'instruction est plus petite que la position du robot
                                                //  0 si l'instruction et position du robot sont proche de moins de 1cm
            if (abs(x_robot-instruction.JumpTimeOrX)<10){
                    depasX = 0;
            }else if(x_robot > instruction.JumpTimeOrX){
                    depasX = -1;
            }
            
            if(abs(y_robot-instruction.JumpY)<10){
                    depasY = 0;
            }else if(y_robot > instruction.JumpY){
                    depasY = -1;
            }
                
            gameEtat = ETAT_GAME_JUMP_POSITION;
        break;
        case ETAT_GAME_JUMP_POSITION:
            bool Xok = false, Yok = false;
             
                if (depasX == 0){
                    Xok = true;    
                }else if ((instruction.JumpTimeOrX - x_robot)*depasX < -5){
                    Xok = true;
                }
                
                if (depasY == 0){
                    Yok = true;    
                }else if ((instruction.JumpY - y_robot)*depasY < -5){
                    Yok = true;
                }
                
                // on teste si les deux coordonnées ont été dépassées, si oui on lance l'instruction suivante
                if (Xok && Yok){
                        actual_instruction = instruction.nextLineOK;//On indique que l'on va charger l'instruction suivante
                        gameEtat = ETAT_GAME_LOAD_NEXT_INSTRUCTION;//On charge l'instruction suivante
                    }
                
        break;
        case ETAT_GAME_WAIT_END_INSTRUCTION:
            if(waitingAckID == 0 && waitingAckFrom ==0) {//On attend que la carte nous indique que l'instruction est terminée
                actual_instruction = instruction.nextLineOK;//On indique que l'on va charger l'instruction suivante
                gameEtat = ETAT_GAME_LOAD_NEXT_INSTRUCTION;//On charge l'instruction suivante
            }
        break;
        
        
        case ETAT_WARNING_TIMEOUT://Attente de la trame fin de danger ou du timeout de 2s
            if(timeoutWarning.read_ms() >= BALISE_TIMEOUT)//ça fait plus de 2s, il faut changer de stratégie
            {
                gameEtat = ETAT_WARNING_SWITCH_STRATEGIE;
            }
        break;
        case ETAT_WARING_END_BALISE_WAIT://Attente d'une seconde apres la fin d'un End Balise pour etre sur que c'est bon
            if(timeoutWarningWaitEnd.read_ms() >= 1000) {//c'est bon, on repart
                //actual_instruction = instruction.nextLineError;
                gameEtat = ETAT_WARNING_END_LAST_INSTRUCTION;
            }
        break;
        case ETAT_WARNING_END_LAST_INSTRUCTION://trouver le meilleur moyen de reprendre l'instruction en cours
#ifdef ROBOT_BIG
            actual_instruction = instruction.nextLineError;//  2 //Modification directe... c'est pas bien mais ça marchait pour le match 5
            gameEtat = ETAT_GAME_LOAD_NEXT_INSTRUCTION;
#else
            actual_instruction = instruction.nextLineError;
            gameEtat = ETAT_GAME_LOAD_NEXT_INSTRUCTION; 
#endif
        break;
        case ETAT_WARNING_SWITCH_STRATEGIE://Si à la fin du timeout il y a toujours un robot, passer à l'instruction d'erreur
            actual_instruction = instruction.nextLineError;
            gameEtat = ETAT_GAME_LOAD_NEXT_INSTRUCTION;
            ingnorBaliseOnce = 1;
        break;
        
        
        
        case ETAT_END: 
            if (ModeDemo){
                gameEtat = ETAT_CHECK_CARTE_SCREEN;
                ModeDemo = 1;
            } else {
                gameEtat = ETAT_END_LOOP;
            }
        break;
        case ETAT_END_LOOP:
            //Rien, on tourne en rond
            
        break;
        default:
        
        break;
    }
}

/****************************************************************************************/
/* FUNCTION NAME: canProcessRx                                                          */
/* DESCRIPTION  : Fonction de traitement des messages CAN                               */
/****************************************************************************************/
void canProcessRx(void)
{
    static signed char FIFO_occupation=0,FIFO_max_occupation=0;
    CANMessage msgTx=CANMessage();
    FIFO_occupation=FIFO_ecriture-FIFO_lecture;
    if(FIFO_occupation<0)
        FIFO_occupation=FIFO_occupation+SIZE_FIFO;
    if(FIFO_max_occupation<FIFO_occupation)
        FIFO_max_occupation=FIFO_occupation;
    if(FIFO_occupation!=0) {
        
        switch(msgRxBuffer[FIFO_lecture].id) {
            case DEBUG_FAKE_JAKE://Permet de lancer le match à distance
                if(gameEtat == ETAT_GAME_WAIT_FOR_JACK) {
                    gameEtat = ETAT_GAME_START;
                }
            break;
            
            case ALIVE_BALISE:
            case ALIVE_MOTEUR:
            case ALIVE_IHM:
            case ALIVE_ACTIONNEURS:
            case ALIVE_POMPES:
            case ALIVE_AX12:
            case ECRAN_ALL_CHECK:
                if(waitingAckFrom == msgRxBuffer[FIFO_lecture].id) {
                    waitingAckFrom = 0;//C'est la bonne carte qui indique qu'elle est en ligne
                }
            break; 
            
            case ACKNOWLEDGE_BALISE:
            case ACKNOWLEDGE_MOTEUR:
            case ACKNOWLEDGE_IHM:
            case ACKNOWLEDGE_TELEMETRE:
            case ACKNOWLEDGE_AX12:
            case INSTRUCTION_END_BALISE:
            case INSTRUCTION_END_MOTEUR:
            case INSTRUCTION_END_IHM:
            case INSTRUCTION_END_AX12:
                
                if(waitingAckFrom == msgRxBuffer[FIFO_lecture].id && ((unsigned short)msgRxBuffer[FIFO_lecture].data[0]|((unsigned short)(msgRxBuffer[FIFO_lecture].data[1])<<8) == waitingAckID)) {
                    waitingAckFrom = 0;
                    waitingAckID = 0;
                }
            break;
#ifdef ROBOT_BIG
            case ODOMETRIE_BIG_POSITION:
#else
            case ODOMETRIE_SMALL_POSITION:
#endif
                x_robot=msgRxBuffer[FIFO_lecture].data[0]|((unsigned short)(msgRxBuffer[FIFO_lecture].data[1])<<8);
                y_robot=msgRxBuffer[FIFO_lecture].data[2]|((unsigned short)(msgRxBuffer[FIFO_lecture].data[3])<<8);
                theta_robot=msgRxBuffer[FIFO_lecture].data[4]|((signed short)(msgRxBuffer[FIFO_lecture].data[5])<<8);
            break;
            
            case ECRAN_START_MATCH:
                if(gameEtat == ETAT_CONFIG) {
                    gameEtat = ETAT_GAME_INIT;
                }
            break;
            case SERVO_AX12_SETGOAL:
                //SendAck(0x114, SERVO_AX12_SETGOAL);
                //if(AX12_isLocal(msgRxBuffer[FIFO_lecture].data[0]))
                    //AX12_setGoal(msgRxBuffer[FIFO_lecture].data[0], msgRxBuffer[FIFO_lecture].data[1]|((unsigned short)(msgRxBuffer[FIFO_lecture].data[2])<<8), msgRxBuffer[FIFO_lecture].data[3]|((unsigned short)(msgRxBuffer[FIFO_lecture].data[4])<<8));
                  
            break;
            
            case SERVO_AX12_PROCESS:
                SendAck(0x114, SERVO_AX12_PROCESS);
                //AX12_processChange(1);
            break;
            
            case SERVO_AX12_DONE:
                SendRawId(POMPE_PWM);
                /*//SendAck(0x114, SERVO_AX12_DONE);
                AX12_notifyCANEnd(((unsigned short)(msgRxBuffer[FIFO_lecture].data[0])));
                
                gameEtat = ETAT_GAME_LOAD_NEXT_INSTRUCTION;
                waitingAckFrom = 0;
                waitingAckID = 0;*/
                
            break;
            case ECRAN_CHOICE_COLOR://Choix de la couleur
                if(gameEtat == ETAT_CONFIG) {//C'est bon on a le droit de modifier les config
                    if(msgRxBuffer[FIFO_lecture].data[0] == 0)
                        InversStrat = 0;//Pas d'inversion de la couleur
                    else
                        InversStrat = 1;//Inversion de la couleur
                        
                    msgTx.id=ECRAN_ACK_COLOR; // tx ack de la couleur
                    msgTx.len=1;
                    msgTx.format=CANStandard;
                    msgTx.type=CANData;
                    // couleur sur 1 octet
                    msgTx.data[0]=msgRxBuffer[FIFO_lecture].data[0];
                    can1.write(msgTx);
                    
                }
            break;
            
            case ECRAN_CHOICE_STRAT://Choix du fichier de stratégie à utiliser
                if(gameEtat == ETAT_CONFIG) {//C'est bon on a le droit de modifier les config
                    msgTx.id=ECRAN_ACK_STRAT; // tx ack de la couleur
                    msgTx.len=1;
                    msgTx.format=CANStandard;
                    msgTx.type=CANData;
                    if(SelectStrategy(msgRxBuffer[FIFO_lecture].data[0])) {
                        // id de la stratégie sur 1 octet
                        if (msgRxBuffer[FIFO_lecture].data[0] < 0x10){  // Si la strat est une strat de match, on desactive le mode demo
                                ModeDemo = 0;
                        } else {                                        // sinon, on active le mode demo, utile pour la fin de la demo
                                ModeDemo = 1;
                        }
                        
                        msgTx.data[0]=msgRxBuffer[FIFO_lecture].data[0];
                    } else {
                        //erreur sur 1 octet
                        msgTx.data[0]=0;
                    }
                    can1.write(msgTx);
                    wait_ms(10);
                    setAsservissementEtat(0);//Désactivation de l'asservissement pour repositionner le robot dans le zone de départ
                    tactile_printf("Strat %d, Asser desactive",msgTx.data[0]);
                }
            break;
            case BALISE_DANGER :
                SendAck(ACKNOWLEDGE_BALISE, BALISE_END_DANGER);
            break;
            
            case BALISE_STOP:
                SendAck(ACKNOWLEDGE_BALISE, BALISE_STOP);
                //if (instruction[actual_instruction].order != MV_TURN){ //J'ai rajouté cette ligne mais il faut tester avec et sans pour voir le comportement du robot, 
                    if(needToStop() != 0 && ingnorBaliseOnce ==0) {
                        if(gameEtat > ETAT_GAME_START && gameEtat != ETAT_WARNING_TIMEOUT)
                        {
                            SendRawId(ASSERVISSEMENT_STOP);
                            //while(1);
                            gameEtat = ETAT_WARNING_TIMEOUT;
                            if(gameEtat != ETAT_WARING_END_BALISE_WAIT) {
                                timeoutWarning.reset();
                                timeoutWarning.start();//Reset du timer utiliser par le timeout
                            }
                        }
                    }
                //}
                ingnorBaliseOnce = 0;
            break;
            
            case BALISE_END_DANGER:
                SendAck(ACKNOWLEDGE_BALISE, BALISE_END_DANGER);
                if(gameEtat == ETAT_WARNING_TIMEOUT) {
                    timeoutWarningWaitEnd.reset();
                    timeoutWarningWaitEnd.start();
                    gameEtat = ETAT_WARING_END_BALISE_WAIT;
                }
            break;
            
            case ECRAN_CHOICE_START_ACTION:
                if(gameEtat == ETAT_CONFIG) {//C'est bon on a le droit de modifier les config
                    if(msgRxBuffer[FIFO_lecture].data[0] == 1) {
                        runRobotTest();
                    } else {
                        initRobotActionneur();
                    }
                    wait_ms(500);
                    SendRawId(ECRAN_ACK_CHOICE_START_ACTION);
                }
            break;
            
            case OBJET_SUR_TABLE:
                if (msgRxBuffer[FIFO_lecture].data[1] == 0xff){
                        
                        gameEtat = ETAT_WARNING_END_LAST_INSTRUCTION;
                    }
                else{
                        
                        waitingAckFrom = 0;
                        waitingAckID = 0; 
                        
                        strat_instructions[actual_instruction+1].arg1 = returnX(strat_instructions[actual_instruction].arg2);
                        strat_instructions[actual_instruction+1].arg2 = returnY(strat_instructions[actual_instruction].arg2);
                    }
                modeTelemetre = 0;
            break;
        }        
        
        FIFO_lecture=(FIFO_lecture+1)%SIZE_FIFO;
    }
}