;**********************************************************************
;                Something to do with a PIC                           *
;**********************************************************************
;                                                                     *
;    Filename:          carlcdv2.asm                                  *
;    Date:              xx - xx - 2001                                *
;    File Version:      0.1B                                          *
;                                                                     *
;    Author:            Tim Thompson                                  *
;    Company:           www.irule.net                                 *
;                                                                     * 
;                                                                     *
;**********************************************************************
;                                                                     *
;    Files required:                                                  *
;                                                                     *
;                                                                     *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Notes:                                                           *
;                                                                     *
;*********************************************************************
        list P=16F877            ; list directive to define processor
				; turn off crossing page boundary message
;        ERRORLEVEL -302


;        __CONFIG _CP_OFF & _WDT_OFF & _BODEN_ON & _PWRTE_ON & _HS_OSC & _WRT_ENABLE_ON & _LVP_OFF & _DEBUG_OFF & _CPD_OFF 

; '__CONFIG' directive is used to embed configuration data within .asm file.
; The lables following the directive are located in the respective .inc file.
; See respective data sheet for additional information on configuration word.
; However not used since we use a boot loader
 
 include "p16f877.inc"        ; processor specific variable definitions
 
 include "fifo.asm" 
 include "carlcd.h"
 include "bank.mac"
 include "jump.mac"
 include "int.mac"
 include "wait.mac"
 
;**********************************************************************
        ORG     h'0003'		; processor reset vector
        GOTO    INIT		; go to initialisation of program

;**************** Interrupt service routine **************************


	ORG     h'0004'             ; interrupt vector location
	PUSH    ; save registers
INT
        ; Interrupt code

INT_TEST_IRQ
;	BTFSS   INTCON,INTF     ; test if external irq
;	GOTO    INT_TEST_RX_IRQ ; nope check next
;	; ad irq
;	call   IRQ_INT_HANDLER ; dummy
;	BCF     INTCON,INTF     ; clear int pin flag

INT_TEST_RX_IRQ
	BTFSS   PIR1,RCIF       ; test if serial recive irq
	GOTO    INT_TEST_TX_IRQ ; nope check next
	movlw	PIE1
	movwf	FSR
	BTFSS	INDF, RCIE	; test if irq is enabled
	GOTO	INT_TEST_TX_IRQ

	; rx irq
	call	RX_INT_HANDLER  ; Handle the data
	BCF     PIR1,RCIF       ; clear rx int flag

INT_TEST_TX_IRQ
	BTFSS   PIR1,TXIF       ; test if serial transmit irq
	GOTO    INT_TEST_TIMER0	; nope check next
	movlw	PIE1
	movwf	FSR
	BTFSS	INDF, TXIE	; test if irq is enabled
	GOTO	INT_TEST_TIMER0 ; nope check next

	; tx irq
	call	TX_INT_HANDLER	; Handle the data
	BCF     PIR1,TXIF       ; clear tx int flag

INT_TEST_TIMER0
	BTFSS	INTCON, T0IE		; Test if interrupt is enabled
	goto	INT_EXIT		; Nope
	BTFSS	INTCON, T0IF		; Test for interupt itself
	goto	INT_EXIT		; Nope

	; tmr0 irq
	bcf	INTCON, T0IF		; Clear int flag
	clrf	TMR0			; Reset timer	

	; Update LED display
	btfsc	SYS_OPTS, SOPT_OK2I2C	; See if its OK to do so..
	call	write_leds

	; Check for beeper 'a beepin
	movf	Piezo_Cntr, F		; We a'beepin?
	btfsc	STATUS, Z
	goto	INT_TEST_TIMER0_REST	; Nope.

	; Yes we makin sum' noise!
	decf	Piezo_Cntr, F
	btfsc	STATUS, Z
	bcf	T2CON, 2		; Counter at zero, turn off PWM


INT_TEST_TIMER0_REST
	; OK test if were connected, if not do an animated '...'
	; Every second or so the "." becomes ".." becomes "...", etc,  back to "."
	; untill we connect.
	btfsc	SYS_OPTS, SOPT_CONNECTED
	goto INT_EXIT
	; OK everything down here is hit when idle...
	LONG_CALL	init_do_wait
	; Do time/date crap
	LONG_CALL	rtc_show_time	

; Do temperature crap

	LONG_CALL	read_temp		; Get temp data

	LCD_MOV 2,12

	movf	Local_TempMSB, W
;	LONG_CALL cel_to_feh		; Convert to temp F

	LONG_CALL ByteToASCII
	movlw	'F'
	LONG_CALL lcd_put_char
	
INT_EXIT
	PULL    ; restore registers
	RETFIE  ; return from interrupt


;*************** end int routine *************************************


second
	Wait	30 Millisec, 0
	Wait	30 Millisec, 0
	Wait	30 Millisec, 0
	Wait	30 Millisec, 0
	Wait	30 Millisec, 0
	Wait	10 Millisec, 0
	return

; ***********************************************************************
; INIT - Cold start vector, called at startup
; 
; initilaize all ports to known state before setup routines are called
;
INIT
	DISABLE_IRQ
        ; pclath and status is already cleared !
        ; before entering this init routine
	; NOT -IRule
        CLRF	SSPCON
        CLRF    INTCON		; ensure int reg is clear  
        CLRF    PIR1		; clear periphial irq's
        CLRF    PIR2		; ditto
        
        ; make sure all individual irq's are disabled
        MOVLW   PIE1		; get adress for periphial irq enable
        MOVWF   FSR		; setup fsr
        CLRF    INDF		; and clear irq enable flags

        MOVLW   PIE2		; get adress for second periphial irq enable
        MOVWF   FSR		; setup fsr
        CLRF    INDF		; and clear irq enable flags

        ; note porta as is set as ANALOGUE i/o as default
        ; clear output data latches
        CLRF	PORTA
        CLRF    PORTB
	movlw	b'00100000'	; Make sure power pin is high
	movwf	PORTC
;        CLRF    PORTC
	CLRF	PORTD
	CLRF	PORTE
	
        ; call initialize routines for periphials/ports
        ; note must be at bank0 during initializing

        ; NOTE ! DO NOT CHANGE ORDER OF THESE ROUTINES !!

        ; clear all user ram ( set to all 0's )
	call      CLEAR_RAM
        ; setup our ports to in/out/analogue/rx/tx/spi/etc
        ; must be done before calling any other INIT_XXX routine
        ; as most of them depends on pin settings       
	call      INIT_PORTS      
	; setup uart
	call      INIT_UART
	; setup I2C
	call      INIT_I2C
	; clear system opts register
	clrf	SYS_OPTS

	Bank0
;	POWER_ON			; Make sure we stay alive!
	RESET_ON			; Reset any external crap such as LCD controller
	nop
	nop
	RESET_OFF

;	fifo_define f_but_fifo, 10

	fifo_init f_but_fifo

	bsf	FAN_CTRL		; Turn OFF fan.

	call	lcd_contrast_rst	; reset contrast chip

	bsf	LCD_BIAS_CTRL		; Turn on BIAS generator

	movlw	d'13'			; Set LCD contrast
	call	lcd_contrast_adj

	call	init_lcd		; Setup and initilize the LCD controller
	call	lcd_clear_text		; Yup.

	call	init_send_beeper	; Send initing beeper message
	; setup pizeo
	call	init_piezo
	call	init_send_done

	call	init_send_timer
	; Setup timer0
	bsf	INTCON, T0IE		; Enable timer0
	clrf	TMR0			; Clear it
	call	init_send_done

	call	init_send_temp
	; Setup Various Other Crap(tm)
	call	init_temp		; Start temp chip a tempin'
	call	init_send_done

	call	init_send_serial
 	call	INIT_BUFFERS		; Init the serial buffers
	call	init_send_done

	; all pins/periphials configured
	movf	PORTB, W
	bcf	INTCON, RBIF

	movlw	'R'
	call	lcd_put_char
	movlw	'T'
	call	lcd_put_char
	movlw	'C'
	call	lcd_put_char
	movlw	':'
	call	lcd_put_char
	movlw	' '
	call	lcd_put_char
	
	call	rtc_init		; Make RTC 12hr and enabled.

	movlw	'D'
	call	lcd_put_char
	movlw	'o'
	call	lcd_put_char
	movlw	'n'
	call	lcd_put_char
	movlw	'e'
	call	lcd_put_char

	call	led_fun			; Do that lil' thang we do


	; OK lets begin shall we?

	call	init_send_ready
	call	second
	call	second

;***
; Display da logo
; and "Waiting" crap..
;***
	call	lcd_clear_graphic	; Blank the display
	call	lcd_clear_text		; Clear text aswell..
	movlw	DISPLAY_OFF		; Turn the display off initialy, to mask slow loading of logo... :)
	movwf	COMMANDBUF
	call	lcd_send_cmd

; OK this will load the logo from the beginning of the i2c EEPROM.
; Working. Yay.
	LONG_CALL	display_logo

	movlw	(GRAPHIC_ON | TEXT_ON)	; Turn on text and graphics
	movwf	COMMANDBUF
	call	lcd_send_cmd

	LCD_MOV 2, 21

	movlw	'W'
	call	lcd_put_char
	movlw	'a'
	call	lcd_put_char
	movlw	'i'
	call	lcd_put_char
	movlw	't'
	call	lcd_put_char
	movlw	'i'
	call	lcd_put_char
	movlw	'n'
	call	lcd_put_char
	movlw	'g'
	call	lcd_put_char
	movlw	'.'


	movlw	WAITING_DELAY
	movwf	logo_txt_cntr

	ENABLE_IRQ
	bsf	SYS_OPTS, SOPT_OK2I2C
	bcf	LED_PWR
	call	beep			; Make annoyance

;****************************************;
;*           Main Loop Here             *;
;****************************************;
MAIN_LOOP
        ; main loop

        ; test for specific events

	call	RX_GET_BUFFER		; Data ready?
	btfsc	STATUS, Z		; Test..
	goto	MAIN_DONE		; Nope.

	; OK we got something. Parse it!

	btfss	SYS_OPTS, SOPT_CONNECTED
	call	got_connect

	bcf	LED_ACT
	call	check_cmds
	bsf	LED_ACT

MAIN_DONE
	btfss	INTCON, RBIF		; Interupt?
	goto	MAIN_LOOP

	movf	PORTB, W
	bcf	INTCON, RBIF

	; Now read the button states
;	DISABLE_IRQ
;	bcf	INTCON, TMR0
	bcf	SYS_OPTS, SOPT_OK2I2C
	call	read_funct_buts		; Read buttons
	bsf	SYS_OPTS, SOPT_OK2I2C
;	bsf	INTCON, TMR0
;	ENABLE_IRQ

	movf	FBut_State, W		; backup state
	movwf	tmp_main

	Wait	30 Millisec, 0
	Wait	30 Millisec, 0
	Wait	30 Millisec, 0

;	DISABLE_IRQ
;	bcf	INTCON, TMR0
	bcf	SYS_OPTS, SOPT_OK2I2C
	call	read_funct_buts		; Read again
	bsf	SYS_OPTS, SOPT_OK2I2C
;	bsf	INTCON, TMR0
;	ENABLE_IRQ

	movf	FBut_State
	subwf	tmp_main, W		; Compare them
	btfss	STATUS, Z
	goto MAIN_LOOP			; If same, then debounced, if not, bad read


	fifo_skip_nfull f_but_fifo, 7	; Skip everything if the fifo is full
	goto	MAIN_LOOP

	movf	FBut_State, W		; get current state
	movwf	tmp_int
	comf	tmp_int, F		; Is it zero?
	movf	tmp_int, F
	skpnz
	goto	MAIN_LOOP		; Yup. no buttons down

;	call	beep			; Keypress beeps

;	bsf	SYS_OPTS, SOPT_BUTDN

	movf	tmp_int, W
	movwf	FBut_State

	fifo_skip_full f_but_fifo, 7
	fifo_put f_but_fifo, 7, tmp_int

        ; and return to main loop
        GOTO    MAIN_LOOP


got_connect
	bsf	SYS_OPTS, SOPT_CONNECTED ; OK got initial packet, clear display!
	call	lcd_clear_graphic
	call	lcd_clear_text

	movlw	TEXT_ON			; Turn on text only
	movwf	COMMANDBUF
	call	lcd_send_cmd
	return



; ***********************************************************************
;
;  INIT_PORTS - Initialises all ports on the PIC
;  i.e sets the pins as in/out/analog/etc
;  Make sure to be at bank0

INIT_PORTS
        ; setup PORTA 
        ; set all porta pins digital
        MOVLW   ADCON1			; get adress for ad/module config1 reg
        MOVWF   FSR			; setup fsr
	MOVLW	b'00000111'		; All digital I/O
        MOVWF   INDF			; and store it

        ; shutoff ad/module
        MOVLW   ADCON0			; get adress for ad/module config reg
        MOVWF   FSR			; setup fsr
	CLRF	INDF			; Disable A/D

	; set in/out for port pins
	MOVLW   TRISA			; get adress for port control reg
	MOVWF   FSR			; setup fsr
	MOVLW   b'00000000'		;
	MOVWF   INDF			; and set it

	MOVLW	PORTA			; Turn all LCD controll lines high
	MOVWF	FSR
	bsf	INDF, 3
	bsf	INDF, 2
	bsf	INDF, 1
	bsf	INDF, 0

	; set in/out for port pins
	MOVLW   TRISB			; get adress for port control reg
	MOVWF   FSR			; setup fsr
	MOVLW   b'11110000'		; 7 for FBut interupt.

	MOVWF   INDF			; and set it

        ; setup PORTC
        ; note PORTC must be setup properly when using SPI/UART/CCP/TIMER
        ; look in data sheet, some setups are 'unlogical' and/or overridden
        ; as TX pin configured as input etc.

        ; set in/out for portc pins
        MOVLW   TRISC			; get adress for portc control reg
        MOVWF   FSR			; setup fsr        
        MOVLW   b'11011000'		; 7-6 for uart must be set 
                           		; 4-3 for i2c must be set for master mode.
                           		; 1-2 is for CCP module, 0 is for timer inp.
        MOVWF   INDF    ; and set it

	MOVLW	TRISE			; Setup TRIS as outputs
	MOVWF	FSR
	MOVLW	b'00000000'		; PORTE
	MOVWF	INDF

        ; setup OPTION reg
        
        MOVLW   OPTION_REG; get adress for option reg
        MOVWF   FSR     ; setup fsr
        MOVLW   b'01000110'		; pull up portb by latch, int edge falling,TMR0 source internal
                                	; TMR0 source edge inc on low->high, prescaler to Timer0, TMR0 rate 1:2
        MOVWF   INDF    ; and set it

	BcF	INTCON, RBIE
        RETURN

        
; ***********************************************************************
;
;  INIT_UART - Initialises UART
;  enables recevier and transmitter
;  Make sure to be at bank0

INIT_UART
        ; make sure pins are setup before calling this routine
        ; TRISC:6 and TRISC:7 must be set ( as for output, but operates as input/output )
        ; furthermore its advised that interrupts are disabled during this routine
        
        ; setup baudrate
        MOVLW   SPBRG			; get adress for serial baud reg
        MOVWF   FSR			; setup fsr
        MOVLW   CALC_HIGH_BAUD(BAUD_RATE) ; get baudrate
        MOVWF   INDF			; and store it

        ; enable transmitter
        MOVLW   TXSTA			; get adress for serial enable reg
        MOVWF   FSR			; setup fsr
        MOVLW   (1<<TXEN)|(1<<BRGH)	; preset enable transmitter and high speed mode
        MOVWF   INDF			; and set it

        ; enable recevier
        MOVLW   (1<<SPEN)|(1<<CREN)	; preset serial port enable and continous recevie
        MOVWF   RCSTA			; set it

        ; enable reciever interrupt
        MOVLW   PIE1			; get adress for periphial irq's
        MOVWF   FSR			; setup fsr
        BSF     INDF,RCIE		; enable reciever irq
        BSF     INTCON,PEIE		; and periphial irq must also be enabled

	movf	RCREG,W			; clear uart receiver
	movf	RCREG,W			; including fifo
	movf	RCREG,W			; which is three deep.

        RETURN

; ***********************************************************************
;
;  INIT_I2C - Initialises I2C, module, 100Khz, master mode, 
;  Make sure to be at bank0     

INIT_I2C
        ; make sure pins are setup before calling this routine

        ; setup MSSP adress register
        MOVLW   SSPADD			; get adress for synch serial port status reg
        MOVWF   FSR			; setup fsr
        MOVLW   I2C_ClockValue		; setup clock rate
        MOVWF   INDF			; and store it


        ; setup MSSP status reg
        MOVLW   SSPSTAT			; get adress for synch serial port status reg
        MOVWF   FSR			; setup fsr
        MOVLW   (1<<SMP) 		; enable slewrate control
        MOVWF   INDF			; and store it

        ; setup MSSP control reg
        MOVLW   SSPCON			; get adress for synch serial port control reg
        MOVWF   FSR			; setup fsr
        MOVLW   ((1<<SSPEN)|(1<<CKP)|(1<<SSPM3)); enable syncronous port, enable clock ,
                                                ; I2C master mode clock = OSC/(4*(SSPADD)+1)
        MOVWF   INDF			; and set it

        ; enable MSSP interrupt
        MOVLW   PIE1			; get adress for periphial irq's
        MOVWF   FSR			; setup fsr
        BCF     INDF,SSPIE		; enable MSSP irq
        BSF     INTCON,PEIE		; and periphial irq must also be enabled (if not already )
	Bank1
	BCF	PIE2, BCLIE
	Bank0
        RETURN


led_fun
	clrf	Led_Data
	call	write_leds
	call	second
	comf	Led_Data, F
	call	write_leds

	bcf	Led_Data, 0	; turn on LED 1
	bcf	Led_Data, 7	; and 8
	call	write_leds
	call	second

	bcf	Led_Data, 1	; turn on LED 2
	bcf	Led_Data, 6
	call	write_leds
	call	second

	bcf	Led_Data, 2	; turn on LED 3
	bcf	Led_Data, 5
	call	write_leds
	call	second

	bcf	Led_Data, 3	; turn on LED 4
	bcf	Led_Data, 4	; turn on LED 5
	call write_leds
	call	second


	clrf	Led_Data
	comf	Led_Data, F
	return



; ***********************************************************************
;
;  CLEAR_RAM - Reset all general purpose ram to 0's
;  Note ! does not clear watchdog, add CLRWDT where appropiate if enabled
;  Make sure to be at bank0

CLEAR_RAM
        MOVLW   0x20            ; start ram bank0
        MOVWF   FSR
CLEAR_BANK0     
        CLRF    INDF            ; Clear a register pointed to be FSR
        INCF    FSR,F
        MOVLW   0x7F            ; Test if at top of memory bank0
        SUBWF   FSR,W
        BNZ     CLEAR_BANK0     ; Loop until all cleared

        MOVLW   0xA0            ; start ram bank1
        MOVWF   FSR
CLEAR_BANK1     
        CLRF    INDF            ; Clear a register pointed to be FSR
        INCF    FSR,F
                
        ; note this could also be set to 0xFF or 0xEF as the top 16 bytes are mirrored from
        ; bank0

        MOVLW   0xEF            ; Test if at top of memory bank1
        SUBWF   FSR,W
        BNZ     CLEAR_BANK1     ; Loop until all cleared

        Bank2                   ; select bank2/3 ( with indirect adressing )

        MOVLW   0x10            ; start ram bank2
        MOVWF   FSR
CLEAR_BANK2     
        CLRF    INDF            ; Clear a register pointed to be FSR
        INCF    FSR,F
        
        ; note this could also be set to 0x7F or 0x70 as the top 16 bytes are mirrored from
        ; bank0
        MOVLW   0x70            ; Test if at top of memory bank2
        SUBWF   FSR,W
        BNZ     CLEAR_BANK2     ; Loop until all cleared

        MOVLW   0x90            ; start ram bank3
        MOVWF   FSR
CLEAR_BANK3     
        CLRF    INDF			; Clear a register pointed to be FSR
        INCF    FSR,F
        ; note this could also be set to 0xFF or 0xEF as the top 16 bytes are mirrored from
        ; bank0
        MOVLW   0xEF			; Test if at top of memory bank3
        SUBWF   FSR,W
        BNZ     CLEAR_BANK3		; Loop until all cleared
        
        Bank0				; set back to bank0

        RETURN

irq_stop
	BCF     INTCON,GIE		; disable global interrupt
	BTFSC   INTCON,GIE		; check if disabled 
	GOTO    irq_stop		; nope, try again
	return

irq_start
	BSF	INTCON, GIE
	return

 include "delay.asm"
 include "i2c.asm"
 include "pizeo.asm"
 include "serial.asm"
 include "t6963c.asm"
 include "commands.asm"
 include "initmsgs.asm"
 include "oututil.asm"
 include "MPY8X8.ASM"    ;multiply subroutine
 include "DIV8X8.ASM"    ;divide subroutine

; include "logo.asm"
        END				; directive 'end of program'

