/**************************************************************************
 *
 *                Microchip USB C18 Firmware Version 1.0
 *
 **************************************************************************
 * FileName:        user.c
 * Processor:       PIC18
 *************************************************************************/

/** I N C L U D E S *******************************************************/
#include "p18f2455.h"
#include "user.h"
#include "usb.h"
#include "timers.h"
#include "usart.h"
#include "string.h"
#include "reset.h"
#include "portb.h"
#include "memoire.h"
#include "user.h"
#include "delays.h"

/** V A R I A B L E S ***************************************************/
#pragma idata
DATA_PACKET usbuff;

//Boucle de dechargement vers le bus Usb
unsigned int send_oc;
unsigned char ordre, ordrelen;
unsigned char leds_on, etat;

//Pour la date complete
unsigned int yyyy;
unsigned char mm, dd;

unsigned char hrs, mins, secs;

//Tampon avant ecriture d'un accès en flash 
PASSAGE essai;

//Données recues du RFID et pointeur
unsigned char rec[32];
unsigned char dataptr, rectimeout;
unsigned int accesptr, nextnumero;
unsigned char NByte, pushlen, ZAdr;
unsigned short C, CRC, i;

/** CONSTANTES (VARIABLES) EN MEMOIRE FLASH ************************************************/
#pragma romdata
rom unsigned char clevide[5]={0,0,0,0,0};

#pragma romdata liste_cles = 0x1600
//Ensemble des clés RFID connues (max_cles) - 5ocs code + 27ocs pour nom
//Modifié par WriteFlash en cas de nouvelles clés 
rom CLE_RFID cles[MAX_CLES];

#pragma romdata liste_entrees = 0x4000
//Ensemble des passages enregistrés
rom PASSAGE acces[MAX_ACCES];

#pragma code

/************************************************************************
 * Initialisation du PIC, ports, timer1, usart...
 * 
 ***********************************************************************/
void UserInit(void) {
 //!!! NE PAS RALENTIR AVANT L'ENUM USB !!!
 ADCON0 = 0x0;			// adc off

 PORTA = 0b11100111;	// deux leds en sortie et eteintes
 TRISA = 0b11100111;

 OpenPORTB(PORTB_CHANGE_INT_OFF & PORTB_PULLUPS_ON);
 PORTB = 0b00000000;	// relais en sortie (eteint)
 TRISB = 0b11111101;

 TRISC = 0b11111111;	// portC in

 //Laise passer le no de version du lecteur UM005
 Delay10KTCYx(0);
 Delay10KTCYx(0);

 OpenUSART( USART_TX_INT_OFF & USART_RX_INT_ON &
	USART_ASYNCH_MODE & USART_EIGHT_BIT &
	USART_CONT_RX & USART_BRGH_LOW, 38 );

 OpenTimer1( TIMER_INT_ON & T1_8BIT_RW &
	T1_SOURCE_EXT & T1_PS_1_1 &
	T1_OSC1EN_ON & T1_SYNC_EXT_ON );
 WriteTimer1(0x8000);

 send_oc = 0;
 leds_on = 0;
 dataptr =0;
 etat = 0;
 pushlen = 0;
 ordre = 0;

 //Remet heure & date a zero si POR
 if (isPOR) {
    secs = mins = hrs = 0;
    dd = 1;
    mm = 5;
    yyyy = 2006;  }

 //Recherche adresse et numéro du prochain acces a stocker
 nextnumero=1; 
 for (i=0;i<MAX_ACCES;i++) {
   if ((acces[i].yyyy==0)||(acces[i].yyyy==0xffff)) break;
   else {
     if (acces[i].numero>=nextnumero) nextnumero=1+acces[i].numero;
     if ((i>0)&&(acces[i].numero!=1+acces[i-1].numero)) break;
   }
 }
 if (i==MAX_ACCES) accesptr=0; else accesptr=i;

 PIE1bits.RCIE = 1;			// enable int rx Usart
 PIE1bits.TMR1IE = 1;		// enable int TMR1
 INTCON = 0b11000000;		// enable les interruptions
}


/*************************************************************
* Function:    void ProcessIO(void)
* Overview:    This function is a for other user routines.
*              It is a mixture of both USB and non-USB tasks.
*************************************************************/
void ProcessIO(void) {
   
 //===========================================================
 //     TEST SI MODE LEARN EN COURS
 //===========================================================
 if (etat == (MODELEARN2 | RFIDOK)) {
   //On trouve d'abord la premiere case de clé vide
   //en vérifiant que la clé est pas deja connue...
   for (i=0;i<MAX_CLES;i++) {
      if (!memcmpram2pgm(&cles[i],&rec[3],5)) {
         etat = 0;
         break;
      }
       else
        if (!memcmppgm(&cles[i],&clevide,5)) {
          WriteFlash(&cles[i],&rec[3],5);
          etat = 0;
          break;
        }
   }
   O_LEDV=0;
 }

 if (etat == (MODELEARN1 | RFIDOK)) {
   //On vérifie que la clé est connue pour MODELEARN2...
   for (i=0;i<MAX_CLES;i++) {
      if (!memcmpram2pgm(&cles[i],&rec[3],5)) {
         etat = MODELEARN2;
         O_LEDR=0;
		 O_LEDV=1;
         break;
      }
   }
 }
 
//===========================================================
//       RECEPTION ORDRE RFID
//===========================================================
 if (etat == RFIDOK) {
   //On vérifie que la clé est connue pour MODELEARN2...
   essai.accept =0;					// passage refusé par défaut
   etat=LEDROUGE;					//
   O_RELAIS = 0;					// ne ferme pas le relais / defaut

   for (i=0;i<MAX_CLES;i++) {
     if (!memcmpram2pgm(&cles[i],&rec[3],5))
      //Pas de date de fin -> c'est ok !
      if ((cles[i].fdate[2]==0)||(cles[i].fdate[2]==0xff)) {
        etat = 0;
        leds_on = 3;
        O_LEDV = 1;
		O_RELAIS = 1;					// ferme le relais
        essai.accept = 0xffff;		// passage accepté
        break;  }
      else {
        //Il y a une date de fin -> on la teste
        if (memcmppgm2ram(&yyyy, &cles[i].fdate, 4)<0) {
          etat = 0;
          leds_on = 3;
          O_LEDV = 1;
		  O_RELAIS = 1;					// ferme le relais
          essai.accept = 0xffff;		// passage accepté
          break;
        }
      }
   }

   //Recopie date & heure dans le tampon d'accés (essai[])
   //avant ecriture en flash de essai.
   essai.dd=dd;
   essai.mm=mm;
   essai.yyyy=yyyy;
   essai.hrs=hrs;
   essai.mins=mins;
   essai.secs=secs;
   //Recopie l'identifiant de 5ocs du RFID
   for (NByte=0;NByte<5;NByte++)
       essai.noserie[NByte]=rec[NByte+3];
   //Stocke et incre. le numero d'acces
   essai.numero=nextnumero++;
   //Ecrit la date complete, code[] et flags[]
   WriteFlash(&acces[accesptr++],&essai,16);
   if (accesptr>=MAX_ACCES) accesptr=0;
 }

 // Accès refusé on allume la led rouge
 if (etat & LEDROUGE) {
	etat = 0;
    leds_on = 3;
	O_LEDR = 1;
 }


//=========================================================
//         PARTIE RECEPTION DE COMMANDES USB
//=========================================================
 if((usb_device_state < CONFIGURED_STATE)||(UCONbits.SUSPND==1)) return;
 
 //Verifie que des données sont arrivées
 ordrelen=(USBGenRead((byte*)&usbuff, USBGEN_EP_SIZE));
 //Si oui prend la commande dans 'ordre'
 if (ordrelen!=0) ordre=usbuff._byte[0];

//=========================================================
//          Ordre de lecture mémoire flash
//=========================================================
 if (ordre==0x85) {
   TBLPTR = usbuff._byte[1]+(((unsigned int)usbuff._byte[2])<<8);
   for (NByte=0;NByte<32;NByte++) {
      TableRead_PostInc();
      usbuff._byte[NByte] = TABLAT;
   }
   send_oc = 32;
   ordre=0;
 }

//=========================================================
//          Ordre d'écriture en mémoire flash
//=========================================================
 if (ordre==0x58) {
   TBLPTR = usbuff._byte[1]+(((unsigned int)usbuff._byte[2])<<8);   
   WriteFlash( TBLPTR, &usbuff._byte[3], 28);
   usbuff._byte[0] = 0xAA;			// accusé de réception
   send_oc = 32;
   ordre=0;
 }

//=========================================================
//      Ordre d'effacement bloc flash de 64 ocs
//=========================================================
 if (ordre==0x55) {
   TBLPTR = usbuff._byte[1]+(((unsigned int)usbuff._byte[2])<<8);    
   EraseFlash(TBLPTR);
   usbuff._byte[0] = 0xAA;			// accusé de réception ok
   send_oc = 32;
   ordre=0;
 }

//=========================================================
//          Ordre Lecture Date/Heure -> PC
//=========================================================
 if (ordre==0xC5) {
   //accusé de réception ok
   usbuff._byte[0] = 0xAA;
   //Copie en bloc toute la dat/heure dans le buffer
   memcpy(&usbuff._byte[1], &yyyy, 7);
   send_oc = 32;
   ordre=0;
 }

//=========================================================
//         Ordre d'écriture PC -> Date/Heure
//=========================================================
 if (ordre==0xCA) {
   //Copie en bloc toute la date/heure dans le buffer
   memcpy(&yyyy, &usbuff._byte[1], 7);
   //accusé de réception ok
   usbuff._byte[0] = 0xAA;
   send_oc = 32;
   ordre=0;
 }

//=========================================================
//         VOIT SI RENVOI DE DONNEES EN RETOUR
//=========================================================
 if (send_oc > 0) {     
   if(!mUSBGenTxIsBusy()) {
      USBGenWrite(&usbuff, USBGEN_EP_SIZE);
      send_oc -= 32;
   }
 }

}//end ProcessIO
