//*****************************************************************************
// Title                : Pulse to tone (DTMF) converter
// Author                : Boris Cherkasskiy
// Created                : 2011-10-24
//
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//
// DTMF generator logic is loosely based on the AVR314 app note from Atmel
//
//*****************************************************************************

//*****************************************************************************
//            PIC16F628A VERSION TRANSLATED BY GioRock 2018
//*****************************************************************************

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

#include "RotaryPulseToTone.h"

// In EEPROM:
// 7 Numeri di composizione rapida (funzioni di chiamata speciali da 3 a 9)


// Variabili Globali
volatile unsigned char cSWa = 0x00;               // larghezza del passo di alta frequenza
volatile unsigned char cSWb = 0x00;               // larghezza del passo di bassa frequenza

volatile unsigned int iCurSinValA = 0;           // posizione freq. A in LUT (formato esteso)
volatile unsigned int iCurSinValB = 0;           // posizione freq. B in LUT (formato esteso)

volatile unsigned long ulDelayCounter = 0;       // Contatore di ritardo per la funzione sleep

// Struttura dello stato dei quadranti
typedef struct struct_DialStatus
{
        signed char iDialedDigit;                        // Composto/Cifra selezionata rilevata

        // Chiamato tenendo premuto il rotore per alcuni secondi (segnale acustico per indicare che SF è attivato) prima di rilasciarlo
        // SF definito: 1: *; 2: #; 3-9: composizione rapida; 0: programma il numero di composizione rapida 
        bool bSF_Selected;                               // Funzione speciale selezionata

        signed char iSpeedDialDigitIndex;                // Indice numerico di composizione rapida
        signed char iSpeedDialIndex;                     // Indice numerico di composizione rapida (nell' array SD)
        signed char arSpeedDial[SPEED_DIAL_SIZE];        // Blocco di composizione rapida selezionato
} type_DialStatus;

volatile type_DialStatus sDS;       // Struttura globale dello stato delle composizioni

//----- INIZIO PRINCIPALE ------------------------------------------------------
void main(void)
{
//Variabili locali
bool bPrevDialState = true;        // Stato del rotore precedente
bool bPrevPulseState = false;      // Stato degli impulsi del rotore precedente
bool bCurDialState = true;         // Stato del rotore attuale
bool bCurPulseState = false;       // Stato degli impulsi del rotore attuale
bool bSF_DetectionActive = false;  // SF rilevamento attivo
unsigned char ucPhoneType = 0;     // Selezione del tipo di Telefono

        // Inizializza gli I/O e le variabili globali
        init();

        // Spegne il PWM (OFF)
        GenerateDigit(DIGIT_OFF, 0);
        
        // Identifica il tipo di Telefono utilizzato
        // Il programma riconosce 4 tipi di Telefono
        // impostabili con i due Jumper appositi
        // X. Telefono  - JP1 JP2  - Quadrante (da sinistra a destra)
        // A. Standard  - OFF OFF  - 0987654321
        // B. Svedese   - ON  OFF  - 9876543210
        // C. Zelandese - OFF ON   - 0123456789
        // D. Antico    - ON  ON   - 1234567890 (raro)
        ucPhoneType = 3 - (PORTB & 0b00000011);
        
        // Imposta le PORTA 0 e 1 come variabili per memorizzare lo stato attuale dei
        // pin su PORTB 4 e 5 in modo da non resettare il flag sull'Interrupt
        // Questo è il segreto per far funzionare il codice su un PIC16F628A,
        // AVR usa un ulteriore registro per memorizzare lo stato degli ingressi
        // e preservare i flag di Interrupt, nei PIC16 invece non esiste
        PIN_DIAL_TEMP = ON;
        PIN_PULSE_TEMP = OFF;

        // Ciclo principale
        while (1)
        {


                bCurDialState  = PIN_DIAL_TEMP;

                bCurPulseState = PIN_PULSE_TEMP;


                if (bPrevDialState != bCurDialState)
                {
                        if (!bCurDialState)
                        {
                                // Composizione appena avviata
                                // Attivazione del rilevamento delle funzioni speciali
                                bSF_DetectionActive = true;
                                sDS.bSF_Selected = false;

                                sDS.iDialedDigit = 0;
                                SleepMS(25);        // Ritardo di 50ms (25 con PIC a 8MHz)
                        }
                        else
                        {
                                // Disabilitazione del rilevamento SF (dovrebbe essere già disabilitato???)
                                bSF_DetectionActive = false;

                                // Controlla che stiamo rilevando una cifra valida
                                if ((sDS.iDialedDigit <= 0) || (sDS.iDialedDigit > 10))
                                {
                                        // Non dovrebbe mai accadere - nessun impulso rilevato oppure conteggio superiore a 10 impulsi
                                        sDS.iDialedDigit = DIGIT_OFF;

                                        // Non fare nulla
                                        SleepMS(25);        // Ritardo 50ms (25 con PIC a 8MHz)
                                }
                                else
                                {
                                        // Ottenete una cifra valida - elaboratela
                                        // Telefono Standard
                                        /*if (sDS.iDialedDigit == 10)
                                        {
                                                // 10 impulsi => 0
                                                sDS.iDialedDigit = 0;
                                        }*/
                                        
                                        switch (ucPhoneType) {
                                               case 0:
                                                    // Telefono Standard (0987654321)
                                                    // 10 impulsi => 0
                                                    if (sDS.iDialedDigit == 10) sDS.iDialedDigit = 0;
                                                    break;
                                               case 1:
                                                    // Telefono Svedese (9876543210)
                                                    sDS.iDialedDigit = sDS.iDialedDigit - 1;
                                                    break;
                                               case 2:
                                                    // Telefono Zelandese (0123456789)
                                                    sDS.iDialedDigit = 10 - sDS.iDialedDigit;
                                                    break;
                                               case 3:
                                                    // Telefono Antico (1234567890)
                                                    sDS.iDialedDigit = 11 - sDS.iDialedDigit;
                                                    // 10 impulsi => 0
                                                    if (sDS.iDialedDigit == 10) sDS.iDialedDigit = 0;
                                                    break;
                                               default:
                                                    // Errore di configurazione del tipo di telefono
                                                    // Non dovrebbe mai capitare ma...
                                                    GenerateDigit (DIGIT_BEEP, 1000);
                                                    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
                                                    asm sleep;
                                                    break;
                                        }

                                        ProcessDialedDigit();
                                }

                                sDS.bSF_Selected = false;        // Resetta il flag SF
                        }
                }
                else
                {
                        if (!bCurDialState)
                        {
                                // Composizione in corso
                                if ((bPrevPulseState != bCurPulseState) && bCurPulseState)
                                {
                                        // Disattivazione del rilevamento SF
                                        bSF_DetectionActive = false;

                                        // Un impulso appena avviato
                                        sDS.iDialedDigit++;
                                        SleepMS(25);        // Ritardo 50ms (25 con PIC a 8MHz)
                                }
                        }
                        else
                        {
                                // Quadrante rotante in posizione di riposo
                                // Resetta tutte le variabili
                                bSF_DetectionActive = false;
                                sDS.bSF_Selected = false;
                                sDS.iDialedDigit = DIGIT_OFF;
                        }
                }

                bPrevDialState = bCurDialState;
                bPrevPulseState = bCurPulseState;

                // Non spegnere il PIC se è attivo il rilevamento delle funzioni speciali
                if (bSF_DetectionActive)
                {
                        // Rilevamento SF in corso - abbiamo bisogno del timer per poter funzionare (modalità IDLE)
                        // Nella realtà il PIC16F628A non ha una modaliatà IDLE del processore, così usiamo il WDT
                        // per simularne una simile anche se non è proprio la stessa cosa ma funziona ;-)

                        asm clrwdt;

                        if (!T1CON.TMR1ON) {
                              ResetTMR1();
                              PIR1.TMR1IF = false;
                              T1CON.TMR1ON = true;
                        }

                        // Modalità funzioni speciali rilevata?
                        if (ulDelayCounter >= SF_DELAY_MS * T1_OVERFLOW_PER_MS)
                        {
                                T1CON.TMR1ON = false;
                                PIR1.TMR1IF = true;

                                // Modalità SF rilevata
                                sDS.bSF_Selected = true;
                                bSF_DetectionActive = false;

                                // Indica che siamo entrati in modalità SF con un breve segnale acustico.
                                GenerateDigit(DIGIT_BEEP, 200);
                        }
                }
                else
                {
                        // Non è più necessario il timer: modalità sleep di spegnimento processore
                        set_sleep_mode(SLEEP_MODE_PWR_DOWN);
                        asm sleep;
                }
                
        }

}
//----- FINE ROUTINE PRINCIPALE ------------------------------------------------


// Elaborazione delle cifre composte
void ProcessDialedDigit (void)
{
     unsigned char i=0;
            // Funzioni speciali 1 e 2 (* e #)
            if (sDS.bSF_Selected && (sDS.iDialedDigit == 1))
            {
                    // SF 1-*
                    sDS.iDialedDigit = DIGIT_STAR;
            }
            else if (sDS.bSF_Selected && (sDS.iDialedDigit == 2))
            {
                    // SF 2-#
                    sDS.iDialedDigit = DIGIT_POUND;
            }

            // Funzionalità di selezione rapida: entrata e uscita dalla modalità SD
            if (sDS.bSF_Selected && (sDS.iDialedDigit == 0))
            {
                    // SF 0 - scrive il numero di composizione rapida

                    // Programmazione SP già in corso?
                    if (sDS.iSpeedDialDigitIndex < 0)
                    {
                            // Appena entrato nel modo SD
                            sDS.iSpeedDialDigitIndex = 0;

                            // A questo punto non conosciamo ancora l' indice SD
                            sDS.iSpeedDialIndex = -1;

                            // Cancella l'array SD selezionato
                            for (i = 0; i<SPEED_DIAL_SIZE; i++)
                            {
                                    sDS.arSpeedDial[i] = DIGIT_OFF;
                            }

                            // Beep quando si entra nella modalità SD, l'utente è entrato nell'indice SD
                            GenerateDigit (DIGIT_TUNE_ASC, 700);
                            GenerateDigit (DIGIT_TUNE_DESC, 700);
                    }
                    else
                    {
                            // SD in corso, l'utente è inserito in SF 0 - salvo SD ed esco dalla modalità SD

                            // Salvo il numero di chiamata rapida
                            WriteCurrentSpeedDial(sDS.iSpeedDialIndex);

                            // Abbandono la modalità SD
                            sDS.iSpeedDialIndex = -1;
                            sDS.iSpeedDialDigitIndex = -1;

                            // Beep per indicare che è stato fatto
                            GenerateDigit (DIGIT_TUNE_DESC, 800);
                    }
            }
            // Programmazione numero SD
            else if (sDS.iSpeedDialDigitIndex >= 0)
            {
                    // Composizione della prima cifra dopo aver selezionato la modalità SD. Indice SD non ancora impostato
                    if (sDS.iSpeedDialIndex < 0)
                    {
                            // L'indice SD dovrebbe essere compreso tra 3 e 9
                            if ((sDS.iDialedDigit >= 3) && (sDS.iDialedDigit <= 9))
                            {
                                    sDS.iSpeedDialIndex = sDS.iDialedDigit;

                                    // Beep per indicare che siamo in modalità SD
                                    GenerateDigit (DIGIT_TUNE_ASC, 800);
                            }
                            else
                            {
                                    // Indice SD errato - beep e uscita dalla modalità SD

                                    // Abbandono la modalità SD
                                    sDS.iSpeedDialIndex = -1;
                                    sDS.iSpeedDialDigitIndex = -1;

                                    // Un lungo Beep per indicare un errore
                                    GenerateDigit (DIGIT_BEEP, 1000);
                            }
                    }
                    else
                    {
                            // Programmazione SD già in corso

                            // Abbiamo troppe cifre inserite?
                            if (sDS.iSpeedDialDigitIndex >= SPEED_DIAL_SIZE)
                            {
                                    // SI - Termino e salvo il numero di composizione rapida

                                    // Salva numero di chiamata rapida
                                    WriteCurrentSpeedDial(sDS.iSpeedDialIndex);

                                    // Abbandono la modalità SD
                                    sDS.iSpeedDialIndex = -1;
                                    sDS.iSpeedDialDigitIndex = -1;

                                    // Beep per indicare che è stato fatto
                                    GenerateDigit (DIGIT_TUNE_DESC, 800);
                            }
                            else
                            {
                                    // Tutto a posto - imposto una nuova cifra sull'array
                                    sDS.arSpeedDial[sDS.iSpeedDialDigitIndex] = sDS.iDialedDigit;

                                    // Beep generico - non produco il codice DTMF
                                    GenerateDigit(DIGIT_BEEP_LOW, DTMF_DURATION_MS);

                                    // Prossima cifra
                                    sDS.iSpeedDialDigitIndex++;
                            }
                    }
            }
            // Chiamo il numero SD memorizzato
            else if (sDS.bSF_Selected && (sDS.iDialedDigit >= 3) && (sDS.iDialedDigit <= 9))
            {
                    // SF 3-9 -> Numero di chiamata rapida
                    Dial_SpeedDialNumber(sDS.iDialedDigit);
            }
            // Standard (funzionalità di chiamata non rapida)
            else
            {
                    // Modalità standard (nessuna selezione rapida, nessuna funzione speciale)
                    // Genero il codice DTMF
                    GenerateDigit(sDS.iDialedDigit, DTMF_DURATION_MS);
            }
}

// Inizializzazione PIC
void init(void)
{
    unsigned char i = 0;

        CMCON      = 0b00000111; // Disabilita i comparatori
        TRISA      = 0b00100000; // PORTA tutte uscite eccetto MCLR
        TRISB      = 0b00110011; // PORTB tutte uscite eccetto RB0, RB1, RB4 e RB5
        PORTA      = 0b00100000; // tutte le porte A a livello basso eccetto MCLR
        PORTB      = 0b00110011; // tutte le porte B a livello basso eccetto RB0, RB1, RB4 e RB5, RB3 uscita PWM
        OPTION_REG = 0b01001000; // Pull-up su PORTB Abilitate + WDT prescaler 1:1 (Watch Dog Timer)
        INTCON     = 0b00001000; // Interrupt Globale disabilitato + Interrupt delle Priferiche disabilitato + RB<7:4> Interrupt abilitato
        T1CON      = 0b00000001; // Impostazione TIMER1 interno sincrono Prescaler 1:1 abilitato (Fck / 4)
        T2CON      = 0b00000100; // Prescaler TIMER2 1:1 per il modulo PWM
        PR2        = 0b01111111; // Preload TIMER2 per una frequenza di 62500 Hz con XT a 8Mhz risoluzione 8bit (vedere il datasheet)
        CCP1CON    = 0b00001100; // Impostazione della modalità PWM - 0x0C
        CCPR1L     = 0b00000000; // Reset del Duty Cycle a 8bit MAX.
        PIE1       = 0b00000001; // CCP1 Interrupt + TIMER2 su PR2 Interrupt su corrispondenza del periodo disabilitati + TIMER1 Overflow Interrupt abilitato

        // Fermo il generatore PWM e spengo l'uscita
        PWM_Stop();
        PIN_PWM_OUT = OFF;

        // Inizializza la struttura (globale) dello stato della chiamata (sDS)
        sDS.iDialedDigit = DIGIT_OFF;

        // SF composto tenendo premuto il rotore per alcuni secondi (segnale acustico per indicare che SF è attivato) prima di rilasciarlo
        // SF definito: 1:*; 2:#; 3-9: composizione rapida; 0: programma il numero di composizione rapida
        sDS.bSF_Selected = false;        // Funzione Speciale selezionata

        // Velocità del Quadrante
        sDS.iSpeedDialDigitIndex = -1;        // Indice numerico di composizione rapida
        sDS.iSpeedDialIndex = -1;             // Indice numerico di composizione rapida (nell'array SD)
        for (i=0; i<SPEED_DIAL_SIZE; i++)     // Cancella l'array SD selezionato
        {
                sDS.arSpeedDial[i] = DIGIT_OFF;
        }

        // Resetta tutti i settaggi e abilita gli Interrupt
        ResetTMR1();                // Resetta il Timer1

        INTCON.RBIF = false;        // Resetta il flag RB<7:4>
        PIR1.TMR1IF = false;        // Resetta il flag TMR1
        PIR1.TMR2IF = false;        // Resetta il flag TMR2
        
        INTCON.PEIE = true;         // Abilita l'Interrupt sulle Periferiche
        INTCON.GIE = true;          // Abilita l'Interrupt Globale

}

// Questa funzione simula la modalità del TM0 dell'AVR8
// in modalità IDLE per risparmiare corrente
// Quì usiamo il TIMER1 per generare un Interrupt per
// rivegliare il PIC16F628A - PSEUDO IDLE MODE
void set_sleep_mode(unsigned char s_mode)
{
      ResetTMR1();
      
      asm clrwdt;
      
      if(s_mode == SLEEP_MODE_IDLE) {
            // Prescaler WDT 1:1
            OPTION_REG.PS2 = 0;
            OPTION_REG.PS1 = 0;
            OPTION_REG.PS0 = 0;
            PIR1.TMR1IF = false;
            T1CON.TMR1ON = true;
      } else if (s_mode == SLEEP_MODE_PWR_DOWN){
            // Prescaler WDT 1:128
            OPTION_REG.PS2 = 1;
            OPTION_REG.PS1 = 1;
            OPTION_REG.PS0 = 1;
            PIR1.TMR1IF = true;
      }
}

// Genera i toni DTMF, durata x ms
void GenerateDigit (signed char scDigit, unsigned int uiDuarationMS)
{
            if (scDigit >= 0 && scDigit <= DIGIT_POUND)
            {
                    // Cifre standard 0-9, *, #
                    cSWa = auc_frequency[scDigit][0];
                    cSWb = auc_frequency[scDigit][1];
                    EnablePWM();

                    // Attesa x ms
                    SleepMS(uiDuarationMS);
            }
            else if (scDigit==DIGIT_BEEP)
            {
                    // Beep ~1000Hz (66)
                    cSWa = 122;
                    cSWb = 0;
                    EnablePWM();

                    // Attesa x ms
                    SleepMS(uiDuarationMS);
            }
            else if (scDigit==DIGIT_BEEP_LOW)
            {
                    // Beep ~500Hz (33)
                    cSWa = 66;
                    cSWb = 0;
                    EnablePWM();

                    // Attesa x ms
                    SleepMS(uiDuarationMS);
            }
            else if (scDigit==DIGIT_TUNE_ASC)
            {
                    cSWa = 68;         // C=523.25Hz
                    cSWb = 0;
                    EnablePWM();

                    SleepMS(uiDuarationMS/3);
                    cSWa = 86;         // E=659.26Hz
                    SleepMS(uiDuarationMS/3);
                    cSWa = 102;        // G=784Hz
                    SleepMS(uiDuarationMS/3);
            }
            else if (scDigit==DIGIT_TUNE_DESC)
            {
                    cSWa = 102;        // G=784Hz
                    cSWb = 0;
                    EnablePWM();

                    SleepMS(uiDuarationMS/3);
                    cSWa = 86;        // E=659.26Hz
                    SleepMS(uiDuarationMS/3);
                    cSWa = 68;        // C=523.25Hz
                    SleepMS(uiDuarationMS/3);
            }


        // Fermo la trasmissione DTMF
        // Disabilito il PWM e spengo l'uscita con la MACRO
        // La modalità di corrispondenza del periodo è disabilitata
        PWM_Stop();
        PIN_PWM_OUT = OFF;
        
        #ifdef USE_LED
            PIN_LED = OFF;
        #endif
        
        // Resetto le variabili di generazione del segnale
        cSWa = 0;
        cSWb = 0;

}

// Abilito l'uscita PWM configurando la modalità di corrispondenza con comparazione - senza inversione del PWM
void EnablePWM(void)
{
    
    // Opzionale posso accendere un LED
    #ifdef USE_LED
        PIN_LED = ON; // It does working???  OK!!!
    #endif
    
    PWM_Start();

}


// Attesa x ms
void SleepMS(unsigned int uiMsec)
{
        ulDelayCounter = 0;

        set_sleep_mode(SLEEP_MODE_IDLE);
        asm sleep;

        while(ulDelayCounter <= uiMsec * T1_OVERFLOW_PER_MS)
        {
                // Usando il WDT prima di ogni 18ms bisogna fare un reset
                // se siamo in modalità sleep, il PIC non si resetta ma
                // ritorna alla chiamata successiva dopo questa (trucco)
                asm clrwdt;
                // Riaccendo il TIMER dopo l'Interrupt
                T1CON.TMR1ON = true;

        }

        // Spengo il TIMER che non serve più
        T1CON.TMR1ON = false;

}

// Legge il numero nella EEPROM in un passaggio
void eeprom_read_byte_block(char * __dst, char __src, unsigned short __n)
{
     unsigned char p;
     unsigned char * dst;
     
     p = __src;
     dst = __dst;
     
     while (__n--) {
           * dst++ = EEPROM_Read(p++);
           SleepMS(20);
     }
}

// Scrive il numero nella EEPROM e solo se il valore attuale è differente
void eeprom_update_byte_block(char * __src, char __dst, unsigned short __n)
{
     unsigned char p;
     unsigned char * src;
     
     p = __dst;
     src = __src;

     while (__n--) {
           if (EEPROM_Read(p) !=  * src+p) {
                SleepMS(20);
                EEPROM_Write(p++, * src++);
                SleepMS(20);
           }
     }
}

// Composizione del numero di selezione rapida - (elimina il numero SD corrente nella struttura globale)
void Dial_SpeedDialNumber(unsigned char iSpeedDialIndex)
{
  unsigned char i=0;

        if ((iSpeedDialIndex >= 3) && (iSpeedDialIndex <= 9))
        {
        
                // Se è chiamato l'indice 3 => utilizza l'indice 0 dell'array
                eeprom_read_byte_block((char *)sDS.arSpeedDial, ((iSpeedDialIndex - 3) * SPEED_DIAL_SIZE), SPEED_DIAL_SIZE);

                for (i=0; i<SPEED_DIAL_SIZE; i++)
                {
                        // Chiamo il numero
                        // Salto le cifre non valide
                        if ( (sDS.arSpeedDial[i] >= 0) && (sDS.arSpeedDial[i] <= DIGIT_POUND) )
                        {
                                GenerateDigit(sDS.arSpeedDial[i], DTMF_DURATION_MS);

                                // Una pausa tra i toni DTMF
                                SleepMS(DTMF_DURATION_MS);
                        }
                }
        }

}


// Scrivo l'array di selezione rapida corrente (dalla versione globale) alla EEPROM
void WriteCurrentSpeedDial(unsigned char iSpeedDialIndex)
{

        if ((iSpeedDialIndex >= 3) && (iSpeedDialIndex <= 9))
        {
                // Se è chiamato l'indice 3 => utilizza l'indice 0 dell'array
                eeprom_update_byte_block((char *)sDS.arSpeedDial, ((iSpeedDialIndex - 3) * SPEED_DIAL_SIZE), SPEED_DIAL_SIZE);
        }

}


//Routine di Interrupt
void Interrupt(void)
{
    unsigned char ucSinA = 0;
    unsigned char ucSinB = 0;
    unsigned int i_TmpSinValA = 0;
    unsigned int i_TmpSinValB = 0;

    // ISR Timer2 overflow o corrispondenza con il periodo del PWM (Interrupt Service Routine)
    if (PIR1.TMR2IF) {

            // PIR1.TMR2IF = 0;  // Spostare qui se XT è di 20MHz

            // Viene sempre utilizzata una componente (alta frequenza)
            // sposto il Puntatore a circa la larghezza del passo in avanti
            iCurSinValA += cSWa;
            // normalizzo il Puntatore temporaneo
            i_TmpSinValA = (char)(((iCurSinValA + 4) >> 3) & (0x007F));
            ucSinA = auc_SinParam[i_TmpSinValA];


            //        La componente B (bassa frequenza) è opzionale
            if (cSWb > 0)
            {
                    // sposto il Puntatore a circa la larghezza del passo in avanti
                    iCurSinValB += cSWb;
                    // normalizzo il Puntatore temporaneo
                    i_TmpSinValB = (char)(((iCurSinValB + 4) >> 3) & (0x007F));
                    ucSinB = auc_SinParam[i_TmpSinValB];
            }
            else
            {
                    ucSinB = 0;
            }

            // calcolo il valore del PWM: valore dell'alta frequenza + 3/4 del valore della bassa frequenza
            // Per recuperare la bassa risoluzione dei bit dovuto al prescaler del PIC che divide XT per 4
            // moltiplico il duty risultante per 2 in maniera da compensare tale perdita anche se il massimo
            // valore della risoluzione PWM scende da 512 a 256 MAX.
            SetDutyCycle((ucSinA + (ucSinB - (ucSinB >> 2))) << 1);

            PIR1.TMR2IF = false; // Resetto il flag del Timer2

    // ISR Timer1 overflow (Interrupt Sservice Routine)
    } else if (PIR1.TMR1IF) {

              ResetTMR1();
              // Incremento il contatore per calcolare il tempo trascorso
              ulDelayCounter++;
              PIR1.TMR1IF = false; // Resetto il flag del Timer1

    } else if (INTCON.RBIF) {
        // I pin su PORTB hanno generato un Interrupt
        // Salvo lo stato corrente degli ingressi su PORTA

          PIN_DIAL_TEMP = PIN_DIAL;
          PIN_PULSE_TEMP = PIN_PULSE;

          // Piccola pausa per assicurarci che non ci siano rimbalzi
          Delay_us(100);

          // Resetto il flag su RB<7:4>
          INTCON.RBIF = false;

    }

}

// Funzione per impostare il Duty Cycle a 8bit
void SetDutyCycle(unsigned int duty) {
    CCPR1L  = (duty >> 2) & 0xFF; // Traslo il PWM da 10bit a 8bit
    CCP1X_bit= 0; // 8bit PWM
    CCP1Y_bit= 0; // 8bit PWM
}

// Reimpostazione del TIMER1
void ResetTMR1(void)
{
     T1CON.TMR1ON = false;
     TMR1H = T1_PRELOAD_PER_MS;
     TMR1L = 255;
}