                ;**********************************************************************
                ;  T628A16.ASM
                ;**********************************************************************
                ;
                ;  Progetto:
                ;    TERMOIGROMETRO RS485
                ;
                ;  Autore:
                ;    Sergio Tanzilli (http://www.tanzilli.com)
                ;
                ;  Versione:
                ;    26/03/2004 Revisione per PIC16F628A
                ;     1/02/2004 Porting su PICmicro 16F628 su scheda ST01 versione 1.00
                ;    18/06/2003 Versione per SHT71
                ;     3/05/2004 Versione per scheda ST01 versione 2.0
                ;
                ;  Modifiche da fare:
                ;
                ;    Il campo SNAP NDB per ora non e' compatibile con le specifiche SNAP in
                ;    quanto il suo valore viene usato cosi' com'e' e non come indice
                ;    per la tabella delle lunghezze definite dal protocollo.
                ;
                ;  Note sulla compatibilità con SNAP
                ;
                ;    Molte caratteristiche previste dal protocollo SNAP non vengono
                ;    implementate (www.hth.com). I pacchetti hanno un campo di indirizzamento
                ;    fisso a 8 bit e l'unico controllo d'errore e' il CRC16
                ;
                ;**********************************************************************

                PROCESSOR       16F628A
                RADIX           DEC
                INCLUDE         "P16F628A.INC"
                ERRORLEVEL      -302          ;Elimina la segnalazione di warning n.302
                __CONFIG        0x3F62

#define         MY_ADDR            20         ;Indirizzo di questo nodo
#define         MASTER_ADDR     	0         ;Indirizzo del dispositivo master

#define         MAXPOLLINGDELAY   150         ;Ritardo massimo di polling (s) prima di accendere
                                              ;il led rosso

#define         DATA_BIT          PORTA,0     ;Port A0 linea dati del sensore
#define         CLOCK_BIT         PORTA,1     ;Port A1 linea del clock del sensore
#define         COM_DE            PORTB,3     ;Port B3 linea di abilitazione tx RS485 (1=abilitato)
#define         LED_ROSSO         PORTB,4     ;Port B4 Led Rosso
#define         LED_VERDE         PORTB,5     ;Port B5 Led Verde
#define         L_VERDE           PORTA,4     ;Port A5 Led Verde
#define         INGRESSO          PORTB,0
                ;Comandi riconosciuti dal sensore SHT71

#define         CMD_READ_TEMP     0x03  ;Comando di lettura temperatura
#define         CMD_READ_HUM      0x05  ;Comando di lettura umidità

                ;**********************************************************************
                ; Parametri SNAP
                ;**********************************************************************

                ;Frame coding

#define         SNAP_ACK        0x10
#define         SNAP_NACK       0x02
#define         SNAP_SYNC       0x54

                ;SNAP Frame properties

#define         TX_MAX_DL 16    ;Max data lenght on tx packet
#define         RX_MAX_DL 16    ;Max data lenght on rx packet

                ;RX buffer status flags (tzn_rxb_flag)

#define         RX_DATA_READY   1       ;Data buffer contains valid data
#define         RX_FLOW_ON      2       ;Byte are coming from rx line

                ;RX packet status flags (tzn_rxp_flag)
                ;Please refer to SNAP protocol definitions on http://www.hth.com

#define         RX_SYNC         0       ;SYNC byte received
#define         RX_HDB2         1       ;HDB2 byte received
#define         RX_HDB1         2       ;HDB1 byte received
#define         RX_DAB1         3       ;DAB1 byte received
#define         RX_SAB1         4       ;SAB1 byte received
#define         RX_DB           5       ;DB   byte received
#define         RX_CRC2         6       ;CRC2 byte received

                ;TX status register flags (tzn_txb_flag)

#define         TX_DATA_READY   1       ;Tx buffer with data to transmit


#define         RX_TIMEOUT      10      ;Timeout in ricezione. Indica il tempo massimo che il PIC aspetta
                                        ;tra un carattere e l'altro superato il quale annulla la ricezione
                                        ;dell'intero pacchetto. 2 = 1ms

                ;File register on BANK 0

#define         W_TEMP          0x20    ;Temporany register used to save and restore W, STATUS,
#define         STATUS_TEMP     0x21    ;PCLATH and FSR register while an interrupt handler
#define         PCLATH_TEMP     0x22    ;routine is executed
#define         FSR_TEMP        0x23

#define         msDelayTimer    0x24    ;msDelay subroutine counter
#define         msDelayTmp      0x25

                org     0xA0

                ;File register on BANK 1

W_TEMP_mirrow   res     1     ;Questo registro viene usato per memorizzare il valore
                              ;dell'accumulatore quando si verifica un interrupt. Non
                              ;cambiarne l'indirizzo !!

saveSTATUS      res     1

tzn_rxp_flag    res     1     ;Rx packet status flags
tzn_rxb_flag    res     1     ;Rx buffer status flags

RxNDB           res     1     ;Number of Data Bytes extract from NDB field
RxCRC2          res     1     ;CRC16 del pacchetto ricevuto
RxCRC1          res     1

RxDataCounter   res     1
RxWritePointer  res     1
RxToutTimer     res     1
rxDummyCounter  res     1

RxCRC_Temp      res     1
RxCRC_Count     res     1
RxCRC_High      res     1
RxCRC_Low       res     1

RxIncomingChar  res     1

txNDB           res     1
TxBitDelayCount res     1     ;Contatore utilizzato nella macro ONE_BIT_DELAY
txDummyCounter  res     1

TxCRC_Temp      res     1
TxCRC_Count     res     1
TxCRC_High      res     1
TxCRC_Low       res     1

sysTimer0L      res     1
sysTimer0H      res     1

inputTimer      res     1

TestLedCounter  res     2


                ;Tx Buffer

tzn_txheader    res     4               ;Tx header
tzn_txdata      res     TX_MAX_DL       ;Tx max data len
tzn_txcrc       res     2               ;Tx CRC16

                ;Rx Buffer

tzn_rxdata      res     RX_MAX_DL

last_register   res     1               ;Questo registro non viene usato dal programma mi serve solo
                                        ;per vedere quanta memoria RAM ho usato

                ;**********************************************************************
                ; Registri
                ;**********************************************************************

                org     0x30

firstdata       res     1
myCounter       res     1

                ;Variabili usate dalle routine di lettura dal sensore SHT71/75

LoopVar         res     1
Temp            res     1
DelayL          res     1
DelayH          res     1
WithAck         res     1
TempL           res     1
TempH           res     1
HumL            res     1
HumH            res     1
Checksum        res     1
Delay_cnt1      res     1
Delay_cnt2      res     1

ReadDelay       res     1
UTToggle        res     1

pollAllarm      res     1

                ;**********************************************************************
                ; Macro usate per SNAP
                ;**********************************************************************


ONE_BIT_DELAY   MACRO
                LOCAL   OneBitDelayLoop

                movlw   72      ;Wait a bit (Clock 16Mhz)

                movwf   TxBitDelayCount
OneBitDelayLoop
                decfsz  TxBitDelayCount,F
                goto    OneBitDelayLoop
                ENDM

                ; Swap to register bank 0

SWAP_TO_BANK0   MACRO
                bcf     STATUS,RP0              ;Point to BANK 0
                ENDM

                ; Swap to register bank 1

SWAP_TO_BANK1   MACRO
                bsf     STATUS,RP0              ;Point to BANK 1
                ENDM

                ;*************************************************************************
                ; Inizializza ed abilita la sezione RX
                ;*************************************************************************

INIT_RX         MACRO

                SWAP_TO_BANK1
                clrf    tzn_rxb_flag            ;Clear all rx flags
                clrf    tzn_rxp_flag

                SWAP_TO_BANK0
                bcf     RCSTA,CREN
                bsf     RCSTA,CREN

                movf    RCREG,W                 ;Empty USART RX buffer
                bcf     COM_DE            			;Disable RS485 driver

                SWAP_TO_BANK1
                bsf     PIE1,RCIE               ;Enable the USART receive interrupt

                ENDM


                ; Macro per le linee clock e dati
DATA_LINE_IN    MACRO
                SWAP_TO_BANK1
                ;bsf TRISA, DATA_BIT
                bsf DATA_BIT
                SWAP_TO_BANK0
                ENDM

DATA_LINE_OUT   MACRO
                SWAP_TO_BANK1
                ;bcf TRISA, DATA_BIT
                bcf DATA_BIT
                SWAP_TO_BANK0
                ENDM

DATA_LINE_LOW   MACRO
                bcf DATA_BIT
                ENDM

                ; Legge la linea dati. Salta se è a 1
DATA_LINE_READ  MACRO
                btfss DATA_BIT
                ENDM

DATA_LINE_HIGH  MACRO
                bsf DATA_BIT
                ENDM

CLOCK_LINE_LOW  MACRO
                bcf CLOCK_BIT
                ENDM

CLOCK_LINE_HIGH MACRO
                bsf CLOCK_BIT
                ENDM

                ;**********************************************************************
                ; Reset vector
                ;**********************************************************************

                ORG     0x00
                goto    Main

                ORG     0x04
                goto    Interrupt_handler

                ;**********************************************************************
                ; Invia la sequenza di start al sensore
                ;**********************************************************************
                
SendStart

                DATA_LINE_OUT
                
                CLOCK_LINE_HIGH
                nop
                nop
                nop
                DATA_LINE_LOW
                CLOCK_LINE_LOW
                nop
                nop
                nop
                CLOCK_LINE_HIGH
                nop
                nop
                nop
                DATA_LINE_HIGH
                CLOCK_LINE_LOW
                
                DATA_LINE_IN
                return

                ;**********************************************************************
                ; Invia un reset logico al sensore
                ;**********************************************************************

SendReset

                movlw 0x0B
                movwf LoopVar

ResetLoop
                CLOCK_LINE_HIGH
                nop
                nop
                nop
                CLOCK_LINE_LOW
                decfsz  LoopVar, F
                goto ResetLoop
                return

                ;**********************************************************************
                ; Invia un byte
                ; il byte deve essere in W
                ; Torna 1 se tutto OK, 0 altrimenti
                ;**********************************************************************

SHT_SendByte

                ; Valore del byte in Temp
                DATA_LINE_OUT
                movwf Temp
        
                ; Inizializzazione del Loop
                movlw 0x80
                movwf LoopVar

SendLoop

                ; Se il bit è 1 alzo la linea dati
                movf Temp,W
                andwf LoopVar,W
                btfsc STATUS,Z
                goto Set0
                DATA_LINE_HIGH
                goto Prosegui

Set0
                DATA_LINE_LOW

Prosegui
                CLOCK_LINE_HIGH
                nop
                nop
                nop
                CLOCK_LINE_LOW
        
                ; Controllo il fine loop
                bcf STATUS,C
                rrf LoopVar,F
                movf LoopVar,F
                btfss STATUS,Z
                goto SendLoop
        
                ; Aspetta l'ACK
                DATA_LINE_IN
                CLOCK_LINE_HIGH
        
                ; Carico il timeout
                movlw 0xFF
                movwf DelayL

WaitAck
                ; Attende che la linea dati torni bassa
                DATA_LINE_READ
                goto AckReceived
        
                ; Controllo il timeout
                decfsz DelayL,F
                goto WaitAck
                retlw 0x00

AckReceived
                ; ACK Ricevuto
                CLOCK_LINE_LOW
                retlw 0x01


                ;**********************************************************************
                ; Legge un byte
                ; Se la variabile WithAck è 1 manda l'ack, altrimenti no
                ; Ritorna con il byte letto in W
                ;**********************************************************************

ReadByte
                clrf Temp
                DATA_LINE_IN
        
                ; Inizializzazione del Loop
                movlw 0x80
                movwf LoopVar

ReceiveLoop
                CLOCK_LINE_HIGH
                nop
                nop
                nop
                ; Leggo la linea dati, se 0 proseguo, altrimenti setto il bit
                DATA_LINE_READ
                goto ReceiveProsegui
                movf LoopVar,W
                iorwf Temp, F

ReceiveProsegui
                CLOCK_LINE_LOW;
        
                ; Controllo il fine loop
                bcf STATUS,C
                rrf LoopVar,F
                movf LoopVar,F
                btfss STATUS,Z
                goto ReceiveLoop
        
        
                ; Ok, byte terminato. Mando l'ACK se richiesto
                btfss WithAck,0
                goto NoAkcRequested
        
                ; Acknowledge del byte
                DATA_LINE_OUT
                DATA_LINE_LOW
                CLOCK_LINE_HIGH
                nop
                nop
                nop
                CLOCK_LINE_LOW
                DATA_LINE_IN
        
                ; Ritorna il valore letto
                movf Temp,W
                return

NoAkcRequested
                ; Senza acknowledge
                DATA_LINE_OUT
                DATA_LINE_HIGH
                CLOCK_LINE_HIGH
                nop
                nop
                nop
                CLOCK_LINE_LOW
                DATA_LINE_IN
        
                ; Ritorna il valore letto
                movf Temp,W
                return


                ;**********************************************************************
                ; Legge la temperatura
                ; Riporta il valore in TempL e TempH
                ;**********************************************************************

ReadTemperature
                ; Invia la sequenza di startup
                call SendStart
                
                ; Invia il comando di lettura
                movlw CMD_READ_TEMP
                call SHT_SendByte
                ; Controllo se è andato tutto bene, altrimenti resetto ed esco
                andlw  0x01
                btfss  STATUS,Z
                goto ProseguiReadTemp
        
                call SendReset
                retlw 0x00

ProseguiReadTemp
                ; Attende che la misura sia disponibile (linea dati bassa)
                DATA_LINE_READ
                goto EndReadT
                goto ProseguiReadTemp

EndReadT
                ; Legge i byte di dati
                clrf WithAck
                incf WithAck,F
                call ReadByte
                movwf TempH
                call ReadByte
                movwf TempL
        
                clrf WithAck
                call ReadByte
                movwf Checksum
                
        
                retlw 0x01


                ;**********************************************************************
                ; Legge l'umidità
                ; Riporta il valore in HumL e HumH
                ;**********************************************************************
ReadHumidity
                ; Invia la sequenza di startup
                call SendStart
                
                ; Invia il comando di lettura
                movlw CMD_READ_HUM
                call SHT_SendByte
                
                ; Controllo se è andato tutto bene, altrimenti resetto ed esco
                andlw  0x01
                btfss  STATUS,Z
                goto ProseguiReadHum
        
                call SendReset
                retlw 0x00

ProseguiReadHum
                ; Attende che la misura sia disponibile (linea dati bassa)
                DATA_LINE_READ
                goto EndReadH
                goto ProseguiReadHum

EndReadH
                ; Legge i byte di dati
                clrf WithAck
                incf WithAck,F
                call ReadByte
;******************************
;               movlw 0
;               btfss INGRESSO
;               movlw 10
;******************************
                movwf HumH
                call ReadByte
;******************************
;               movlw 0
;               btfss INGRESSO
;               movlw 10
;******************************
                movwf HumL
        
                clrf WithAck
                call ReadByte
                movwf Checksum
                
                retlw 0x01

                ;**********************************************************************
                ;**********************************************************************
                ;**********************************************************************
                ;**********************************************************************
                ; Main
                ;**********************************************************************
                ;**********************************************************************
                ;**********************************************************************
                ;**********************************************************************
Main
                clrf    STATUS

                ; Init BANK1 register

                SWAP_TO_BANK1

                ;Set the default the I/O lines state

                ;RA0    (pin 17) <-> Data line SH7x
                ;RA1    (pin 18) --> Clock line SHT7x
                ;RA2    (pin  1) <-- 0=Termo     1=Opto
                ;RA3    (pin  2) <-- 0=Aperto    1=Chiuso
                ;RA4    (pin  3) --> N.C

                ;RB0    (pin  6) --> Niente    
                ;RB1    (pin  7) <-- RS485 RXD
                ;RB2    (pin  8) --> RS485 TXD
                ;RB3    (pin  9) --> RS485 DE
                ;RB4    (pin 10) --> LED Rosso
                ;RB5    (pin 11) --> LED Verde
                ;RB6    (pin 12) --> PGC
                ;RB7    (pin 13) --> PGD

                movlw   00000100B   ; Modificato RA2, è diventato ingresso.
                movwf   TRISA

                movlw   00000011B
                movwf   TRISB

                ;Reset all registers on bank 1

                movlw   0xA0
                movwf   FSR
InitBank1Loop
                clrf    INDF
                incf    FSR,F
                btfss   STATUS,Z
                goto    InitBank1Loop

                INIT_RX

                SWAP_TO_BANK1

                movlw   12                      ;19200 baud (Clock = 16Mhz)
                movwf   SPBRG

                bcf     TXSTA,SYNC              ;Asynchronous mode
                bsf     TXSTA,TXEN              ;Transmit enabled
                bcf     TXSTA,TX9               ;Select 8 bit transmission

                bcf     TXSTA,BRGH              ;Low speed

                bsf     PIE1,RCIE               ;Enables the USART to generate RX interrupt
                bcf     PIE1,TXIE               ;Disables the USART to generate TX interrupt

                bcf     OPTION_REG,NOT_RBPU     ;Port B pull up enabled
                bcf     OPTION_REG,T0CS         ;Timer0 source internal cycle clock
                bcf     OPTION_REG,PSA          ;Prescaler in assigned to the Timer0

                ;Set the prescaler (Clock = 16Mhz)
                bcf     OPTION_REG,PS2          ;Prescaler 1:16
                bsf     OPTION_REG,PS1          ;16MHz/4 = 4MHz/8 = 500KHz/(256-6) = 2KHz
                bcf     OPTION_REG,PS0          ;to obtain a TMR0 interrupt each 0.5ms

                ;Init BANK0 register

                SWAP_TO_BANK0

                ;Reset all registers on bank 0

                movlw   0x20
                movwf   FSR
InitBank0Loop
                clrf    INDF
                incf    FSR,F

                movlw   0x80
                xorwf   FSR,W

                btfss   STATUS,Z
                goto    InitBank0Loop

                movlw 0x07                      ;Porta A in modalità digitale (Vedi pagina 53)
                movwf CMCON

                ;Init register

                bsf     RCSTA,SPEN              ;Serial port enabled
                bsf     RCSTA,CREN              ;Enables continuous receive
                bcf     RCSTA,RX9               ;Select 8 bit reception

                movlw   6
                movwf   TMR0

                bsf     INTCON,T0IE             ;Enables TMR0 overflow interrupt
                bsf     INTCON,PEIE             ;Enables all un-masked peripheral interrupts

                bsf     INTCON,GIE              ;Enables Global Interrupt

                bcf     COM_DE 			        ;Disable RS485 tx driver
                bcf     LED_ROSSO
                bcf     LED_VERDE

                movlw   MAXPOLLINGDELAY
                movwf   pollAllarm

                ;**********************************************************************
                ; LOOP PRINCIPALE
                ;**********************************************************************
MainLoop
                SWAP_TO_BANK0

check_rx_buffer
                SWAP_TO_BANK1
                btfss   tzn_rxb_flag,RX_DATA_READY  ;Ci sono dati validi ?
                goto    _check_rx_buffer            ;No, passa al task successivo
                                                    ;Si, controlla cosa e' stato ricevuto

                ;---------------------------------------------------------------
                ; 0x02 Richiesta di trasmissione dei valori di temperatura
                ;      ed umidita
                ;
                ; Risposta nel campo NDB:
                ;
                ;   [TempH] [TempL] [HumH] [HumL]
                ;---------------------------------------------------------------

CmdReadData
                SWAP_TO_BANK1

                movlw   0x02
                xorwf   tzn_rxdata,W
                btfss   STATUS,Z
                goto    _CmdReadData

                SWAP_TO_BANK0
                movf    TempH,W
                SWAP_TO_BANK1
                movwf   tzn_txdata+0

                SWAP_TO_BANK0
                movf    TempL,W
                SWAP_TO_BANK1
                movwf   tzn_txdata+1

                SWAP_TO_BANK0
                movf    HumH,W
                SWAP_TO_BANK1
                movwf   tzn_txdata+2

                SWAP_TO_BANK0
                movf    HumL,W
                SWAP_TO_BANK1
                movwf   tzn_txdata+3

                movlw   4
                movwf   txNDB

                ;Attende prima di trasmettere la risposta

                SWAP_TO_BANK0
                movlw   10
                call    msDelay
                SWAP_TO_BANK1

                SWAP_TO_BANK0
                bsf     LED_ROSSO
                call    SendPacket

                SWAP_TO_BANK1

                INIT_RX
                goto    _endCheckPacket
_CmdReadData


_endCheckPacket
                ;Spegne il led rosso

                SWAP_TO_BANK0
                movlw   MAXPOLLINGDELAY
                movwf   pollAllarm
                bcf     LED_ROSSO
_check_rx_buffer



                ;**********************************************************************
                ; Lettura a ciclo continuo dei dati dal sensore SHTxx
               ;**********************************************************************
ReadFromSHT71
                SWAP_TO_BANK0

                movf    ReadDelay,W
                btfss   STATUS,Z
                goto    _ReadFromSHT71

                btfss   UTToggle,0
                goto    ReadTempFromSHT71
                goto    ReadUmidFromSHT71

ReadTempFromSHT71
                bsf     UTToggle,0
                call    ReadTemperature
                goto    _ReadFromSHT71

ReadUmidFromSHT71
                bcf     UTToggle,0
                call    ReadHumidity
                goto    _ReadFromSHT71

_ReadFromSHT71
                incf  ReadDelay,F

                goto    MainLoop


                ;**********************************************************************
                ; Interrupt handler
                ;**********************************************************************

Interrupt_handler

                ;Save the registers

                MOVWF   W_TEMP                  ;Copy W to TEMP register, could be bank one or zero
                SWAPF   STATUS,W                ;Swap STATUS to be saved into W
                CLRF    STATUS                  ;bank 0, regardless of current bank, Clears IRP,RP1,RP0
                MOVWF   STATUS_TEMP             ;Save status to bank zero STATUS_TEMP register
                MOVF    PCLATH, W               ;Only required if using pages 1, 2 and/or 3
                MOVWF   PCLATH_TEMP             ;Save PCLATH into W
                CLRF    PCLATH                  ;Page zero, regardless of current page
                BCF     STATUS, IRP             ;Return to Bank 0
                MOVF    FSR, W                  ;Save FSR
                MOVWF   FSR_TEMP

                clrf    STATUS                  ;Point to BANK 0

                ;Check interrupt source and call its own handler

                btfsc   PIR1,RCIF               ;Check for USART rx char interrupt
                goto    USART_RCIF_Handler

                btfsc   INTCON,T0IF             ;Check for TMR0 overflow interrupt
                goto    TMR0_T0IF_Handler

                btfsc   PIR1,TMR1IF             ;Check for TIMER1 interrupt
                goto    TMR1IF_Handler

_Interrupt_handler

                ;Restore the registers and return from the interrupt

                SWAP_TO_BANK0

                MOVF    FSR_TEMP, W             ;Restore FSR
                MOVWF   FSR
                MOVF    PCLATH_TEMP, W          ;Restore PCLATH
                MOVWF   PCLATH
                SWAPF   STATUS_TEMP,W           ;Swap STATUS_TEMP register into W
                                                ;(sets bank to original state)
                MOVWF   STATUS                  ;Move W into STATUS register
                SWAPF   W_TEMP,F                ;Swap W_TEMP
                SWAPF   W_TEMP,W                ;Swap W_TEMP into W
                retfie

                ;**********************************************************************
                ; USART rx char interrupt
                ;**********************************************************************

USART_RCIF_Handler
                movf    RCREG,W                         ;Save the byte received
                SWAP_TO_BANK1
                movwf   RxIncomingChar

                ;**********************************************************************
                ; Check for the rx buffer status
                ;**********************************************************************

                btfsc   tzn_rxb_flag,RX_DATA_READY      ;Does the buffer already contains any good data ?
                goto    _USART_RCIF_Handler             ;Yes, exit and lost the byte received
                                                        ;No, continue

                bsf     tzn_rxb_flag,RX_FLOW_ON         ;Segnala la presenza di un flusso di dati in ricezione
                                                        ;(Questo flag viene azzerato su timeout)

                ;**********************************************************************
                ; Check for SNAP_SYNC char
                ;**********************************************************************
CheckSYNC
                btfsc   tzn_rxp_flag,RX_SYNC            ;Is the SYNC byte already received ?
                goto    _CheckSYNC                      ;Yes, continue
                                                        ;No, check if a SYNC character is incoming

                movlw   SNAP_SYNC                       ;Is the byte received a SYNC ?
                xorwf   RxIncomingChar,W
                btfss   STATUS,Z
                goto    _USART_RCIF_Handler             ;No, it should be a preamble char or anything else then trash
                                                        ;the byte received

                bsf     tzn_rxp_flag,RX_SYNC            ;Yes, set RX_SYNC flag and exit

                clrf    RxToutTimer                     ;Reset Rx timeout

                goto    _USART_RCIF_Handler             ;Exit from interrupt handler

_CheckSYNC

                ;**********************************************************************
                ; Checks for HDB2 char
                ;**********************************************************************
CheckHDB2
                btfsc   tzn_rxp_flag,RX_HDB2            ;Is the HDB2 byte already received ?
                goto    _CheckHDB2                      ;Yes, continue

                movf    RxIncomingChar,W                ;Is DAB=01B and SAB=01B and PDB=00 ?
                andlw   11111100B
                movwf   rxDummyCounter
                movlw   01010000B
                xorwf   rxDummyCounter,W
                btfss   STATUS,Z
                goto    ResetRxSession                  ;No, Reset Rx session and exit

                ;Reset CRC16 fields

                clrf    RxCRC_Low
                clrf    RxCRC_High

                ;Calculate CRC16

                movf    RxIncomingChar,W
                call    CalcRxCRC

                ;!!! Inserire qui il codice per sapere se e' richiesto o meno l'ACK !!!

                bsf     tzn_rxp_flag,RX_HDB2            ;Yes, set RX_HDB2 flag
                clrf    RxToutTimer                     ;Reset Rx timeout
                goto    _USART_RCIF_Handler             ;Exit from interrupt handler
_CheckHDB2

                ;**********************************************************************
                ; Checks for HDB1 char
                ;**********************************************************************
CheckHDB1
                btfsc   tzn_rxp_flag,RX_HDB1            ;Is the HDB1 byte already received ?
                goto    _CheckHDB1                      ;Yes, continue

                movf    RxIncomingChar,W                ;Is C=0B and EDM=100 ?
                andlw   11110000B
                movwf   rxDummyCounter
                movlw   01000000B
                xorwf   rxDummyCounter,W
                btfss   STATUS,Z
                goto    ResetRxSession                  ;No, reset the rx session and exit

                movf    RxIncomingChar,W                ;Read the NDB field (Number of Data Bytes)
                andlw   00001111B
                movwf   RxNDB

                ;Calculate CRC16

                movf    RxIncomingChar,W
                call    CalcRxCRC

                bsf     tzn_rxp_flag,RX_HDB1            ;Yes, set RX_HDB1 flag
                clrf    RxToutTimer                     ;Reset Rx timeout
                goto    _USART_RCIF_Handler             ;Exit from interrupt handler
_CheckHDB1

                ;**********************************************************************
                ; Checks for DAB1 char (Destination Address Byte)
                ;**********************************************************************
CheckDAB1
                btfsc   tzn_rxp_flag,RX_DAB1            ;Is the DAB1 byte already received ?
                goto    _CheckDAB1                      ;Yes, continue

                ;Legge i dip switch esterni se richiesto

#ifdef          EX_ADDR_ENABLED

                SWAP_TO_BANK0
                swapf   PORTB,W
                andlw   0x0F
                iorlw   MY_ADDR
                SWAP_TO_BANK1
#else
                movlw   MY_ADDR                         ;Is DAB1 = My address ?
#endif

                xorwf   RxIncomingChar,W
                btfss   STATUS,Z
                goto    ResetRxSession                  ;No, Reset Rx session and exit

                ;Calculate CRC16

                movf    RxIncomingChar,W
                call    CalcRxCRC

                bsf     tzn_rxp_flag,RX_DAB1            ;Yes, set RX_DAB1 flag
                clrf    RxToutTimer                     ;Reset Rx timeout
                goto    _USART_RCIF_Handler             ;Exit from interrupt handler
_CheckDAB1

                ;**********************************************************************
                ; Read and save SAB1 (Source Address Byte)
                ;**********************************************************************
CheckSAB1
                btfsc   tzn_rxp_flag,RX_SAB1            ;Is the SAB1 byte already received ?
                goto    _CheckSAB1                      ;Yes, continue

                ;Inserire qui il codice per leggere il nodo che ha trasmesso il pacchetto

                ;Calculate CRC16

                movf    RxIncomingChar,W
                call    CalcRxCRC

                bsf     tzn_rxp_flag,RX_SAB1            ;Yes, set RX_SAB1 flag

                clrf    RxDataCounter                   ;Clear rx chars counter
                movlw   tzn_rxdata                      ;Init rx buffer write pointer
                movwf   RxWritePointer

                clrf    RxToutTimer                     ;Reset Rx timeout

                goto    _USART_RCIF_Handler             ;Exit from interrupt handler
_CheckSAB1

                ;**********************************************************************
                ; Save the data bytes
                ;**********************************************************************

CheckDB
                btfsc   tzn_rxp_flag,RX_DB              ;Are the user data already received ?
                goto    _CheckDB                        ;Yes, continue

                incf    RxDataCounter,F                 ;Increments data counter

                ; Save the data received in the RxBuffer

                movf    RxWritePointer,W                ;FSR = rx buffer write pointer
                movwf   FSR

                ;Calculate CRC16

                movf    RxIncomingChar,W
                call    CalcRxCRC

                movf    RxIncomingChar,W
                movwf   INDF                            ;Save rx character in tzn_rxbuffer
                incf    RxWritePointer,F

                ; Check if is the last data byte

                movf    RxNDB,W                         ;Is the NDB field (on the packet header) equals to the current rx data counter ?
                xorwf   RxDataCounter,W
                btfsc   STATUS,Z
                bsf     tzn_rxp_flag,RX_DB              ;Yes, set RX_DB flag

                clrf    RxToutTimer                     ;Reset Rx timeout

                goto    _USART_RCIF_Handler             ;Exit from interrupt handler
_CheckDB

                ;**********************************************************************
                ; Checks for CRC2 char
                ;**********************************************************************
CheckCRC2
                btfsc   tzn_rxp_flag,RX_CRC2            ;Is the CRC2 byte already received ?
                goto    _CheckCRC2                      ;Yes, continue

                movf    RxIncomingChar,W
                movwf   RxCRC2

                bsf     tzn_rxp_flag,RX_CRC2            ;Yes, set RX_CRC2 flag

                clrf    RxToutTimer                     ;Reset Rx timeout

                goto    _USART_RCIF_Handler             ;Exit from interrupt handler
_CheckCRC2

                ;**********************************************************************
                ; Checks for CRC1 char
                ;**********************************************************************
CheckCRC1
                movf    RxIncomingChar,W
                movwf   RxCRC1

                ;Compare the CRC16 received with the CRC16 calculated

                movf    RxCRC_High,W
                xorwf   RxCRC2,W
                btfss   STATUS,Z
                goto    ResetRxSession                  ;No, Reset Rx session and exit

                movf    RxCRC_Low,W
                xorwf   RxCRC1,W
                btfss   STATUS,Z
                goto    ResetRxSession                  ;No, Reset Rx session and exit


                ;Packet ready !!!

                bsf     tzn_rxb_flag,RX_DATA_READY      ;Received buffer now is ready with valid data
                goto    _USART_RCIF_Handler             ;Exit from interrupt handler
_CheckCRC1


ResetRxSession
                INIT_RX

_USART_RCIF_Handler
                goto    _Interrupt_handler


                ;**********************************************************************
                ; TMR0 overflow interrupt handler
                ; This routine is calling each 1/2 millisecond and checks and updates
                ; all the system timer
                ;**********************************************************************

TMR0_T0IF_Handler

                ;**********************************************************************
                ; TMR0 TASK1
                ; Re-enables TMR0 interrupt and reload TMR0 register
                ;**********************************************************************

tmr0_task_1

                SWAP_TO_BANK1
                bcf     INTCON,T0IF             ;Re-enables TMR0 interrupt

                SWAP_TO_BANK0
                movlw   6                       ;Reload TMR0 register
                movwf   TMR0
_tmr0_task_1

                ;**********************************************************************
                ; TMR0 TASK2
                ; Update system timer
                ;**********************************************************************
tmr0_task_2

                SWAP_TO_BANK0
                incf    msDelayTimer,F

UpdateSysTimer
                SWAP_TO_BANK1
                incf    sysTimer0L,F
                btfsc   STATUS,Z

                incf    sysTimer0H,F

                movf    sysTimer0L,W
                xorlw   0xE8
                btfss   STATUS,Z
                goto    _UpdateSysTimer

                movf    sysTimer0H,W
                xorlw   0x03
                btfss   STATUS,Z
                goto    _UpdateSysTimer

                clrf    sysTimer0L
                clrf    sysTimer0H

                movf    inputTimer,W
                btfss   STATUS,Z
                decf    inputTimer,F

_UpdateSysTimer

_tmr0_task_2

                ;**********************************************************************
                ; TMR0 TASK3
                ; Check timeout on rx to close rx data flow
                ;**********************************************************************

tmr0_task_3
                btfsc   tzn_rxb_flag,RX_DATA_READY      ;RX_DATA_READY ?
                goto    _tmr0_task_3                    ;Yes, exit

                btfss   tzn_rxb_flag,RX_FLOW_ON         ;RX_FLOW_ON ?
                goto    _tmr0_task_3                    ;No, exit

                incf    RxToutTimer,F

                movlw   RX_TIMEOUT                      ;Timeout ?
                xorwf   RxToutTimer,W
                btfss   STATUS,Z
                goto    _tmr0_task_3                    ;No, exit

                INIT_RX                                 ;Yes, reset the rx section for timeout
_tmr0_task_3

                SWAP_TO_BANK0

                ;**********************************************************************
                ; TMR0 TASK5
                ; Flash test led
                ;**********************************************************************

tmr0_task_5
                SWAP_TO_BANK1

                incf    TestLedCounter+0,F

                movlw   200                             ;10 ms ?
                xorwf   TestLedCounter+0,W
                btfss   STATUS,Z
                goto    _tmr0_task_5                    ;No, exit

                clrf    TestLedCounter+0

                incf    TestLedCounter+1,F              ;Yes

                movlw   10                              ;1 sec ?
                xorwf   TestLedCounter+1,W
                btfss   STATUS,Z
                goto    _tmr0_task_5                    ;No, exit

                clrf    TestLedCounter+1                ;Yes, flash test led

                SWAP_TO_BANK0

                decfsz  pollAllarm,F                    ;Accende il led rosso se il polling
                goto    noPollAllarm
                bcf     LED_ROSSO                 			;non arriva dopo n secondi
noPollAllarm

                btfsc   LED_VERDE                 ;Toggle del led verde
                goto    _testled_off
                goto    _testled_on

_testled_off
                bcf     LED_VERDE
                goto    _tmr0_task_5

_testled_on
                bsf     LED_VERDE
                goto    _tmr0_task_5
_tmr0_task_5


                

                SWAP_TO_BANK0
                goto    _Interrupt_handler              ;Exit from interrupt handler


                ;**********************************************************************
                ; TMR1IF interrupt handler
                ; Non utilizzato
                ;**********************************************************************

TMR1IF_Handler

                SWAP_TO_BANK0
                bcf     PIR1,0          ;Reset TIMER1 interrupt flag
_TMR1IF_Handler
                goto    _Interrupt_handler

                ;**********************************************************************
                ; Delay of W ms (uses TMR0 interrupt)
                ;**********************************************************************

msDelay
                movwf   msDelayTmp
                clrf    msDelayTimer
msDelayLoop
                movf    msDelayTimer,W
                xorwf   msDelayTmp,W
                btfss   STATUS,Z
                goto    msDelayLoop

                return

                ;**********************************************************************
                ; CRC16 calculator for interrupt handler routine
                ; Thanks to Frank Vorstenbosch author of this routine
                ;**********************************************************************

CalcRxCRC
                SWAP_TO_BANK1

                movwf   RxCRC_Temp
                movlw   8
                movwf   RxCRC_Count
RxCRC_Loop
                movf    RxCRC_Low,W
                xorwf   RxCRC_Temp,W
                clrc
                rrf     RxCRC_High,F
                rrf     RxCRC_Low,F
                andlw   1
                bz      RxCRC_Skip

                movlw   0xA0
                xorwf   RxCRC_High,F
                movlw   0x01
                xorwf   RxCRC_Low,F

RxCRC_Skip
                rrf     RxCRC_Temp,F

                decfsz  RxCRC_Count,F
                goto    RxCRC_Loop

                return

                ;**********************************************************************
                ; CRC16 calculator for non interrupt handler routine
                ; Thanks to Frank Vorstenbosch author of this routine
                ;**********************************************************************

CalcTxCRC
                SWAP_TO_BANK1

                movwf   TxCRC_Temp
                movlw   8
                movwf   TxCRC_Count
TxCRC_Loop
                movf    TxCRC_Low,W
                xorwf   TxCRC_Temp,W
                clrc
                rrf     TxCRC_High,F
                rrf     TxCRC_Low,F
                andlw   1
                bz      TxCRC_Skip

                movlw   0xA0
                xorwf   TxCRC_High,F
                movlw   0x01
                xorwf   TxCRC_Low,F

TxCRC_Skip
                rrf     TxCRC_Temp,F

                decfsz  TxCRC_Count,F
                goto    TxCRC_Loop

                return

                ;**********************************************************************
                ; Send a SNAP packet to the Master node
                ;----------------------------------------------------------------------
                ; Input parameters:
                ;
                ;   MY_ADDR     = My address
                ;   MASTER_ADDR = Target address
                ;
                ;   txNDB = Number of Data Bit
                ;**********************************************************************

SendPacket
                SWAP_TO_BANK0

                bcf     INTCON,GIE        ;Disables Global Interrupt
                bsf     COM_DE			      ;Enable RS485 driver

                ;Assemble the frame header

                SWAP_TO_BANK1

                movlw   01010000B         ;HDB2
                movwf   tzn_txheader+0

                movlw   01000000B         ;HDB1
                movwf   tzn_txheader+1

                movf    txNDB,W
                iorwf   tzn_txheader+1,F  ;Inserisce in HDB1 il campo NDB (Number on Data Bytes)

                movlw   MASTER_ADDR       ;DAB1
                movwf   tzn_txheader+2

#ifdef          EX_ADDR_ENABLED

                SWAP_TO_BANK0
                swapf   PORTB,W
                andlw   0x0F
                iorlw   MY_ADDR
                SWAP_TO_BANK1
#else
                movlw   MY_ADDR
#endif
                movwf   tzn_txheader+3

                ;************************************************
                ;  Send frame
                ;************************************************

                ;Send preamble bytes

                SWAP_TO_BANK1

                clrf    TxCRC_High
                clrf    TxCRC_Low

                movlw   SNAP_SYNC
                call    SendByte

                movlw   SNAP_SYNC
                call    SendByte

                ;Send frame header

                SWAP_TO_BANK1

                movlw   4
                movwf   txDummyCounter

                movlw   tzn_txheader
                movwf   FSR
_TxHeaderLoop
                movf    INDF,W
                call    SendByte

                movf    INDF,W
                call    CalcTxCRC

                incf    FSR,F
                decfsz  txDummyCounter,F
                goto    _TxHeaderLoop

                ;Send data byte

                SWAP_TO_BANK1

                movf    txNDB,W
                movwf   txDummyCounter

                movlw   tzn_txdata
                movwf   FSR
_TxDataLoop
                movf    INDF,W
                call    SendByte

                movf    INDF,W
                call    CalcTxCRC

                incf    FSR,F
                decfsz  txDummyCounter,F
                goto    _TxDataLoop

                ;Send CRC16 byte

                SWAP_TO_BANK1

                movf    TxCRC_High,W
                movwf   tzn_txcrc+0

                movf    TxCRC_Low,W
                movwf   tzn_txcrc+1

                movlw   2
                movwf   txDummyCounter

                movlw   tzn_txcrc
                movwf   FSR
_TxCrcLoop
                movf    INDF,W
                call    SendByte
                incf    FSR,F

                decfsz  txDummyCounter,F
                goto    _TxCrcLoop

                SWAP_TO_BANK0
                bcf     COM_DE  			            ;Disable RS485 driver

                movf    RCREG,W                         ;Clear USART RX buffer
                movf    RCREG,W

                bsf     INTCON,GIE                      ;Enables Global Interrupt

                SWAP_TO_BANK1
                bsf     PIE1,RCIE                       ;Enable the USART to receive interrupt

                SWAP_TO_BANK0
                return

                ;*************************************************
                ; Send a byte to RS485 line
                ;
                ; Input parameters:
                ;
                ;   W = Byte to send
                ;
                ;   Note: The RS485 drive enable must be on
                ;         The receiver interrupt must be disabled
                ;*************************************************

SendByte
                SWAP_TO_BANK0
                movwf   TXREG           ;Move the byte to send in the UART's TX register

                SWAP_TO_BANK1
WaitTxStopBit
                btfss   TXSTA,TRMT      ;Wait until the stop bit is finished
                goto    WaitTxStopBit

                ;Questo ritardo serve per aspettare che effettivamente sia passato tutto
                ;lo stop bit sulla linea RS485. Il bit TRMT del registro TXSTA infatti indica
                ;solo che e' iniziata la trasmissione dello stop bit e non che questa sia finita

                ONE_BIT_DELAY

                return

                END
