;********************************************************************************
;*																				*
;* 					  				Dice Kit									*
;* 																				*
;********************************************************************************
;	Operation;
;
; 1. Reads a piezo strike to create random dice count, displayed on 7 leds 
;
;********************************************************************************
;
; Copyright SpikenzieLabs 2010, All rights reserved
; By: Mark Demers 



	list      p=12f675            ; list directive to define processor
	#include <p12f675.inc>        ; processor specific variable definitions

	errorlevel  -302              ; suppress message 302 from list file

	__CONFIG   _CP_OFF & _CPD_OFF & _BODEN_ON & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT


;*************************** 		MACROs 	   ********************************

LITELEDS macro LEDPATTERN	
	movlw	LEDPATTERN
	movwf	GPIO
	endm

MULTIPLY3 macro VALX				; result in W
	movlw	0x03
	movwf	TIMES

	movf	VALX,w
	movwf	SUM
	decf	SUM,f
	movf	SUM,w
	movwf	TEMPDICE

MULTIPLYLOOP:	
	decfsz	TIMES,f
	goto	MULTIPLYCONT
	movf	SUM,w
	goto	MULTIPLYEXIT

MULTIPLYCONT:
	movf	TEMPDICE,w
	addwf	SUM,f
	goto	MULTIPLYLOOP

MULTIPLYEXIT:
	endm

;*************************** DEFINE STATEMENTS ********************************

#define		OFFFLAG				FLAGVAR,0
#define		GOODREADFLAG		FLAGVAR,1
#define		SLEEPFLAG			FLAGVAR,3
#define		HITDEBOUNCEFLAG		FLAGVAR,4
#define		ANAREJECTFLAG		FLAGVAR,5	

;******************************************************************************		
;								VARIABLE DEFINITIONS 
;******************************************************************************
      cblock	0x20


; - General Variables
;	(8 Bit)
	DICE
	buffer
	onLEDoffset
	TIMES
	SUM
	TEMPDICE
	TEMP2

;	(16 bit)
	sleepycounter:2

;	(Boolean)
	FLAGVAR

; - Temp. INTERRUPT Variables
	WTEMP
	STATUSTEMP
	PCLATHTEMP
	FSRTEMP

      endc

;****************************** Start of Program ******************************
	org     0x000			; processor reset vector
	goto	Initialize

	org     0x004
	goto	INTERRUPT

;******************************************************************************
; Initialize      
;******************************************************************************
	org	0x005				; Start of Programm Memory Vector

Initialize

;******************************************************************************	
;							Comparator Init
;******************************************************************************

	bsf		CMCON,CM0			; Comparitors off
	bsf		CMCON,CM1
	bsf		CMCON,CM2

;******************************************************************************	
;								A2D Init
;******************************************************************************

	bsf     STATUS,RP0		; Bank 1 
	movlw	b'01010001'		; Channel 0  Analog input & Fosc/16 (for 4mhz)
	movwf	ANSEL		
	bcf     STATUS,RP0		; Bank 0

	movlw	b'10000001'		; ADC ON & Chanel 0  & RIGHT justified
	movwf	ADCON0

;******************************************************************************	
;								PIN Init
;******************************************************************************

	clrf	GPIO
	bsf     STATUS,RP0		; Bank 1 
	movlw	b'00001001'		; All outputs, except PIN 0 - Analog input
	movwf	TRISIO
	bcf     STATUS,RP0		; Bank 0 

;******************************************************************************	
;								General Init
;******************************************************************************

	clrf	TEMP2				; clear
	clrf 	TMR0				; clear Timer 0
	clrf	sleepycounter
	clrf	sleepycounter+1
	bcf		SLEEPFLAG

;******************************************************************************	
;							 Timer ZERO Inits - TMR0
;******************************************************************************
	clrwdt
	bsf     STATUS,RP0			; Bank 1
	bcf		OPTION_REG,T0CS		; Use internal clock source
	bcf		OPTION_REG,PSA		; Prescaler assigned to TMR0
	bcf     STATUS,RP0			; Bank 0

;******************************************************************************	
;							 Timer ONE Inits - TMR1
;******************************************************************************

	movlw	b'00000000'			; Prescaler b'00xx0000' where 11=1:8, 10=1:4, 01=1:2, 00=1:1
	movwf	T1CON


;******************************************************************************	
;							GPIO IOC Init
;******************************************************************************
	movf	GPIO,w				; Clears missmatch
	bcf		INTCON,GPIF			; Clear flag

	bsf     STATUS,RP0			; Bank 1
	bsf		IOC,0				; Enable IOC for GPIO pin 0
	bcf     STATUS,RP0			; Bank 0


;******************************************************************************
;								Variable Init
;******************************************************************************
	movlw	0x01
	movwf	DICE

	clrf	onLEDoffset

	bcf		OFFFLAG
	bcf		GOODREADFLAG
	bcf		HITDEBOUNCEFLAG
	bcf		ANAREJECTFLAG


;******************************************************************************	
;							   INTERRUPT Init
;******************************************************************************

;TIMER 1
	bcf		PIR1,TMR1IF			; Clear Timer 1 Overflow Flag
	clrf	TMR1L
	clrf	TMR1H

	bcf		INTCON,T0IF
	clrf	TMR0

	bsf		INTCON,T0IE


	bsf     STATUS,RP0			; Bank 1
	bsf		PIE1,TMR1IE			; Enable timer 1 overflow
	bsf		PIE1,ADIE			; Enable AD Conversion Inter.
	bcf     STATUS,RP0			; Bank 0

	bsf		T1CON,TMR1ON

;ALL INTERRUPTS
	bsf		INTCON,GIE
	bsf		INTCON,PEIE

;********************************************************************************
;																				*
;								MAIN PROGRAM									*
;																				*
;********************************************************************************
MAIN:

	call	UPDATELEDS

	btfsc	GOODREADFLAG
	goto	MAIN


	btfss	ADCON0,GO
	bsf		ADCON0,GO			; Start the analog reading

	btfss	SLEEPFLAG
	goto	MAIN

; ------------------------ SLEEP SET-UP - START
; --- Turn off A/D converter
	bcf		ADCON0,ADON

; --- Turn off analog pins
	bsf     STATUS,RP0		; Bank 1
	bcf		ANSEL,ANS0		
	bcf     STATUS,RP0		; Bank 0

; --- Clear GPIO
	clrf	GPIO
	movf	GPIO,W

; --- Clear IOC FLAG
	bcf		INTCON,GPIF			; Clear flag	

; --- Turn on IOC for Pin 0
	bsf		INTCON,GPIE
; ------------------------ SLEEP SET-UP - END


	nop
	nop
	SLEEP
	nop
	nop

; ------------------------ SLEEP WAKE - START
; --- Turn off IOC for Pin 0
	bcf		INTCON,GPIE

; --- Turn ON analog pins
	bsf     STATUS,RP0		; Bank 1
	bsf		ANSEL,ANS0		
	bcf     STATUS,RP0		; Bank 0

; --- Turn ON A/D converter
	bsf		ADCON0,ADON

; --- Clear IOC FLAG
	bcf		INTCON,GPIF			; Clear flag	

; ------------------------ SLEEP WAKE - END

	bcf		GOODREADFLAG		; Start reading Analog values right away
	bsf		ANAREJECTFLAG		; Try to re-new the DICE value

	goto	MAIN


;********************************************************************************
;																				*
;  SUBROUTINES 																	*
;																				*
;********************************************************************************



;******************************************************************************
; Flash the LEDS
;******************************************************************************
UPDATELEDS:

	btfsc	OFFFLAG
	goto	EXITUPDATELEDS

UPDATELEDSSTATE:
	movlw	HIGH UPDATELEDSTABLE						
	movwf	PCLATH
	banksel	DICE

	MULTIPLY3 DICE
	addwf	onLEDoffset,w

	addlw	LOW UPDATELEDSTABLE
	btfsc	STATUS,C
	incf	PCLATH,f
	movwf	PCL

UPDATELEDSTABLE:							; STATE
	goto	ONEA							; 	1
	goto	ONEB							; 	1
	goto	ONEC							; 	1

	goto	TWOA							;	2
	goto	TWOB							;	2
	goto	TWOC							;	2

	goto	THREEA							;	3
	goto	THREEB							;	3
	goto	THREEC							;	3

	goto	FOURA							; 	4
	goto	FOURB							; 	4
	goto	FOURC							; 	4
	
	goto	FIVEA							; 	5
	goto	FIVEB							; 	5
	goto	FIVEC							; 	5

	goto	SIXA							; 	6
	goto	SIXB							; 	6
	goto	SIXC							; 	6


	
ONEA:
	LITELEDS	b'00100000'
	goto	EXITUPDATELEDS
ONEB:
	LITELEDS	b'00000000'
	goto	EXITUPDATELEDS
ONEC:
	LITELEDS	b'00000000'
	goto	EXITUPDATELEDS

TWOA:
	LITELEDS	b'00010000'
	goto	EXITUPDATELEDS
TWOB:
	LITELEDS	b'00000000'
	goto	EXITUPDATELEDS
TWOC:
	LITELEDS	b'00000000'
	goto	EXITUPDATELEDS

THREEA:
	LITELEDS	b'00010000'
	goto	EXITUPDATELEDS
THREEB:
	LITELEDS	b'00100000'
	goto	EXITUPDATELEDS
THREEC:
	LITELEDS	b'00000000'
	goto	EXITUPDATELEDS

FOURA:
	LITELEDS	b'00010000'
	goto	EXITUPDATELEDS
FOURB:
	LITELEDS	b'00000100'
	goto	EXITUPDATELEDS
FOURC:
	LITELEDS	b'00000000'
	goto	EXITUPDATELEDS

FIVEA:
	LITELEDS	b'00100000'
	goto	EXITUPDATELEDS
FIVEB:
	LITELEDS	b'00010000'
	goto	EXITUPDATELEDS
FIVEC:
	LITELEDS	b'00000100'
	goto	EXITUPDATELEDS

SIXA:
	LITELEDS	b'00000010'
	goto	EXITUPDATELEDS
SIXB:
	LITELEDS	b'00010000'
	goto	EXITUPDATELEDS
SIXC:
	LITELEDS	b'00000100'
	goto	EXITUPDATELEDS

EXITUPDATELEDS:

	return
;******************************************************************************


;********************************************************************************
;																				*
;  INTERRUPT 																	*
;																				*
;********************************************************************************

INTERRUPT:

; 	Interrupt PREP. here ---------------------------------
	movwf   WTEMP         	;Save off current W register contents
	swapf	STATUS,w
	clrf	STATUS			;Force to page0 
	movwf	STATUSTEMP
	movf	PCLATH,w
	movwf	PCLATHTEMP		;Save PCLATH
	movf	FSR,w
	movwf	FSRTEMP			;Save FSR
	
; --------------------------------------------------------
;	TEST Cause of INTERRUPT
GP2_INT_ExternalInterruptCheck:	
	bcf 	STATUS,RP0		; Force to Bank 0

; Timer 1 Overflow	
	btfsc	PIR1,TMR1IF
	goto	TIMEUP

; ADC conversion Done
	btfsc	PIR1,ADIF
	goto	ANALOGREAD

; Timer Zero Int.
	btfsc	INTCON,T0IF
	goto	TIMERZERO

; GPIO IOC pin int.
	btfsc	INTCON,GPIF
	goto	IOCHANDEL

; 	Interrupt EXIT here ----------------------------------
InterruptEXIT:
	movf	FSRTEMP,w
	movwf	FSR				  ;Restore FSR
	movf	PCLATHTEMP,w
	movwf	PCLATH			  ;Restore PCLATH				
	swapf	STATUSTEMP,w
	movwf	STATUS			  ;Restore STATUS
	swapf	WTEMP,f			  
	swapf	WTEMP,w			  ;Restore W without corrupting STATUS bits
	retfie

; ===================================================================================================== **

;*****************************************************************************************
; 	TMR0 Overflow (Used for "hit" debounnce, and incrementor for delay before Sleep
;*****************************************************************************************
TIMERZERO:							

	btfsc	HITDEBOUNCEFLAG
	goto	HITISDEBOUNCED			; Use 2x Timer 0 for the debounce
	
HITDEBOUNCE:
	bsf		HITDEBOUNCEFLAG
	clrf	TMR0
	bcf		INTCON,T0IF
	goto	CHECKSLEEP

HITISDEBOUNCED:
	bcf		GOODREADFLAG
	bcf		HITDEBOUNCEFLAG

	clrf	TMR0
	bcf		INTCON,T0IF

;---
CHECKSLEEP:
	incf	sleepycounter,f
	btfss	STATUS,Z
	goto	CHECKSLEEPEXIT

;	incf	sleepycounter+1,f		; Use for longer ON time
;	btfss	STATUS,Z
;	goto	CHECKSLEEPEXIT
YESSLEEP:

	bsf		SLEEPFLAG

CHECKSLEEPEXIT:
;---

	goto	InterruptEXIT

;*****************************************************************************************
; 	TMR1 Overflow - Used to adjust ON time of LEDs
;*****************************************************************************************
TIMEUP:							
	
	incf	onLEDoffset,f
	movlw	0x03
	subwf	onLEDoffset,w
	btfss	STATUS,Z
	goto	TIMEUPEXIT
	
	clrf	onLEDoffset

TIMEUPEXIT:

	clrf	STATUS

	movlw	0x40
	movwf	TMR1L

	movlw	0xFF
	movwf	TMR1H

	bcf		PIR1,TMR1IF
	bsf		T1CON,TMR1ON

	goto	InterruptEXIT

;*****************************************************************************************
; 	Analog read is done
;*****************************************************************************************

ANALOGREAD:
	movf	ADRESH,w
	movwf	TEMP2

	btfsc	ANAREJECTFLAG
	goto	ANALOGREADFORCED

; -- old
;	bcf		TEMP2,0				; Comment out this line to make "hit" more sensitive
;	movf	TEMP2,f

;	btfsc	STATUS,Z			; ADRESH will be zero if Analog read is less than 256
;	goto	ANALOGREADEXIT		; Not Hit hard enough !
; -- old

	movf	TEMP2,f
	btfss	STATUS,Z			; ADRESH 
	goto	ANALOGREADFORCED	; ADRESH is greater than 0 -> use the reading

	bsf     STATUS,RP0		; Bank 1
	movf	ADRESL,w
	bcf     STATUS,RP0		; Bank 0
	sublw	0x20
	
	btfsc	STATUS,C			; ADRESL is at least XX
	goto	ANALOGREADEXIT		; Not Hit hard enough !


ANALOGREADFORCED:
	bcf		ANAREJECTFLAG
	clrf	GPIO

	bsf     STATUS,RP0		; Bank 1
	movf	ADRESL,w
	bcf     STATUS,RP0		; Bank 0

	movwf	TEMP2
	movlw	b'00000111'
	andwf	TEMP2,f
	incf	TEMP2,f						; remove zero as posible answer

	movf	TEMP2,w	
	sublw	0x06						; Test for less than or = to 6
	btfss	STATUS,C
	goto	ANALOGREAD_REJECT

	movf	TEMP2,w	
	movwf	DICE

	bsf		GOODREADFLAG
	clrf	TMR0
	bcf		INTCON,T0IF

	clrf	sleepycounter
	clrf	sleepycounter+1

	goto	ANALOGREADEXIT

ANALOGREAD_REJECT:
	bcf		GOODREADFLAG
	bsf		ANAREJECTFLAG

ANALOGREADEXIT:

	bcf		PIR1,ADIF
	goto	InterruptEXIT

;*****************************************************************************************
; 	GPIO IOC HANDLE	(Used only to wake PIC from Sleep mode)
;*****************************************************************************************

IOCHANDEL:
	bcf		SLEEPFLAG
	movf	GPIO,w				; Clears missmatch
	bcf		INTCON,GPIF			; Clear flag

	goto	InterruptEXIT

;******************************************************************************
PLACETOSTOP:
	end                     	; directive 'end of program'

