;**************************************************************************
; SC001_multichip.ASM
;
; PROGRAM: Solar Garden Light Logger based upon Simple Serial Project 
;
;
;	NOTE: Chips oscillator calibration is stored in this source and the HEX file.
;   Adjust to suit your chip.
;
; DESCRIPTION: 
;	I brought a Garden Light logger, and found its performance disappointing.
;
;	I wanted to know how long the battery was being charged, and how long the LED is on at BRIGHT,  DIM and EXHUSTED.
;
;	Also, how long is the battery above a threshold voltage when the SOLAR CELL is not charging?
;
;	This project uses a PIC 16F676 to measure the three voltages of interest on the garden light.
;
;	Instead of storing each voltage sample, it processes the voltages using logic and increments counters.
;
;	The counters are 	MMcntTimeH,MMcntSolarCellH,MMcntBrightH,MMcntDimH,MMcntVbattH
;
;	MMcntTimeH,		Incremented every tick
;	MMcntSolarCellH,	Incremented every tick when the solar Cell is charging battery
;	MMcntBrightH,		Incremented every tick when the LED is bright
;	MMcntDimH,		Incremented every tick when the LED is DIM
;	MMcntVbattH		Incremented every tick when the battery is not being charged and is above a threshold voltage.
;
;	The ticks are every 4 seconds.
;
;	The onlytime when the counters are not being activily incremented is just before dawn at about 03:00
;
;	It uses TMR1 to provides a realtime clock and ticks at 15 seconds. Once a day it saves the counts and resets them.
;
;	It uses the 128 byte EEPROM to store calibration parameters and the days counts for about 9 day's worth of samples.
;
;	It is based on a simple serial project that receives serial commands from a tty program.
;
;	This allows simple access to the logger while it is running, using a tty terminal program.
;
;	
;
; Serial Commands:-
;
;   ; w,p,r,g,f,a
;
; Logger instructions	
;
;	On reset, Counts are reset, and after 4 seconds the chip will auto sample at rate set in eeprom[14]
;
;	<CR>m;	Display Vsolar,Vbatt,VtopLED,count,SolarCont,brightCount,DimmCount,Vbatt&NoChrgeCnt
;	<CR>M;	ResetCounts
;	<CR>s;	Start ticks  
;	<CR>S;	Stop  ticks
;	<CR>d;	dump Conts stored in EEPROM
;
;	<CR>gaa;		get EEPROM values
;	<CR>paadd;	put EEPROM values
;
;	<CR>raa;		read  FILE or RAM values
;	<CR>waadd;	write FILE or RAM values
;
;	The voltages are measured relative to Vref. Vref is connected to the top of a BLUE LED, which provides 3.25 volts
;	This is only turned on to make the measurements, one every 4 seconds.
;
;	<CR>tnn;		toggle pin that turns on the BLUE LED that acts as a reference,
;	<CR>1nn;		sets   pin that turns on the BLUE LED that acts as a reference, turns off LED
;	<CR>0nn;		resets pin that turns on the BLUE LED that acts as a reference, turns on LED
;	
;
;	NOTE: when repeat sampling the output is: ,count,SolarCont,brightCount,DimmCountVsolar,Vbatt,VtopLED,* 
;	
;	AN1 is VREF, so the A to D can be made more sensitive and more stable when measuring V6,V5,V4.
;	AN6 V6 = Vsolar, 
;	AN5 V5 = Vbattery - AN1 is VREF, so the A to D can be made more sensitive when measuring V4.
;	AN4 V4 = VtopOfLED
;
;	the EEPROM can be used to store config data, use pAADD; and gAA;
;	the ee[n] values need to be < 0 
;	
;	g00; 	Get V6-V5+ee[g00]			- If >0 then inc Solar Count
;	g01; 	Get V5-v4-ee[g01]			- If >0 then inc Dim Count
;	g02; 	Get V5-v4-ee[g01]-ee[g02]	- If >0 then inc Bright Count
;	g03; 	Get V6-0xFF*ee[g03]-ee[g04]	- If >0 then inc Vbattery
;	g04; 	Get V6-0xFF*ee[g03]-ee[g04]	- If >0 then inc Vbattery
;	
;	I started with left justified values, but ended up with right justified 16 bit subtracts.
;
;	Measured Voltages: 
;		Vdd   = 3.82
;		Vbatt = 0.94
;		Vref  = 3.25 - using a BLUE LED
;		
;	Measured values of Solar Cell batter voltage for Dim 
;		0 volts
;			Off
;		1.74volts
;			Vbattery - dim 
;		2.2volts
;			Vbattery - Bright  
;
;
;	Uses TMR1 and MMloopCount:
; 
;	TMR1 overflows  Fosc/4, 1e6/2^16m = 1/15.2587890625
;
;	My Serial LCD display needs an inter Character delay to process the last character.
;	You can configure an inter character deleay here.
;
;	g05;		Get delay between characters in bits to allow a serial LCD to be used.
;
;	Here we use the EEPROM to store the counters.
;	g07;		Pointer to Samples 
;	g08 to g7F;	Samples	- there are 103 bytes, there are 5 counts so 10 sets can be stored.
;
;
; Special Instructions.
;	<CR>tDD;			Toggle for DD ms 
;	<CR>1DD;			Set 1  for DD ms wait for DD and then set to 1
;	<CR>0DD;			Set 0  for DD ms wait for DD and reset 
;
;	<CR>aDD;			read AtoD converter and output in hex, DD is ADCON0
;
; File Registers
;	<CR>wAADD;		write DD to register AA
;	<CR>rAA;  		read AA and output to serial port
;
; File reg 25,26,27 stores the time to the next save of the EEPROM counts.
;	R25;	hours   to next store
;	R26;	minutes to next store
;	R27;	seconds to next store
;
;	This is needed as you want to save the counts when they are not being incremented, 
;	which is just before dawn.	
;
;	If you reset the PIC at 18:00, the chip will save at about 03:00
;
; EEPROM
;	<CR>pAADD;		write DD to EEPROM register AA
;	<CR>gAA;  		read EEPROM register AA and output to serial port
;
; PRIPHERALS
;
; SERIAL PORT CONTROL:
;
;	PORT RA0  is Serial input
;	PORT RA0 is serial output
;
;	usb gmus-03 USB Serial Adapter
;
;	TX  D9 Pin 3 -[4k7]----+-----PA0
;	RX  D9 Pin 2 ----------/
;
;	GND D9 Pin 5 ---------------- 0V
; 
;	29/09/2008 discovered that using PA0 affects AtoD Reading.
;
;	TX  D9 Pin 3 -[4k7]----+-----PC5
;	RX  D9 Pin 2 ----------/
;
;	GND D9 Pin 5 ---------------- 0V
; 
;
;	Crystal:	4MHz - Uses Internal RC oscillator
;
;	I/O used:-
;
;	; Port B is used for the LCD
;
;	OPERATION:
;	The TMR1 ticks overflow and trigger the AtoD process periodically.
;	The three volatages are measured, and then compared using logic.
;	The appropriate counters are incremented.
;
;	Every sample the current counts are output on the serial port.
;
;	It is possible to use the serail port to update the EEPROM and start and stop the sampling.
;
;
;	MMcntTimeH,MMcntSolarCellH,MMcntBrightH,MMcntDimH,MMcntVbattH
;
; Samples from logger - Vref is relative to Vdd, others are relative to Vref
;CNT ,SolC,Bright,Dim,Vbatt,,/,INTCON,T1,,t,HHMM,SS  ,,,Vsc,Vba,Vled,Vref
;
;MMcntTimeH,MMcntSolarCellH,MMcntBrightH,MMcntDimH,MMcntVbattH,/t,hhmmss,Vsolar,Vbattery,VtopOfLED,Vref,//s,Vsolar-Vbatt,Vbatt-Vled
;007B,007B,0000,0000,0000,/t,08380D,0360,02B0,02B2,0345,//s,00B0,l,FFFE,,*
;007C,007C,0000,0000,0000,/t,08380C,0360,02B3,02B0,0345,//s,00AD,l,0003,,*
;
;
;	MMcntTimeH,MMcntSolarCellH,MMcntBrightH,MMcntDimH,MMcntVbattH
; Every day the counts are stored and backed up, in the order:
;	MMcntTimeH,MMcntSolarCellH,MMcntBrightH,MMcntDimH,MMcntVbattH
;
; Use the d; command to dump the EEPROM counts.
;d;*
;19,*
;19,,FFFF,FFFF,FFFF,FFFF,FFFF,*
;23,,FFFF,FFFF,FFFF,FFFF,FFFF,*
;2D,,FFFF,FFFF,FFFF,FFFF,FFFF,*
;37,,FFFF,FFFF,FFFF,FFFF,FFFF,*
;41,,FFFF,FFFF,FFFF,FFFF,FFFF,*
;4B,,FFFF,FFFF,FFFF,FFFF,FFFF,*
;55,,FFFF,FFFF,FFFF,FFFF,FFFF,*
;5F,,FFFF,FFFF,FFFF,FFFF,FFFF,*
;69,,FFFF,FFFF,FFFF,FFFF,FFFF,*
;73,,FFFF,,**
;
;
;	Future Enhancements:
;
;
; AUTHOR:  Douglas Rice
; Copyright 2006
;
;**************************************************************************


;--------------------------------------------------------------------------
; Sec 0.  #Defines tofor different chips
;--------------------------------------------------------------------------

; uncomment only one of these
;

#define pic16F676 	1
;#define pic12F675 	1

    LIST    w=1, R=DEC


;--------------------------------------------------------------------------
; Sec 0.1 #Defines for 16F676
;--------------------------------------------------------------------------

	ifdef pic16F676
	#define wantAtoD
	
    LIST    P=16F676, R=DEC
	INCLUDE "p16F676.inc"       

	__idlocs  0x0676
	;__CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _INTRC_OSC_CLKOUT _INTRC_OSC_NOCLKOUT & _MCLRE_OFF & 0x31FF
	__CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON &  _INTRC_OSC_NOCLKOUT & _MCLRE_OFF & 0x31FF
	
	cblock 0x20
	endc

; *********** I/O EQUATES **************
PA0           EQU  0		; Serial Out and Serial In - moved. This affects AtoD result.
PA1           EQU  1		; Output
PA2           EQU  2		; Output
PA7           EQU  7		; Output

PC5           EQU  5		; Serial Out and Serial In



;PORT_RS232	EQU  PORTA 	    
;TRIS_RS232	EQU  TRISA 	    
;RS232tx		EQU  PA0	; Serial Out
;RS232rx		EQU  PA0	; Serial In needs to be equal to BUTTON_RS232

PORT_RS232	EQU  PORTC 	    
TRIS_RS232	EQU  TRISC 	    
RS232tx		EQU  PC5	; Serial Out
RS232rx		EQU  PC5	; Serial In needs to be equal to BUTTON_RS232


OUTPUTPIN	  	EQU  3	;  



	endif



;--------------------------------------------------------------------------
; Sec 0.2 #Defines for 16F876
;--------------------------------------------------------------------------

	ifdef pic16F876
#define 	buildPWM	1
    	LIST    P=16F876, R=DEC
	INCLUDE "p16F876.inc"       

	__idlocs  0x0876
	__CONFIG _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_ON & _WDT_OFF & _BODEN_OFF & _PWRTE_ON  & _HS_OSC & _LVP_OFF
	
	cblock 0x20
	endc

; *********** I/O EQUATES **************

PORT_RS232	  EQU  PORTA 	    
TRIS_RS232	  EQU  TRISA 	    
RS232tx         EQU  0	; Serial Out
RS232rx         EQU  0	; Serial In needs to be equal to BUTTON_RS232


	endif


;--------------------------------------------------------------------------
; Sec 0.3 #Defines for 12F675
;--------------------------------------------------------------------------

	ifdef pic12F675
	#define wantAtoD
    	LIST    P=12F675, R=DEC

	INCLUDE "p12F675.inc"       
	__idlocs  0x0675
	__config  _PWRTE_ON & _WDT_OFF & _BODEN_OFF & _INTRC_OSC_NOCLKOUT & _MCLRE_OFF 

	
	cblock 0x20
	endc

; *********** I/O EQUATES **************

PORT_RS232  EQU  GPIO 	    
TRIS_RS232  EQU  TRISIO 	    
RS232tx     EQU  5	; Serial Out
RS232rx     EQU  5	; Serial In needs to be equal to BUTTON_RS232

OUTPUTPIN   EQU  3

PORTA		EQU  GPIO 	    		
PORTB		EQU  GPIO 	    		

TRISA		EQU  TRISIO 	    
TRISB		EQU  TRISIO 	    

	endif



;--------------------------------------------------------------------------
; Sec 1. Equates and Constants
;--------------------------------------------------------------------------
; The General Purpose Registers start at the end of the 
; Special Purpose Registers.

; IPMentState values
; in normal running or in time setting modes
;

; DoTimeSlice bits
; these bits are set to schedule a timer chain event
DTsS4event		EQU	0	; 
RUN_BUFF			EQU	0	; 

; IPtrigMenu
DTSFast			EQU	0

;--------------------------------------------------------------------------
; Sec 1.1 Button and LED 
;--------------------------------------------------------------------------

BUTTON_RS232	EQU	RS232rx	; EDG  - Bottom Buttom
BUTTON_DOWN	EQU	3		; EDG  - STore Counts Button.

;--------------------------------------------------------------------------
; Sec 1.2 EEPROM LOCATIONS
;--------------------------------------------------------------------------
;	g00; 	Get V6-V5-ee[g00]		- If >0 then inc Solar Count
;	g01; 	Get V5-v4-ee[g01]		- If >0 then inc Dim Count
;	g02; 	Get V5-v4-ee[g01]-ee[g02]		- If >0 then inc Bright Count
;	g03; 	Get V6- ee[g03],ee[g04]- If >0 then inc Vbattery
;
;	g00,g01,g02,are too insensitive, and the values have to be -2,-2,-1
;	g03 = 0x78

EEsolarOffset		EQU 0x00
EEdimOffset		EQU 0x01	
EEbrightOffset	EQU 0x02	
EEbatteryOffsetH	EQU 0x03
EEbatteryOffsetL	EQU 0x04
EEinterCharDelay	EQU 0x05
EEAtoDappatureDelay EQU	0x06
				;	EQU 0x06
				;	EQU 0x07
EEinterCharDelay	EQU 0x05


EEFILESTART		EQU	0x08
EEFILEPTR	  		EQU	EEFILESTART-1


;--------------------------------------------------------------------------
; Sec 2.0 Variables
;--------------------------------------------------------------------------
; Variables start 0x0C
;

;	DoTimeSlice Bits, to schedule, set bit

	cblock 	

;
; AD AtoD routine Variables.
;
ADrl
ADansel



BTdelay

BTdelayCnt
BTdelayCnt1ms


CLhh
CLmm
CLss
DoTimeSlice


IPnew
IPlast
IPbuttonEvent

IPnewFast
IPlastFast
IPbuttonEventUp

IPtrigMenu

;
; MM Solar Cell Measurement Code. 
; 
MMtmph
MMtmp

; Using Vref as Max
MMV6h	
MMV6l
MMV5h
MMV5l
MMV4h
MMV4l
; Using Vdd as Max
MMV1h	
MMV1l


; count, time, solarCell, bright, dim ,
MMcntTimeH
MMcntTimeL
MMcntSolarCellH
MMcntSolarCellL
MMcntBrightH
MMcntBrightL
MMcntDimH
MMcntDimL
MMcntVbattH
MMcntVbattL
;
;MMloopCount

EEptrEEPROM	; pointer to EEPROM
EEptrMEM	; pointer to Memory - count, time, solarCell, bright, dim 
EEloopCount
EEloopCount2


; variables used by Serial input and output routines
RStxTemp
RStxTemp2
RSloopCnt

RSdelayCnt
RSin
RSout
RSinterCharDelay
RSafterCRCharDelay

; Serial input buffer
RSipBuffCnt ; input buffer counter
; start of buffer
RScmd
RSAa		;
RSaA		;
RSDd		;
RSdD		;
RSterminator
; end of buffer

; temporary variables
RSaddr
RSdata
;
	ENDC

;--------------------------------------------------------------------------
; Sec 3. MACROS
;--------------------------------------------------------------------------

TEST_STRADDLE	MACRO	START
	if high( $ ) != high( START ) 
	    Error "Table straddles Page Boundary " + Start
	endif
	endm

;--------------------------------------------------------------------------
; Sec 4. Program Code
;--------------------------------------------------------------------------
	ORG     0       
	GOTO    Start

	ORG 	4
	RETFIE
	GOTO 	Intrtn

;--------------------------------------------------------------------------
; Sec 4.1 	Main Program Init Code
;--------------------------------------------------------------------------

Start

	;MOVLW	0x6C		; load the Calib
	movlw	0x98
	
	;CALL 	OscCalValue
	banksel	OSCCAL
	MOVWF	OSCCAL


;	Debug jumps:
;	CALL	MMtsSample1false
;	CALL	MMtsSampleProcess


	BANKSEL	TRISA
	MOVLW	1 << 4 | 1 << 5 | 0 << 3 | 1 << 2 | 1 << 1 | 1 << 0 
	MOVWF	TRISA

	;BANKSEL	TRISC
	MOVLW	1 << 4 | 1 << 5 | 1 << 2 | 1 << 1 | 1 << 0
	MOVWF	TRISC

	; There is currently a conflict as serial is on RA0
	banksel  ANSEL
	MOVLW	1 << ANS5 | 1 << ANS4 | 0 << ANS2 | 1 << ANS1 | 0 << ANS0
	movwf	ANSEL
	
	; Turn off the comparator.
	MOVLW	1 << CM2 | 1 << CM1 | 1 << CM0 
	banksel 	CMCON
	MOVWF	CMCON	

	CALL	MMts

	MOVLW	1 << ANS5 | 1 << ANS4 | 1 << ANS1
	movwf	ADansel
	
	CALL	ADconvert

	CALL 	INinit
	CALL	INsayHello	
	
	; set up for manual start, get repeat time in g14
	; reset logger and delay first time for 8 seconds 
	; to allow user to type <CR>S; on reset.
	
	CALL	MMinit		; init
	CALL	MMinitTime

	CALL	EEfileDump
		
	GOTO	MainLoop


;--------------------------------------------------------------------------
; Sec 4.2		Main Program 
;--------------------------------------------------------------------------

MainLoop	
		BANKSEL 	DoTimeSlice
		CALL	IPtimesliceFast
		
		; test for rising edge
		BTFSC	IPbuttonEventUp,BUTTON_RS232	; RS232 input start 
		CALL	IPrs232
		
		BTFSC	PIR1,TMR1IF
		CALL	MMts

		MOVF	DoTimeSlice,w
		Bz		MainLoop

		BTFSC	DoTimeSlice,RUN_BUFF
		CALL	DLrunBuff

		GOTO 	MainLoop
		


;--------------------------------------------------------------------------
; Sec 5.	Subroutines, procedures and functions
;--------------------------------------------------------------------------


;--------------------------------------------------------------------------
; Sec 5.1		Button Poll Routine
;--------------------------------------------------------------------------
		
IPtimeslice
		;	--_____	button press
		;	----___	
		
		;	__-----  /IPnew
		;	----___  IPlast
		;	__--___  
		;
		;
		;
		; This reads all Port A inputs and looks for Press
		MOVFW	IPnew
		MOVWF	IPlast
		MOVFW	PORTA
		MOVWF	IPnew
		; IP last contains new setting, IPlast contains previous
		; look for falling edges
		COMF	IPnew,W
		ANDWF	IPlast,W
		; now force IPbuttonEvent bits to high for new pressed button
		; the service routine should reset the bit to clear the event.
		IORWF	IPbuttonEvent,F
		RETURN

IPtimesliceFast
		; Look for rising edges
		MOVFW	IPnewFast
		MOVWF	IPlastFast
		MOVFW	PORT_RS232
		MOVWF	IPnewFast

		COMF	IPlastFast,W
		ANDWF	IPnewFast,W
		IORWF	IPbuttonEventUp,F
		RETURN
;--------------------------------------------------------------------------
; Sec 5.2	
;--------------------------------------------------------------------------

;--------------------------------------------------------------------------
; Sec 5.2	.1 run process on request
;--------------------------------------------------------------------------

DLrunBuff
		BANKSEL DoTimeSlice
		BCF	DoTimeSlice,RUN_BUFF
	
		MOVFW	RSin			
		GOTO	RSbuffInput
		;return
	
	


;--------------------------------------------------------------------------
; Sec 5.3	 Button Input functions
;--------------------------------------------------------------------------


IPdownPressed 
		BCF IPbuttonEvent,BUTTON_DOWN
		GOTO	EEfileCounts


IPrs232
		BCF IPbuttonEventUp,BUTTON_RS232
		GOTO RSrs232in 	


;--------------------------------------------------------------------------
; Sec 5.4	 Clock Chain Routine
;--------------------------------------------------------------------------
		
CLtimeslice
		;
		BTFSS	INTCON,T0IF
		RETURN

		; TMR0 timeout
		BCF		INTCON,T0IF
		BSF		DoTimeSlice,DTsS4event
		
		CALL	IPtimeslice
		RETURN


;--------------------------------------------------------------------------
; Sec 5.5 	Serial Input Routine
;--------------------------------------------------------------------------

RSjumpTable
	; Its not a CLICK or HOLD
	MOVLW	high ( $ )
	MOVWF	PCLATH			; Assume that the tabel is in the bottom 256 byte
	; restrict to 32 states
	;ANDLW	0x03
	MOVFW	RSloopCnt
	ADDWF	PCL,f
	; set choice State Table - limited to 8 states
	RETLW	'w'
	GOTO	RSbuffInput2start		
	RETLW	'p'
	GOTO	RSbuffInput3start		
	RETLW	'r'
	GOTO	RSbuffInput4start		
	RETLW	'g'
	GOTO	RSbuffInput5start		
;	RETLW	'f'
;	GOTO	RSbuffInput6start		
	RETLW	't'
	GOTO	RSbuffInput7start		
	RETLW	'1'
	GOTO	RSbuffInput8start		
	RETLW	'0'
	GOTO	RSbuffInput9start		
	RETLW	'a'
	GOTO	RSbuffInput10start		
	RETLW	'M'
	GOTO	RSbuffInput11start
	RETLW	'm'
	GOTO	RSbuffInput12start
	RETLW	's'
	GOTO	RSbuffInput13start
	RETLW	'S'
	GOTO	RSbuffInput14start
	RETLW	'd'
	GOTO	RSbuffInput15start
	RETLW	0
	
	TEST_STRADDLE	 RSjumpTable

	

		

;**************************************************
RSrs232in

; Test is in main loop or uncomment code below to
; spin for a start bit 
;		CLRWDT
;		BTFSS	PORT_RS232,RS232rx	
;		GOTO	RSrs232in		
		
		
	; CALL	RSdelayBit			; delay through Stop Bit
	CALL 	RSdelayHalfBit		; delay halfway into first bit

	movlw	8
	movwf	RSloopCnt
RSrs232inL0
	CALL	RSdelayBit			; delay halfway into first bit

	MOVFW	PORT_RS232
	ANDLW	 1<< RS232rx		; mask off bit
	ADDLW	-1<< RS232rx		; use ripple carry to move into C
	RRF		RSin,F
		
	; CALL	RSdelayBit
	DECFSZ	RSloopCnt,f
	goto	RSrs232inL0

	; do not test for Stop bit
	COMF	RSin,f
	BSF		DoTimeSlice,RUN_BUFF
	RETURN
		

;--------------------------------------------------------------------------
; Sec 5.6 	Serial Output Routines
;--------------------------------------------------------------------------

RSwrtWasHex
	;
	; Write W reg as HEX to RS232
	;
	MOVWF	RStxTemp2
	SWAPF	RStxTemp2,W
	CALL	RSwrtHexNibble
	MOVFW	RStxTemp2
	GOTO	RSwrtHexNibble


RSwrtHexNibble	; currently only displays 0..9, A..F
	ANDLW	0x0F
	ADDLW	0x06	; is it A..F, if so trigger a digit overflow
	SKPNDC
	ADDLW	7; subtract 10, then add 'A'-'0'
	ADDLW	0x30-6	; Subtract extra 6 added to cause DC
	MOVWF	RSout
	GOTO	RStxChar
	
	
RS232sendCR	
	MOVLW	0x0D
	GOTO	RS232sendWByte	
		
RS232sendLF	
	MOVLW	0x0A
	GOTO	RS232sendWByte	

RS232sendSpace	
	MOVLW	' '
	GOTO	RS232sendWByte	

RS232sendComma	
	MOVLW	','
	GOTO	RS232sendWByte	

RS232sendStar
	MOVLW	'*'
	GOTO	RS232sendWByte	


RS232sendWByte	
RStxChar
	;
	; Output Start Bit
	; Start bit is low, data bits are inverted
	;
	
	movwf	RStxTemp
	comf	RStxTemp,f
	BCF		PORT_RS232,RS232tx

	; Make RS232 pin an ouput while transmitting character
	BANKSEL  TRIS_RS232		
	BCF		TRIS_RS232,RS232tx
	BANKSEL  PORT_RS232		

	; 1200 baud output
	; move the char into RStxtemp, it is destroyed.
	;Start Bit
	BSF		PORT_RS232,RS232tx

	call	RSdelayBit
	movlw	8
	movwf	RSloopCnt

RStxCharLp1
	
	; After start bit, which is 1, then test each bit
	; I need to set PA:0 to same as LSB RStxTemp
	; this compares PA:0 with RStxTemp so see if it needs toggling
	; The xorwf PORT_RS232,f causes the bit to be toggled if required.
	
	RRF		RStxTemp,f
	movfw	STATUS
	andlw	1 << C			; mask off bit
	addlw   ( 1 << RS232tx) -1	; shift bit by using a ripple carry
	xorwf	PORT_RS232,W			; Doeas output need toggling ?
	andlw	1 << RS232tx		; Mask off output pin	
	xorwf	PORT_RS232,f			; Toggle output pin if needed	
	call	RSdelayBit			; delay bit
	
	
	decfsz	RSloopCnt,f
	goto	RStxCharLp1

	BCF		PORT_RS232,RS232tx
	call	RSdelayBit	; apply stop bit

	; apply an inter character delay of  4 bits
	; call	RSdelayBit
	; get inter character delay from the EEPROM

	; you have to read from RAM, and not EEPROM as pXXXX; does not work as EEwrt needs delay before EEread 
	MOVFW	RSinterCharDelay
RStxCharInterDelay	
	movwf	RSloopCnt

RStxCharLp2
	call	RSdelayBit
	decfsz	RSloopCnt,f
	goto	RStxCharLp2


	; Make RS232 pin an input so that main loop can test for start bit
	BANKSEL  TRIS_RS232		
	BSF		TRIS_RS232,RS232tx
	BANKSEL  PORT_RS232		

	RETURN


; timing functions to delay serial routines for a bit or half bit.

RSdelayHalfBit		
	MOVLW	0x1D		; shorten delay as edge detector takes about 22 us for 4800 baud
	GOTO	RSdelayBit0			

RSdelayBit		
	NOP
	MOVLW	0x40	 ; for 4800 baud	

RSdelayBit0			
	MOVWF	RSdelayCnt
RSdelayBit1	
	DECFSZ	RSdelayCnt,f		; 1
	GOTO	RSdelayBit1		; 2 clk
	CLRWDT
	RETURN



;--------------------------------------------------------------------------
; Sec 5.7 	Serial Output Format Routines
;--------------------------------------------------------------------------

RSasciiToNibble
	MOVWF	RSin
	; if 0..1 then 0x30 to 0x39
	; if A..F then 0x41 to 0x46
	; if a..f then 0x61 to 0x66
	; test if bit 4 set and assume a letter or number
	BTFSS	RSin,4
	ADDLW	0x09		; letter so add 9 
	ANDLW	0x0F		; mask of nibble
	return


;--------------------------------------------------------------------------
; Sec 5.8 	Serial Input Buffer Routine
;--------------------------------------------------------------------------

; take serial input CAADD and put into buffer 
; if char id ; the do command
; if char is CR reset buffer pointer
; if buff end then reset buff pointer

RSipbuffStart	EQU RScmd 
RSipbuffEnd	EQU RSterminator

RSbuffInput
	MOVWF	RSin
	; look for line feed and reset buff cnt
	ADDLW	-0x0D
	BNZ		RSbuffInput1
	
RSbuffInput1start	
	MOVLW	RSipbuffStart
	MOVWF	RSipBuffCnt
	RETURN

RSbuffInput1		
	; end of line command - do command
	ADDLW	-';'+0x0D
	BNZ		RSbuffInput2
	GOTO	RSbuffInputProcess

RSbuffInput2
	; Store the current time into the next register.
	MOVFW	RSipBuffCnt
	MOVWF	FSR
	MOVFW	RSin
	MOVWF	INDF
	INCFSZ	RSipBuffCnt,f
	MOVFW	RSipBuffCnt

	ADDLW	-(RSipbuffEnd+1)
	; Check if the end of memory
	SKPZ	
	GOTO	RSbuffInputEnd1
	MOVLW	RSipbuffStart
	MOVWF	RSipBuffCnt

	; reset cursor
	
	CALL 	RS232sendCR
	RETURN
	

RSbuffInputProcess
	MOVLW	RSipbuffStart
	MOVWF	RSipBuffCnt

	MOVFW	RSAa
	; if 0..1 then 0x30 to 0x39
	; if A..F then 0x41 to 0x46
	; if a..f then 0x61 to 0x66
	; test if bit 4 set and assume a letter or number

	BTFSS	RSAa,4
	ADDLW	0x09		; letter so add 9 
	ANDLW	0x0F		; mask of nibble
	MOVWF	RSin
	SWAPF	RSin,F
	
	MOVFW	RSaA
	BTFSS	RSaA,4
	ADDLW	0x09		; letter so add 9 
	ANDLW	0x0F		; mask of nibble
	ADDWF	RSin,w
	MOVWF	RSaddr

	MOVFW	RSDd
	BTFSS	RSDd,4
	ADDLW	0x09		; letter so add 9 
	ANDLW	0x0F		; mask of nibble
	MOVWF	RSin
	SWAPF	RSin,F
	
	MOVFW	RSdD
	BTFSS	RSdD,4
	ADDLW	0x09		; letter so add 9 
	ANDLW	0x0F		; mask of nibble
	ADDWF	RSin,w
	MOVWF	RSdata
	
	; CALL 	RStxChar

	; got to end of buffer so process. does not allow for backspace

	MOVFW	RScmd
	
	CALL	RSfindAndRunCommand

;	; Write to file register
;	MOVLW	-'w'
;	ADDWF	RScmd,w	; test to see if command is s, if so save into register.
;	bnz  	RSbuffInput3		
	
RSbuffInput2start	
	; Write to file register
	MOVFW	RSaddr
	MOVWF	FSR
	
	MOVFW	RSdata
	MOVWF	INDF

	GOTO	RSbuffInputEndOK
	
	

RSbuffInput3start	
	; put octet in EEPROM
	BANKSEL	RSaddr
	MOVFW	RSaddr
	CALL	EEsetAddr

	BANKSEL	RSdata
	MOVFW	RSdata
	CALL	EEwrt

	GOTO	RSbuffInputEndOK
	
		

RSbuffInput4start
	; read from file register
	MOVFW	RSaddr
	MOVWF	FSR
	
	MOVFW	INDF
	MOVWF	RSin

RSbuffInput4display
	MOVLW	'='
	CALL 	RStxChar
	
	SWAPF	RSin,w
	CALL	RSwrtHexNibble

	MOVFW	RSin
	CALL	RSwrtHexNibble
	
	GOTO	RSbuffInputEnd



RSbuffInput5start
	; get from EEPROM register
	MOVFW	RSaddr
	CALL	EEread
	MOVWF	RSin
	
	GOTO	RSbuffInput4display	


	
RSbuffInput7start	
	; Toggle A0 for AA ms
	CALL	BTtoggle
	GOTO	RSbuffInputEndOK
			

RSbuffInput8start	
	; Set A0
	CALL	BTdelaySet
	GOTO	RSbuffInputEndOK
			

RSbuffInput9start	
	; Reset A0
	CALL	BTdelayReset
	GOTO	RSbuffInputEndOK


		

RSbuffInput10start	
	CALL	ADconvert
	GOTO	RSbuffInputEnd
	

RSbuffInput11start	
	CALL	MMinit
	GOTO	RSbuffInputEndOK

	
RSbuffInput12start	
	MOVLW	EEinterCharDelay		;0x15
	CALL	EEread
	MOVWF	RSinterCharDelay

	CALL	MMtsSample
	MOVLW	','
	CALL 	RStxChar

	CALL	MMdisplay
	GOTO	RSbuffInputEndOK
			

RSbuffInput13start	
	CALL	MMstartTicks
	GOTO	RSbuffInputEndOK
			

RSbuffInput14start	
	; STOP measure Solar Cells
	CALL	MMstopTicks
	GOTO	RSbuffInputEndOK

;RSbuffInput15
;	; dump EEPROM 
;	MOVLW	-'d'
;	ADDWF	RScmd,w	
;	bnz  	RSbuffInput16

RSbuffInput15start
	; dump EEPROM 
	CALL	EEfileDump
	GOTO	RSbuffInputEndOK

RSbuffInput16
RSbuffInputEndNOK
	MOVLW	'?'
	CALL 	RStxChar
	GOTO	RSbuffInputEnd
			
RSbuffInputEndOK
	MOVLW	'*'
	CALL 	RStxChar

RSbuffInputEnd
	CALL 	RS232sendCR
	CALL 	RS232sendLF
		

RSbuffInputEnd1
    return


;--------------------------------------------------------------------------
; Sec 5.9 	Lookup command letter by doing a linear search
;--------------------------------------------------------------------------


RSfindAndRunCommand
	; look up command
	MOVWF	RSin
	CLRF	RSloopCnt
RSfindCmd1	
	CALL	RSjumpTable
	; Increment pointer onto the command.
	INCF	RSloopCnt,f	

	; test if command char has ben found in the list.
	XORWF	RSin,w
	BZ		RSfindCmdFound
	XORWF	RSin,w
	BZ		RSfindCmdEnd
	
	; point onto next command
	INCF	RSloopCnt,f	
	GOTO	RSfindCmd1		
	
RSfindCmdFound
	GOTO 	RSjumpTable
	
RSfindCmdEnd
	GOTO	RSbuffInputEndNOK

;--------------------------------------------------------------------------
; Sec 5.10 	Initilization code - 
;--------------------------------------------------------------------------


INinit
	; Enable Interupts
	MOVLW	H'00'
	; BANKSEL	INTCON is available in both banks.
	MOVWF	INTCON

	CLRF PORT_RS232 ;Initialize PORT_RS232 by setting
	;output data latches
	
	ifdef wantAtoD
	; get the Oscillator calibration

	;MOVLW	0x6C		; load the Calib
;	BSF		STATUS,RP0
;	CALL 	OscCalValue
;	MOVWF	OSCCAL

	
	BANKSEL 	CMCON
	MOVLW 	0X07 ;Turn comparators off and
	MOVWF 	CMCON ;enable pins for I/O
	
;	BANKSEL 	ANSEL
;	CLRF	ANSEL	

	endif



	ifdef pic16F628
	BANKSEL CMCON
	MOVLW 0X07 ;Turn comparators off and
	MOVWF CMCON ;enable pins for I/O

	endif

	ifdef pic16F876
     ;make AtoD inputs digital
	BANKSEL ADCON1
	MOVLW 0X07 ;Turn comparators off and
	MOVWF ADCON1 ;enable pins for I/O
	endif


    ifndef	 pic16F676
	banksel	TRISB
	MOVLW	0XF0
	MOVWF	TRISB
	endif
	
	banksel	TRIS_RS232
	BSF		TRIS_RS232, RS232tx 	; Make PORT_RS232 3:0 INPUTS.
	BCF		TRIS_RS232, OUTPUTPIN
	

	banksel	RSipbuffStart
	; reset input buffer
	MOVLW	RSipbuffStart
	MOVWF	RSipBuffCnt

	; Change Prescaler
	CLRWDT

	; Configure Tmr 0
	BSF		STATUS,RP0
	; Set up prescaller for 8192 / 16 = 512 ticks perseconds.

	MOVLW	0x0 + 2 	; For Tmr0 0=/2, 1=/4, 2=/8,3=/16
	MOVWF	OPTION_REG
	BCF		STATUS,RP0

	ifdef buildPWM

	; Configure Tmr 1
	MOVLW	0x0 | 1<<TMR1ON | 3 <<T1CKPS0 
	MOVWF	T1CON

	endif

	CLRF	DoTimeSlice	
	CLRF	IPbuttonEvent
	CLRF	IPbuttonEventUp
	return

INsayHello	
	; print out power on message

	CALL 	RS232sendCR
	CALL 	RS232sendLF

	MOVLW	'S'
	CALL 	RStxChar
		
	MOVLW	'R'
	CALL 	RStxChar
		
	CALL 	RS232sendCR
	CALL 	RS232sendLF

	return


;--------------------------------------------------------------------------
; Sec 5.11 	EEprom Routines for 16F628
;--------------------------------------------------------------------------

EEread		
	; w contains address
	banksel	EEADR	
	MOVWF	EEADR
	BSF		EECON1,RD
	MOVFW	EEDATA
	banksel	0	
	RETURN

EEsetAddr
	banksel	EEADR
	MOVWF	EEADR
	RETURN
		
EEwrt	; blocking, EEADR and EEDATA set up.

	banksel 	EEDATA

	MOVWF	EEDATA
	BANKSEL	INTCON
	BCF		INTCON,GIE

	; need to enable peripheral interupts for wake up from sleep.
	BSF		INTCON,PEIE
	BCF		PIR1,EEIF

	BANKSEL	PIE1
	BSF		PIE1,EEIE

	BANKSEL EECON1
	BCF		EECON1,WREN	; disable EROM
	BSF		EECON1,WREN
	; BCF		INTCON,GIE
	MOVLW	0x55
	MOVWF	EECON2
	MOVLW	0xAA
	MOVWF	EECON2
	BSF		EECON1,WR
		
	BANKSEL	INTCON
	BCF		INTCON,GIE

	BANKSEL	PIR1
	BCF		PIR1,EEIF
	
	BANKSEL	PIE1
	BsF		PIE1,EEIE
		
	; Now wait for EEwrt to finish write
EEwaitForWrt	; block until EEPROM write has finished.
	BANKSEL EECON1
	BCF		EECON1,WREN	; disable EROM

	; NOTE:- I have commented out the goto and the write to eeprom started to work


	SLEEP
	NOP
	NOP

	BANKSEL 	EECON1
	BTFSC	EECON1,WR	
	GOTO	EEwaitForWrt
		
	BANKSEL	PIR1
	BCF		PIR1,EEIF		; EEPROM finished

	banksel	0	
	RETURN
		
	
	
	
;--------------------------------------------------------------------------
; Sec 5.12	Routines to set up PWM on 16F628
;--------------------------------------------------------------------------


BTtoggle	; set up the PWM   
	MOVLW	1 << OUTPUTPIN
	XORWF	PORTC,f
	CALL 	BTdelayNms
	MOVLW	1 << OUTPUTPIN
	XORWF	PORTC,f
	RETURN
	
BTdelaySet	; set up the PWM
	CALL 	BTdelayNms
	BSF		PORTC,OUTPUTPIN
	RETURN
	
BTdelayReset	; set up the PWM
	CALL 	BTdelayNms
	BCF		PORTC,OUTPUTPIN
	RETURN
	
	
BTdelayNms
    ; pick up the delay from the CMD line to impliment tDD;
	MOVFW	RSaddr
;	MOVFW	BTdelay
	MOVWF	BTdelayCnt
BTdelayNms1
	CALL 	BT1msdelay	
	DECFSZ	BTdelayCnt
	GOTO	BTdelayNms1
	RETURN
	
BT1msdelay
	MOVLW	.199
	
BTdelayW10us
	MOVWF	BTdelayCnt1ms
BT1msdelay1   	
	GOTO	$+1	
	DECFSZ	BTdelayCnt1ms
	GOTO	BT1msdelay1	
	RETURN
	
	
	
;--------------------------------------------------------------------------
; Sec 5.13	Routines to read A to D converter on 16F676
;--------------------------------------------------------------------------


ADconvertVdd
	ifdef pic16F676

	movfw	ADansel
	banksel  ANSEL
	movwf	ANSEL

	banksel  ADCON1
	movlw	B'00010000'	;Fosc/8
	movwf	ADCON1
	
	movfw	RSaddr
	addwf	RSaddr,w
	addwf	RSaddr,w
	addwf	RSaddr,w
	iorlw	B'10000000'	; right Justify and Vdd  and Turn on
	banksel  ADCON0
	movwf	ADCON0
	iorlw	B'10000001'	; right Justify and Vdd and Turn on
	movwf	ADCON0
	endif

	GOTO	ADStartConvert

ADconvert

	ifdef pic16F676
	movfw	ADansel
	banksel  ANSEL
	movwf	ANSEL

	banksel  ADCON1
	movlw	B'00010000'	;Fosc/8
	movwf	ADCON1
	
	movfw	RSaddr
	addwf	RSaddr,w
	addwf	RSaddr,w
	addwf	RSaddr,w
	;iorlw	B'10000001'	; Left justify and turn on
	iorlw	B'11000000'	; right Justify and Vref 
	banksel  ADCON0
	movwf	ADCON0
	iorlw	B'11000001'	; right Justify and Vref and Turn on
	movwf	ADCON0
	endif


ADStartConvert

    ; Switches set up - Now wait for the sample and hold capacitor to charge
    ; for a 10k source you need about 20u seconds
	MOVLW	EEAtoDappatureDelay
	CALL	EEread
	CALL 	BTdelayW10us
	
	; Now start the 

	bcf		PIR1,ADIF

	banksel	ADCON0 
	bsf		ADCON0,GO	;Start A/D conversion

ADwait
	btfss	PIR1,ADIF	;Wait for conversion to complete
	goto	ADwait

	nop
	nop

; Read the A to D agains to try to get a bit of stability.

ADStartConvertAgain
	bcf		PIR1,ADIF

	banksel	ADCON0 
	bsf		ADCON0,GO	;Start A/D conversion

ADwaitAgain
	btfss	PIR1,ADIF	;Wait for conversion to complete
	goto	ADwaitAgain

	nop
	nop
	return	


;--------------------------------------------------------------------------
; Sec 5.14	MM ( make measurements ) Routines to use the A to D converter to Measure SolarCell 
;--------------------------------------------------------------------------

;  +----------------	V SolarCell
;  |
;  +--|>|---+-------	Vbattery
;  |        |
;  |        +-[==]--	VLEDresitor
;  |
;  +----------------   0 Volts
;
;  V4 SolarCell
;  V5 Vbattery
;  V6 VLEDresistor
;
;	if V5 > V2+Vdiode then charging
;	if (V2-V3) = Vres
;
;	if Vres > k1 then Bright
;	if Vres < k2 then Off
;	Else Dim
;
	
MMinit
	CLRF	MMcntTimeH
	CLRF	MMcntTimeL
	CLRF	MMcntSolarCellH
	CLRF	MMcntSolarCellL
	CLRF	MMcntBrightH
	CLRF	MMcntBrightL
	CLRF	MMcntDimH
	CLRF	MMcntDimL
	CLRF	MMcntVbattH
	CLRF	MMcntVbattL
	return



MMinitTime
	;
	; time in binary to time when samples are stored in EEPROM
	;
	; If you want to logger to sample at 03:00 and it is 18:00 
	; you want the time to be 
	;	24:00 
	; +	03:00
	; -	18:00 
	;	=====
	;	09:00 9 hours time	
	;
	
;	banksel 	CLhh
;	MOVLW	.24
;	MOVWF	CLhh
	
;	MOVLW	.60
;	MOVWF	CLmm

;	MOVLW	.15
;	MOVWF	CLss


	banksel 	CLhh
	MOVLW	.09+1
;	MOVLW	.00+1
	MOVWF	CLhh
	
	MOVLW	.00+1
	MOVWF	CLmm

	MOVLW	.00+1
	MOVWF	CLss		; CLss is in seconds / seconds between TMR1 timeout




	return


MMstartTicks	
	;Clear and init TMR1, this will be used as a time base.
	banksel T1CON
	CLRF	T1CON
	CLRF	TMR1H
	CLRF	TMR1L
	
	;
	; Start TMR1 to use the external oscillator.
	; This should be a 32K768 Hz crystal, so the overflow is every 2 seconds.
	;
	MOVLW	1 << T1OSCEN | 1 << T1CKPS0 | 1 << NOT_T1SYNC | 1 << TMR1CS | 1 << TMR1ON
	MOVWF	T1CON
	return

MMstopTicks	
	;Clear and init TMR1, this will be used as a time base.
	banksel T1CON
	MOVLW	0 << T1OSCEN | 1 << T1CKPS0 | 1 << NOT_T1SYNC | 1 << TMR1CS | 0 << TMR1ON
	MOVWF	T1CON
	return


MMts
	BANKSEL	PIR1
	BCF		PIR1,TMR1IF

	BCF		PORTC,3

	; tick every 4 seconds 
	; and reset chain for 24 hours timeout
	;
	DECFSZ	CLss,F
	GOTO	MMts1
	MOVLW	.15
	MOVWF	CLss		

	DECFSZ	CLmm,F
	GOTO	MMts1
	MOVLW	.60
	MOVWF	CLmm		

	DECFSZ	CLhh,F
	GOTO	MMts1
	MOVLW	.24
	MOVWF	CLhh		

	; buffer counts once a day.
	CALL	EEfileCounts
	CALL	MMinit
	

MMts1
	MOVLW	EEinterCharDelay		;0x15
	CALL	EEread
	MOVWF	RSinterCharDelay

	CALL 	RS232sendLF
	CALL 	RS232sendCR

	CALL	MMdisplay

	; ouput the counts first, then the voltages 
	; so that the 24Char display shows the counts	
	CALL	MMtsSample
	MOVLW	','
	CALL 	RStxChar

	MOVLW	'*'
	CALL 	RStxChar

	BSF		PORTC,3

	RETURN

	; run into MMtsSample
	

MMtsSample
	; tick once a second
	CALL	MMincCntTime
	
	; Measure VsolarCell
	MOVLW	6 
	movwf	RSaddr
	
	CALL	ADconvert		
	
	banksel  ADRESH
	movfw	ADRESH
	movwf	MMV6h
	banksel  ADRESL
	movfw	ADRESL
	movwf	MMV6l

	MOVLW	MMV6h
	CALL	MMdisplayIndirect


	; Measure Vbattery
	MOVLW	5
	movwf	RSaddr
	
	CALL	ADconvert		
	
	banksel  ADRESH
	movfw	ADRESH
	movwf	MMV5h
	banksel  ADRESL
	movfw	ADRESL
	movwf	MMV5l

	MOVLW	MMV5h
	CALL	MMdisplayIndirect

	
	; Measure VtopOfLED
	MOVLW	4
	movwf	RSaddr
	
	CALL	ADconvert		
	
	banksel  ADRESH
	movfw	ADRESH
	movwf	MMV4h
	banksel  ADRESL
	movfw	ADRESL
	movwf	MMV4l
	
	MOVLW	MMV4h
	CALL	MMdisplayIndirect


	; Measure Vref but relative to Vdd
	MOVLW	1
	movwf	RSaddr

	CALL	ADconvertVdd
	
	banksel  ADRESH
	movfw	ADRESH
	movwf	MMV1h
	banksel  ADRESL
	movfw	ADRESL
	movwf	MMV1l
	
	MOVLW	MMV1h
	CALL	MMdisplayIndirect

	movlw	'/'
	call	RStxChar
	movlw	','


MMtsSampleProcess

	; Subtract MMV6h - MMV5H+eeprom[10]
	; The difference 

	; if MMV6h < MMV5H then Vbat > Vsolar so do not carry on with calc.
	
	
	; 00 00 - 
	; 00 01
	;========
	;    ff
    
	MOVFW	MMV5l
	SUBWF	MMV6l,w	; w = F-W or MM6L-MMV5 -> W
	MOVWF	MMtmp
		
	MOVFW	MMV5h
	; Apply Borrow
	SKPC	
	ADDLW	0x01

	; suntract the difference of the low bytes
	; Note MMV5 - MMV6 to get negative value
	SUBWF	MMV6h,w	; w = F-W or MM6L-MMV5 -> W
	MOVWF	MMtmph	

	;; MMV6 = MMV5 
	;; MMV6 > MMV5

	; Output difference between Solar Call and Vbattery
	; This is the compliment
	
	movlw	'/'
	call	RStxChar
	movlw	's'
	call	RStxChar
	movlw	','
	call	RStxChar

	MOVFW	MMtmph
	CALL	RSwrtWasHex
	
	MOVFW	MMtmp
	CALL	RSwrtWasHex
	
	movlw	','
	call	RStxChar

	
	; V6,V5,V4 use Vref, the voltage across a blue LED
	; Also measure the voltage of the BLUE LED relative to Vref.
	;
	; V6 = 0E0 - Solar cell in darkness
	; V5 = A70 - Vbattery when LED is on bright
	; V4 = 8EC - Vtop of LED when LED is bright
	;
	; Vref = D7C  - Vdd ~ 3.82 Vref=3.25 volts 
	; this right shift reduces the sensitivity
	;

	; 
	; w = w-f
	;
	
	; MMtmp contains Vsolar-Vbat
	; MMtmp = MMtmp - ( 0x0000 + EE[00] )
	MOVLW	EEsolarOffset		;0x00	
	CALL	EEread	; 		
	SUBLW	0		; Negate W

	ADDWF	MMtmp,f
	MOVLW	0xFF		; Assume -ve

	; Apply CARRY
	SKPNC	
	ADDLW	0x01
	
	ADDWF	MMtmph,f

	
	
	; if V6-V5-EEprom[10] < 0 then increment MMincCntSolarCell
	BTFSC	MMtmph,7		; test MSB to see if negative	
	GOTO	MMtsSample1false

MMtsSample1true
	CALL	MMincCntSolarCell
	GOTO	MMtsSample1

MMtsSample1false
	; So Solar Cell is not charging, 
	; Is battery above eeprom[13]and eeprom[14]

	; MMtmp = MM5V - EEPROM[13,14]	
	MOVLW	EEbatteryOffsetL		;0x14
	CALL	EEread			
	SUBWF	MMV5l,w 	;	w=w-f
	MOVWF	MMtmp

	MOVLW	EEbatteryOffsetH	; 0x13
	CALL	EEread			
	; Apply Borrow
	SKPC	
	ADDLW	0x01

	SUBWF	MMV5h,w
	MOVWF	MMtmph

	BTFSS	MMtmph,	7
	CALL	MMincCntVbatt

	GOTO	MMtsSample1


MMtsSample1

	; Subtrac VtopOfLED from Vbatt
	; if Negative, then LED on

	; Subtract MMV5h - MMv4H+eeprom[11]
	; The subtraction really needs the low voltages
	
	;MOVFW	MMv4h
	;SUBWF	MMV5h,w

	; If Vbat < Vtop of Led
	
	
	MOVFW	MMV4l
	SUBWF	MMV5l,w	; w = F-W or MM6L-MMV5 -> W
	MOVWF	MMtmp
		
	MOVFW	MMV4h
	; Apply Borrow
	SKPC	
	ADDLW	0x01

	; suntract the difference of the low bytes
	; Note MMV5 - MMV6 to get negative value
	SUBWF	MMV5h,w	; w = F-W or MM6L-MMV5 -> W
	MOVWF	MMtmph	
	
	; NOTE: MMV4L - MMV5 to get negative value
	MOVFW	MMV4l
	SUBWF	MMV5l,w
	MOVWF	MMtmp

	movlw	'l'
	call	RStxChar
	movlw	','
	call	RStxChar

	MOVFW	MMtmph
	CALL	RSwrtWasHex

	MOVFW	MMtmp
	CALL	RSwrtWasHex
	movlw	','
	call	RStxChar

	;
	; MMtmp contains Voltage across 20R
	;
	; Is LED DIM, BRIGHT or OFF
	; get constants from EEPROM

	; if (V5-V4)-EEprom[11] < 0 then OFF
	MOVLW	EEdimOffset	; 0x11	
	CALL	EEread			
	SUBLW	0 			; W = 0 - W
	ADDWF	MMtmp,f

	; ADD Carry
	MOVLW	0xFF			; promote -ve EE[01] to 0xFFXX 
	SKPNC
	ADDLW	1
	ADDWF	MMtmph,f
		
	BTFSC	MMtmph,7	
	;	Not +ve so dim constant not reached
	RETURN
	
	; If Still +ve, then the LED is Bright or DIM
	; Subtract a bit more off
	; Subtract some to see if it is bright or dim.
	
	MOVLW	EEbrightOffset	; 0x12	
	CALL	EEread			
	SUBLW	0 			; W = 0 - W
	ADDWF	MMtmp,f

	; ADD Carry
	MOVLW	0xFF			; promote -ve EE[02] to 0xFFXX
	SKPNC
	ADDLW	1
	ADDWF	MMtmph,f
	
	BTFSC	MMtmph,7	
	GOTO	MMincCntDim
	GOTO	MMincCntBright
	
MMincCntTime
	incfsz	MMcntTimeL
	return
	incf	MMcntTimeH,f
	return

MMincCntSolarCell
	incfsz	MMcntSolarCellL
	return
	incf	MMcntSolarCellH,f
	return

MMincCntBright
	incfsz	MMcntBrightL
	return
	incf	MMcntBrightH,f
	return

MMincCntDim
	incfsz	MMcntDimL
	return
	incf	MMcntDimH,f
	return

MMincCntVbatt
	incfsz	MMcntVbattL
	return
	incf	MMcntVbattH,f
	return


MMdisplay
	MOVLW	MMcntTimeH
	CALL	MMdisplayIndirect

	MOVLW	MMcntSolarCellH
	CALL	MMdisplayIndirect

	MOVLW	MMcntBrightH
	CALL	MMdisplayIndirect

	MOVLW	MMcntDimH
	CALL	MMdisplayIndirect

	MOVLW	MMcntVbattH
	CALL	MMdisplayIndirect
	

	;
	; Display -
	;

	movlw	'/'
	call	RStxChar

	movlw	't'
	call	RStxChar

	movlw	','
	call	RStxChar


	banksel	CLhh
	MOVLW	CLhh
	CALL	MMdisplayIndirectThreeByte
	return



MMdisplayIndirectThreeByte
	; display file pointed to by W as 4 HEX nibbles.
	; ;	MOVLW	MMcntTimeH
	; ;	CALL	MMdisplayIndirect

	; move address of file into FSR and then use INDF to get values.
	MOVWF	FSR

	SWAPF	INDF,w
	CALL	RSwrtHexNibble

	MOVFW	INDF
	CALL	RSwrtHexNibble

	; now increment point onto next byte
	INCF	FSR,W


MMdisplayIndirect
	; display file pointed to by W as 4 HEX nibbles.
	; ;	MOVLW	MMcntTimeH
	; ;	CALL	MMdisplayIndirect

	; move address of file into FSR and then use INDF to get values.
	MOVWF	FSR

	SWAPF	INDF,w
	CALL	RSwrtHexNibble

	MOVFW	INDF
	CALL	RSwrtHexNibble

	; now increment point onto next byte
	INCF	FSR,W

MMdisplayIndirectOneByte
	MOVWF	FSR

	SWAPF	INDF,w
	CALL	RSwrtHexNibble

	MOVFW	INDF
	CALL	RSwrtHexNibble
	
	movlw	','
	call	RStxChar
	
	RETURN
	

;--------------------------------------------------------------------------
; Sec 5.15	EE Routines to copy the counts into the EEPROM 
;--------------------------------------------------------------------------
;
;
;MMcntTimeH
;MMcntTimeL
;MMcntSolarCellH
;MMcntSolarCellL
;MMcntBrightH
;MMcntBrightL
;MMcntDimH
;MMcntDimL
;MMcntVbattH
;MMcntVbattL
;
; Copy the bytes into the EEPROM.
; Use the value at 0x17 as a pointer 
; If the file pointer gets too big just return
; 
;

EEfileCounts

	;


	MOVLW	EEFILEPTR
	CALL	EEread			

	MOVWF	EEptrEEPROM
	
	; Add some overflow protection
	ADDLW	-(0x7f-(MMcntVbattL-MMcntTimeH+1))
	SKPNC
	RETURN
		
	MOVLW	MMcntVbattL-MMcntTimeH+1
	MOVWF	EEloopCount

	MOVLW	MMcntTimeH
	MOVWF	FSR

EEfileCounts1

	MOVFW	EEptrEEPROM
	CALL	EEsetAddr

	MOVFW	INDF
	CALL	EEwrt
	
	BANKSEL	EEptrEEPROM
	INCF	EEptrEEPROM,f
	INCF	FSR,f
	
	DECFSZ	EEloopCount
	GOTO	EEfileCounts1

	; now update the EEPROM pointer.
	; There is no overflow test.	
	MOVLW	EEFILEPTR	
	CALL	EEsetAddr
	MOVFW	EEptrEEPROM
	CALL	EEwrt
	
	RETURN
	
	
	
;EEptrEEPROM	; pointer to EEPROM
;EEptrMEM	; pointer to Memory - count, time, solarCell, bright, dim 

	

;*************************************************
;  	Upload the DDATA from the logger

EEfileDump
	CALL	RS232sendCR
	CALL	RS232sendLF

	CALL	RS232sendStar
	CALL	RS232sendCR
	CALL	RS232sendLF

	MOVLW	EEFILEPTR
	CALL	EEread			
	CALL	RSwrtWasHex
	CALL	RS232sendComma

	MOVLW	EEFILESTART
	MOVWF	EEptrEEPROM
		
BA0
	CALL	BA4_addrToRS232

	MOVLW	(MMcntVbattL-MMcntTimeH)/2+1
	MOVWF	EEloopCount
BA2		

	MOVFW	EEptrEEPROM
	CALL	EEread			
	CALL	RSwrtWasHex

	INCF 	EEptrEEPROM,f
	MOVFW	EEptrEEPROM
	CALL	EEread			
	CALL	RSwrtWasHex

	CALL	RS232sendComma
	INCF 	EEptrEEPROM,f
	MOVFW	EEptrEEPROM
	; Add some overflow protection
	ADDLW	-(0x7f-(MMcntVbattL-MMcntTimeH+1))
	SKPNC
	GOTO	BA3

	DECFSZ	EEloopCount,f		
	GOTO	BA2
	GOTO	BA0

			
BA3
	CALL	RS232sendComma
	CALL	RS232sendStar
	CALL	RS232sendCR
	CALL	RS232sendLF
	RETURN		




BA4_addrToRS232		
	CALL	RS232sendStar
	CALL	RS232sendCR
	CALL	RS232sendLF
		
	SWAPF	EEptrEEPROM,W
	CALL	RSwrtHexNibble
	MOVFW	EEptrEEPROM
	CALL	RSwrtHexNibble
	CALL	RS232sendComma
	CALL	RS232sendComma
	RETURN




	
;--------------------------------------------------------------------------
; Sec 6.0		Interrupt Routines
;--------------------------------------------------------------------------

Intrtn		
		RETFIE

;--------------------------------------------------------------------------
; Program End
;--------------------------------------------------------------------------
	ifdef pic12F675
	
	org	0x3FD
	RETLW	0x6C
	RETLW	0x6C
OscCalValue	
	RETLW	0x6C
	endif

	ifdef pic16F676


; Read from the chip being used.
; 34A8
	
	org	0x3FD
	RETLW	0x6C
	RETLW	0x6C
OscCalValue	
;	RETLW	0x80 ; first chip
;	RETLW	0xA8 ; second chip
	RETLW	0x98 ; first chip

	endif


LastProgWord

;--------------------------------------------------------------------------
; Sec 7.0		EEPROM data
;--------------------------------------------------------------------------
EEsolarOffset		EQU 0x00
EEdimOffset		EQU 0x01	
EEbrightOffset	EQU 0x02	
EEbatteryOffsetH	EQU 0x03
EEbatteryOffsetL	EQU 0x04
EEinterCharDelay	EQU 0x05
EEAtoDappatureDelay	 EQU	0x06

		ORG	0x2100
		; solar,off,bright/dim,Timer 61=~41 seconds ticks 1e6/2^16m = 1/15.2587890625	
		DE	0x33		; EEsolarOffset 	; delta Vsolar-Vbattery
		DE	0x14		; EEdimOffset		; delta Vbattery-VtopOfLED - thresehold of DIM
		DE	0x10		; EEbrightOffset	; Subtract this to see if BRIGHT
		DE	0x02		; EEbatteryOffsetH	; VbattH
		DE	0x50		; EEbatteryOffsetL	; VbattL
		DE	0x08		; EEinterCharDelay	; inter sample delay 0x3d = 4 seconds
		DE	0x0A		; EEAtoDappatureDelay	; Appature delay - time from setting up switches to start of sample and hold.
		

		ORG	0x2107
		DE	EEFILEPTR+1		; INIT pointer to EEPROM file.

	cblock 	
LastVar
	endc
               END


