/*
 * File:   max1472_min.c
 * Author: jlc 1/8/2023
 *
 * Controle emetteur MICRF113 ou MAX1472  sur PIC10LF322
 * RA0 (SPDAT) : sortie de modulation sur carte proto
 * 1/8/23: ajout d'un strap entre RA2 et SPDAT sur le proto (= meme source C)
 * RA1 (SPCLK) : sortie de test
 * RA2: CLKR   : IO signal de modulation du MAX1472 sur balise finale
 * RA3 (MCLR)  : entree de code activation/desactivation
 *
 *  Modifs:
 * 2/8/23: mot de code sur 16 bits pour gagner de la place
 *         ajout du code 0xBB de configuration de la duree limite 4 ou 8heures
 * 11/8/23: le passage en heure limite n'écrit plus le code 0x5D de désactivation en UserID0
 *         mais inhibe seulement l'émission. Un reset réactive l'émission.
 * 13/8/23: code 3 pour doubler à 8ms dans UserID2
 */
#define OUTPUT_PROTO 1 // si 1 active la commande par RA0(SPDAT) au lieu de RA2 sur cartes protos

#define pINPUT_CODE RA3  // entree signal activation/desactivation (MCLR pin 6)

#define pTEST_OUT LATA1  // sortie de test pour mesures  et etat d'emission (SPCLK pin3)
#define dirTEST_OUT TRISA1


#define pDATAOUT LATA2   // sortie de modulation sur balise finale
#define dirDATAOUT TRISA2






// si 1 cela active l'horloge 16MHz interne sinon 32KHz
#define HORLOGE_16MHz 0


#define MODETEST 0   // active le signal de test RA1 SPCLK sur carte proto

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <xc.h>


// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

// CONFIG
#pragma config FOSC = INTOSC    // Oscillator Selection bits (INTOSC oscillator: CLKIN function disabled)
#pragma config BOREN = ON       // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config WDTE = ON       // Watchdog Timer Enable (WDT enabled even in Sleep)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF      // MCLR Pin Function Select bit (MCLR pin function is digital input, MCLR internally tied to VDD)
#pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
#pragma config LVP = OFF        // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)
#pragma config LPBOR = OFF       // Brown-out Reset Selection bits (BOR enabled)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)

// UserID0 sert de code de desactivation (14 bits utiles par mot   4mots total)
// attention: tronque par 7F par l'IDE: inactif = 0x5D
#pragma config IDLOC0= 0x0000
// UserID1 = nombre de pulses repetitifs emis en plus chaque 2 secondes de 0 à 3
// defaut = 1 seul top emis
// intervalle de 200ms entre tops
#pragma config IDLOC1= 0

// UserID2 = frequence de chaque top elementaire modulé a 50%
// 0= HF pure pendant 4ms
// 1 ou autres = defaut = 4 ms et frequence 1KHz (4 periodes de 1ms / ms)
// 2= 4ms et frequence 2KHz ( 2 periodes de 500µs / ms)
// 3= 1KHz en 8ms
// choix a faire à la programmation du pic par manque de place du code
#pragma config IDLOC2= 1 //

// UserID3 indique la duree maximale d'émission
// permet d'éviter le comportement erratique en fin de vie de pile
// 0 ou autres= pas de timeout
// 4= limite de 4heures
// 8= limite de 8heures environ par comptage des intervalles de 2 secondes
// attention: UserID3 se réeecrit en 0x0A lors de la réécriture  (cause inconnue ???)
//
#pragma config IDLOC3= 8 //
#define DUREE_LIMITE_8H 14400  // 1800*8 intervalles de 2 secondes pour 8 heures
#define DUREE_LIMITE_4H 7200  // 4 heures

#define _XTAL_FREQ 31000
volatile bit flag_emission_active,flag_desactivation,flag_activation,flag_sauvegarde; // indique si actif ou pas
volatile bit flag_debut_configuration;
volatile unsigned  int code_word;// mot entrant sur 16bits
volatile unsigned char cpt_code=0;
volatile unsigned  int code_word2;
volatile unsigned char nbre_pulses;
volatile unsigned char UserID0,UserID1,UserID2,UserID3; // sauvegarde des UserID avant ecriture du block Config
volatile unsigned char savetimer2,tmpuser;
unsigned int cpt_duree_limite;// compteur d'intervalles de 2 secondes


// chaque IT remet a 0 le WDT
void interrupt interrupt_manage(void)
{
    // edge positif ou negatif detecte sur RA3
    // codage manchester:
    // 1= top de 400ms
    // 0= top de 100ms
    if( IOCIF) {
        IOCIF=0;
        savetimer2=TMR2; // capte le timer une seule fois
        CLRWDT();
      if( IOCAF3) {
         IOCAF3=0;
         flag_debut_configuration=1;// indique de ne pas relancer de Sleep si mode desactive
        if( pINPUT_CODE) {
            // edge positif: synchronise TMR2
            TMR2=0;// repere de mesure du temps a l'etat haut
            if(TMR2IF) {
                // plus d'une seconde entre flancs positifs
                // le chargeur emet un pulse avant le vrai code
                flag_debut_configuration=0;
                TMR2IF=0;
#if MODETEST==1
                cpt_code=0; // pour affichage en test
#endif
                code_word=0;// annule les bits accumulés
            }

        } else {
            // edge negatif: bit detecte suivant temps passe a l'etat haut
            // TMR2 reboucle à 0 au bout de 500ms environ
            // TMR2IF monte au bout de 1 seconde
            if( TMR2IF) { TMR2IF=0;code_word=0;flag_debut_configuration=0;}

            if( savetimer2>40) {// plus de 100ms  car tick de 2ms
                // bit detecte a 1 sinon 0
                code_word |= 1;
#if 0
                            pTEST_OUT=1;// test: indique 1
                            pTEST_OUT=1;
                            pTEST_OUT=1;
                            pTEST_OUT=1;
                            pTEST_OUT=0;

#endif
            } else {
                code_word |= 0; // bit a 0
#if 0
               pTEST_OUT=1;// indique 0
               pTEST_OUT=0;
#endif
            }
#if MODETEST==1
            // affiche le code recu si 16 bits MSB en tete
            cpt_code++;
            if( cpt_code==16) {
                code_word2= code_word;
                while(cpt_code--) {
                    if( code_word2 & 0x8000) {
                        pTEST_OUT=1;
                        pTEST_OUT=1;
                        pTEST_OUT=1;
                        pTEST_OUT=1;
                        pTEST_OUT=0;
                    } else {
                        pTEST_OUT=1;
                        pTEST_OUT=0;
                    }
                    code_word2 <<= 1;
                }
            }
#endif
            tmpuser=code_word & 0xF;// nible lsb
            // test du code activation/desactivation
            if( code_word== 0xAAAA) {
                if( UserID0) { // ne sreecrit qu'en cas de modification
                    UserID0=0x00;
                    flag_sauvegarde=1;
                }
                flag_activation=1;
                flag_desactivation=0;

#if MODETEST==1
                            pTEST_OUT=1;
                            pTEST_OUT=1;
                            pTEST_OUT=1;
                            pTEST_OUT=0;
                            pTEST_OUT=1;
                            pTEST_OUT=0;
                            pTEST_OUT=1;
                            pTEST_OUT=0;
#endif
            }
            else if( code_word== 0xDDDD) {
                // on ne reecrit pas les UserIDs si pas changé
                if( UserID0!=0x5D) {
                 UserID0=0x5D;
                 flag_sauvegarde=1;
                }
                flag_desactivation=1;
                flag_activation=0;


#if MODETEST==1
                            pTEST_OUT=1;
                            pTEST_OUT=1;
                            pTEST_OUT=1;
                            pTEST_OUT=0;
                            pTEST_OUT=1;
                            pTEST_OUT=0;

#endif
            } else if((code_word & 0xFF00)== 0xCC00) {
                // configuration du nombre de repetitions du pulse
                // et activation
                if( tmpuser !=UserID1) {
                    UserID1= tmpuser;
                    flag_sauvegarde=1;
                }
                flag_activation=1;
                flag_desactivation=0;

            } else if((code_word & 0xFF00)== 0xEE00) {
                // configuration du type de modulation
                // et activation
                if( tmpuser !=UserID2) {
                    UserID2= tmpuser;
                    flag_sauvegarde=1;
                }
                flag_activation=1;
                flag_desactivation=0;

            } else if((code_word & 0xFF00)== 0xBB00) {
                // configuration de la duree limite
                // et activation
                if( tmpuser !=UserID3) {
                    UserID3= tmpuser;
                    flag_sauvegarde=1;
                }
                flag_activation=1;
                flag_desactivation=0;

            }
            code_word <<= 1;// place pour le bit suivant

           }

        }


    }



}
// inline economise du code pour les routines utilisees une seule fois
inline void ConfigureOscillator(void)
{
#if HORLOGE_16MHz==1
     /* Activation INTOSC a 16MHz */
    OSCCON= 0b01110000; /* */
    // attend que l'oscillateur HFINTOSC soit stable
    while( !HFIOFS) continue;
#else
    /* Activation INTOSC a 31 kHz */
    OSCCON= 0b00000000; /* */
    // attend que l'oscillateur LFINTOSC soit ready
    while( !LFIOFR) continue;
#endif

}


// version optimisee TMR0 avance chaque 1ms
inline void Delai_100ms(void)
{
    TMR0IF=0;
    TMR0=150;
    while(!TMR0IF)CLRWDT();
}

inline void Delai_50ms(void)
{
    TMR0IF=0;
    TMR0=205;
    while(!TMR0IF)CLRWDT();
}

// configuration des ports
inline void ConfigurePorts(void)
{
    // config des ports
    ANSELA= 0; // tout digital
    WPUA=0;
    pDATAOUT=0;
    dirDATAOUT=0; // signal ASK=0
    nWPUEN=0;// pullups actifs
    // detection IOC sur RA3
    IOCAP3=1;// detecte edge positif
    IOCAN3=1; // detecte edge negatif

#if MODETEST==1
    dirTEST_OUT=0;
    pTEST_OUT=0;
#endif

    dirDATAOUT=0;
    pDATAOUT=0;

}
// activation des timers
inline void ConfigureTimers(void)
{
 #if HORLOGE_16MHz==1
    // Timer0: FOSC/4 Prescaler=4 soit 1µs par top a 16MHz
    // sert pour des delais en µs
    OPTION_REG= 0b00000001;
 #else
    // cas horloge FOSC=31KHz
    // Timer0: FOSC/4= 7.75KHz Prescaler=1/8 1ms par tick
    OPTION_REG= 0b00000010;

    // Timer2 sert pour detection du code activation/desactivation
    // Fosc/4 = 7.75KHz 129µs Prescaler= 1/16  Postscaler= 1/2
    // tick de 2.064ms du compteur TMR2
    // flag IT toutes les 1 sec environ (postscaler=1/2)
    PR2=249;// cycle de 0.5sec Attention: TMR2 remis à 0 au bout de 0.5sec
    T2CON= 0b00001110;
    TMR2IF=0;

    TMR2IE=0;// pas d'IT

    // WDG a 2 secondes sert a cadencer si inactif  et reset au debut
    WDTCON=0b00010111;

#endif
}

/**
 * unlock Flash Sequence
 */
void _unlock( void)
{
    #asm
        BANKSEL     PMCON2
        MOVLW       0x55
        MOVWF       PMCON2 & 0x7F
        MOVLW       0xAA
        MOVWF       PMCON2 & 0x7F
        BSF         PMCON1 & 0x7F,1    ; set WR bit
        NOP
        NOP
    #endasm
} // unlock

// ecriture du code dans les IDLOC
// on doit reecrire les 4 UserId avant de faire l'erase du block
void Save_IDcodes(void)
{
    di();// No ITs
        PMADR= 0;
     // ** ERASE **
        PMCON1bits.CFGS = 1;    // select the flash address space
        PMCON1bits.FREE = 1;    // next operation will be a erase
        PMCON1bits.WREN = 1;    // enable flash memory write/erase
        // Unlock sequence
        _unlock();
        //PMCON1bits.WREN = 0;

      // ** write des 4 UserID les 4 premeirs en latch **
      // seuls les LSB sont utilises pour gagner du code
        PMADR=0;// row adress dans les mots de config
        PMDATL=UserID0;
        PMCON1bits.FREE = 0;    // next operation will be a write
        //PMCON1bits.WREN = 1;    // enable flash memory write/erase
        PMCON1bits.LWLO = 1;    // ecriture dans les latchs

        // Unlock sequence
        _unlock();
        PMADRL++;// poids faibles suffisent
        PMDATL=UserID1;
        _unlock();
        PMADRL++;
        PMDATL=UserID2;
        _unlock();
        PMADRL++;
        PMCON1bits.LWLO = 0;    // puis ecriture effective dans la flash
        PMDATL=UserID3;
        _unlock();

        PMCON1bits.WREN = 0;

     ei();// Its actives
}


// lecture des 4 UserID  adr de 0 a 3
inline void ReadUserId(void)
{
    PMADR = 0;
    PMCON1bits.CFGS = 1;    // select the configuration flash address space
    PMCON1bits.RD = 1;      // next operation will be a read
    NOP();
    NOP();
    UserID0= PMDATL;
    PMADR=1;
    PMCON1bits.RD = 1;      // next operation will be a read
    NOP();
    NOP();
    UserID1= PMDATL;
     PMADR=2;
    PMCON1bits.RD = 1;      // next operation will be a read
    NOP();
    NOP();
    UserID2= PMDATL;
    PMADR=3;
    PMCON1bits.RD = 1;      // next operation will be a read
    NOP();
    NOP();
    UserID3= PMDATL;
}
#if 0
inline void Emit_4KHz_4ms(void)
{
      // modulation
      // 1ms
      pDATAOUT=1;
      pDATAOUT=0;
      pDATAOUT=1;
      pDATAOUT=0;
      pDATAOUT=1;
      pDATAOUT=0;
      pDATAOUT=1;
      pDATAOUT=0;
      // 1ms
      pDATAOUT=1;
      pDATAOUT=0;
      pDATAOUT=1;
      pDATAOUT=0;
      pDATAOUT=1;
      pDATAOUT=0;
      pDATAOUT=1;
      pDATAOUT=0;
      // 1ms
      pDATAOUT=1;
      pDATAOUT=0;
      pDATAOUT=1;
      pDATAOUT=0;
      pDATAOUT=1;
      pDATAOUT=0;
      pDATAOUT=1;
      pDATAOUT=0;
      // 1ms
      pDATAOUT=1;
      pDATAOUT=0;
      pDATAOUT=1;
      pDATAOUT=0;
      pDATAOUT=1;
      pDATAOUT=0;
      pDATAOUT=1;
      pDATAOUT=0;

}
#endif

inline void Emit_2KHz_4ms(void)
{

      // modulation sur la balise finale
      // 1ms
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=0;
      pDATAOUT=0;
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=0;
      pDATAOUT=0;
      // 1ms
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=0;
      pDATAOUT=0;
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=0;
      pDATAOUT=0;
      // 1ms
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=0;
      pDATAOUT=0;
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=0;
      pDATAOUT=0;
      // 1ms
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=0;
      pDATAOUT=0;
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=0;
      // dernier 0 inutile
      //pDATAOUT=0;

}
 void Emit_1KHz_4ms(void)
{

      // modulation sur la balise finale
      // 1ms
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=0;
      pDATAOUT=0;
      pDATAOUT=0;
      pDATAOUT=0;
       // 1ms
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=0;
      pDATAOUT=0;
      pDATAOUT=0;
      pDATAOUT=0;
        // 1ms
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=0;
      pDATAOUT=0;
      pDATAOUT=0;
      pDATAOUT=0;
       // 1ms
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=0;
      // derniers 0 inutiles
      // en cas de duplication servent à l'appel routine
      //pDATAOUT=0;
      //pDATAOUT=0;
      //pDATAOUT=0;

}
#if 0
void Emit_1KHz_8ms(void)
{

      // modulation sur la balise finale
        // 1ms
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=0;
      pDATAOUT=0;
      pDATAOUT=0;
      pDATAOUT=0;
        // 1ms
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=0;
      pDATAOUT=0;
      pDATAOUT=0;
      pDATAOUT=0;
        // 1ms
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=0;
      pDATAOUT=0;
      pDATAOUT=0;
      pDATAOUT=0;
        // 1ms
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=0;
      pDATAOUT=0;
      pDATAOUT=0;
      pDATAOUT=0;
      // 1ms
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=0;
      pDATAOUT=0;
      pDATAOUT=0;
      pDATAOUT=0;
       // 1ms
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=0;
      pDATAOUT=0;
      pDATAOUT=0;
      pDATAOUT=0;
        // 1ms
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=0;
      pDATAOUT=0;
      pDATAOUT=0;
      pDATAOUT=0;
       // 1ms
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=1;
      pDATAOUT=0;
      // derniers 0 inutiles
      //pDATAOUT=0;
      //pDATAOUT=0;
      //pDATAOUT=0;

}
#endif

// HF pure pendant 4ms
inline void Emit_HF_4ms(void)
{

    pDATAOUT=1;
    TMR0=252;// tick de 1ms
    TMR0IF=0;
    while(!TMR0IF) continue;
    pDATAOUT=0;
}


void main(void)
{
    unsigned int i;
    // bloque a 0 le mAX1472 au plus tot
    ANSELA= 0; // tout digital
    pDATAOUT=0;
    dirDATAOUT=0; // signal ASK=0

    ConfigureOscillator();
    ConfigureTimers();
    ConfigurePorts();

    // laisse charger la capa d'alim sur le chargeur
    // si usage sur proto sans la pile
    // les ports sont en HiZ ici
    CLRWDT();
    SLEEP();// sera reveille par le WDG apres 2 secondes (doit etre  actif) ou IT externe
    NOP();

    dirTEST_OUT=0;
    pTEST_OUT=0;

    IOCIE=1;// detection ITs IOC sur RA3
    PEIE=0; // 0 car TMR2 non utilisé sous ITs ne joue pas sur IOCIF
    ei();

     // demandes venant de l'IT de programmation
    flag_desactivation=0; // pas de demande de desactivation
    flag_activation=0;
    flag_sauvegarde=0;
    cpt_duree_limite=0;//reset du compteur de duree limite

    // lecture des UserID
    ReadUserId();
    // lecture de ID user dans le mot de config
    // et indique si emission active ou inhibee
    if( (UserID0) == 0x5D) {
        flag_emission_active=0;
    } else {
        flag_emission_active=1;
    }

    // nombre de pulses emis a chaque 2 secondes
    nbre_pulses= UserID1 & 0x3; // octet LSB
    if( UserID1==0x7F) {
        nbre_pulses=0; // par defaut pas de repetition 0x7F mis par IDE par defaut
    }


    //Save_IDcodes();

    // boucle de signal top HF  toutes les 2 secondes si actif
     dirDATAOUT=0;


     if( flag_emission_active) WPUA3=1;else WPUA3=0;// signale par le pullup

#if MODETEST==1
     if(flag_emission_active) {
     pTEST_OUT=1;
     pTEST_OUT=1;
     pTEST_OUT=1;
     pTEST_OUT=0;
     pTEST_OUT=0;
     pTEST_OUT=0;
     pTEST_OUT=1;
     pTEST_OUT=1;
     pTEST_OUT=1;
     pTEST_OUT=0;
     }
#endif

 while(flag_emission_active
         && (!flag_desactivation)
         && (!flag_activation)) {
      // modulation 4KHz pendant 1ms
      // a 31KHz une instruction dure 125µs  (FOSC/4)
      // repetition des pulses suivant UserID1
    for(i=0;i<=nbre_pulses;i++)
    {
      CLRWDT();// reset du WDG
      di();// masque pour le bon timing du top de modulation
      switch(UserID2)
      {
          case 0: Emit_HF_4ms();break;// HF pure pendant 4ms
          default:
          case 3: Emit_1KHz_4ms();  // pas de break pour avoir 8ms
          case 1: Emit_1KHz_4ms();break;
          case 2: Emit_2KHz_4ms();break;
          //case 4: Emit_4KHz_4ms();break;  // pas asez de place
      }

      ei();// laisse passer les Its de configuration eventuelles
           // car utilisent le timer2 bouclant a 0.5sec
      Delai_100ms(); // 200ms entre pulses
      Delai_100ms(); //
    }


    // limitation de duree de focntionnement
    // inhibe  seulement l'émission sans toucher aux UserIDs
    cpt_duree_limite++;
    switch(UserID3) {
        case 0: break;// pas de duree limite
        default: // autres = 8h
            // passe en mode desactivation
            if( cpt_duree_limite>DUREE_LIMITE_8H) {
                flag_emission_active=0;
            }
            break;
        case 4: // duree limite 4 heures
            // passe en mode desactivation
            if( cpt_duree_limite>DUREE_LIMITE_4H) {
                flag_emission_active=0;
            }
            break;
    }
    // -------- delai 2 secondes entre tops --------------

        for(i=0;i<19;i++) {Delai_100ms(); CLRWDT();}  // 2 secondes


 } /* end while */

 // emission inactive ou demande de desactivation

 SLEEPENTRY:
    CLRWDT();
    if( flag_desactivation) { // mis a jour sous ITs
       // demande de desactivation par inscription du code 0x005D dans UserID
        if( flag_sauvegarde) Save_IDcodes();
        flag_desactivation=0;
        flag_emission_active=0;
        pDATAOUT=0;
        WPUA3=0;
#if MODETEST==1
                            pTEST_OUT=1;
                            pTEST_OUT=0;
                            pTEST_OUT=1;
                            pTEST_OUT=0;
                            pTEST_OUT=1;
                            pTEST_OUT=0;
                            pTEST_OUT=1;
                            pTEST_OUT=0;
                            pTEST_OUT=1;
                            pTEST_OUT=0;
#endif
        // provoque un reset hard via le WDG  mis a 128ms
        // *Warning*: le WDG doit etre active dans la Config
        // le reset remet le WDG a 2sec
        CLRWDT();
        WDTCON= 0x00001110; // active par soft au cas ou
        while(1);// declenche le WDG
        //goto STARTUP;
    }
    if( flag_activation) { // mis a jour sous ITs
        // demande d'activation sous IT
        // ecrit le code d'activation 0  dans ID user
        if( flag_sauvegarde) Save_IDcodes();
        // reset du compteur de duree limite
        cpt_duree_limite=0;
        flag_activation=0;
        flag_emission_active=1;
        WPUA3=1;
#if MODETEST==1
                            pTEST_OUT=1;
                            pTEST_OUT=0;
                            pTEST_OUT=1;
                            pTEST_OUT=0;
                            pTEST_OUT=1;
                            pTEST_OUT=0;
                            pTEST_OUT=1;
                            pTEST_OUT=0;
                            pTEST_OUT=1;
                            pTEST_OUT=0;
                            pTEST_OUT=1;
                            pTEST_OUT=0;

#endif
        // provoque un reset hard via le WDG  mis a 128ms
        // *Warning*: le WDG doit etre active dans la Config
        // le reset remet le WDG a 2sec
        CLRWDT();
        WDTCON= 0x00001110; // active par soft au cas ou
        while(1);// declenche le WDG
        //goto STARTUP;// demarre la sequence d'emission
    }
    // Etat desactive: reste en Sleep sauf IT d WDG chaque 2seconde ou It IOC externe sur RA3
    // reste en Sleep si pas de confguration en cours sous its
    if( !flag_debut_configuration) SLEEP();// reveille par IT ou WDT
    NOP();
    NOP(); // laisser passer l'IT qui a reveillé
    // autorise a nouveau le Sleep si timer2 a boucle a 1sec
    // a la fin d'une sequence de configuration
    if( TMR2IF) flag_debut_configuration=0;


    goto SLEEPENTRY;// reste en Sleep si desactivation et pas en mode configuration


}
