
VERSIONSTRING equ "Money v1.02"

!
! Filename:     money.asm
! Module name:  Money
! Description:  coke money board driver
!
! Commands:
!   string QueryVersion () - query version string
!   SetCREMs (byte cremstate) - set CREMs on or off
!   SetLight (byte lightstate) - turn exact change lite on or off
!   AllowPurchase () - allow a purchase with the next button press
!   ReleaseNickel () - spit a nickel out of the coke machine
!   CheckNickelTube () - fail if nickel tube is empty
!   
! IPC:
!   none
!
! Timers:
!   TIMER_Money_CREMs - timer for refreshing CREMs
!   TIMER_Money_Purchase - timer for purchase pulse
!   
! Hooks:
!   HOOK_USER - interrupt hook for switch checking/debouncing
!
! Comments:
!   none yet.
!
! Hardware Notes:
!   Reading from PORT_Money returns (all active high):
!     D0 = motor switch
!     D1 = tube empty switch
!     D2 = nickel inserted switch
!     D3 = dime inserted switch
!   Write to PORT_Money this fine data (all active high):
!     D0 = CREM timer reset
!     D1 = Purchase pulse
!     D2 = Motor active
!     D3 = Exact change light
!
!   A quarter being inserted is indicated by both nickel and
!   dime inserted switches simultaneouly.
!
! History:
!   bv 6/22/99	- initial revision
!   bv 7/15/99	- updated for new IPC style

	include <coke/coke.inc>

; direct page variables

money_portvalue		equ DIRPAGE_Money
money_nickelcount	equ DIRPAGE_Money+$1
money_motoractive	equ DIRPAGE_Money+$2
money_cremsactive	equ DIRPAGE_Money+$3
money_debouncestate 	equ DIRPAGE_Money+$4
money_state		equ DIRPAGE_Money+$5

money_debounce0		equ DIRPAGE_Money+$6
money_debounce1		equ DIRPAGE_Money+$7
money_debounce2		equ DIRPAGE_Money+$8


; constants

BIT_motorswitch 	equ #$01
BIT_tubeswitch		equ #$02
BIT_nickelswitch	equ #$04
BIT_dimeswitch		equ #$08
BIT_cremreset		equ #$01
BIT_purchase		equ #$02
BIT_motor		equ #$04
BIT_light		equ #$08

CREMTIMEOUT		equ 7
PURCHASEPULSETIME	equ 25
DEBOUNCETIME		equ 3	; 3 debounce cycles, at 8 ms each...
MONEY_MASK		equ %00001111 	; four active bits

; EntryPoint

EntryPoint	subroutine
	cmpa	#IPC_Coke_Hello
	beq	.init
	cmpa	#IPC_Coke_Goodbye
	beq	.free
	sec
	rts

.init
	clra				; clear stuff
	staa	PORT_Money
	staa	money_portvalue
	staa	money_nickelcount
	staa	money_motoractive
	staa	money_cremsactive

	ldx	#CommandTable		; install the command table
	jsr 	Coke_InstallCommandTable
	
	ldaa	#ID_Money		; install IPC handler
	ldx	#EntryPoint
	jsr	Coke_RegisterIPC

	ldaa	#TIMER_Money_CREMs	; install the CREM refresh timer
	ldx	#CREMsTimerFunction
	ldy	#CREMTIMEOUT
	jsr	Coke_SetTimer

	ldaa	#HOOK_USER		; install the hook routine
	ldx	#HookFunctionEnd
	jsr	Coke_InstallHook
	clc
	rts

.free
	ldaa	#HOOK_USER		; remove interrupt hook
	ldx	#HookFunctionEnd
	jsr	Coke_RemoveHook
	ldaa	#TIMER_Money_CREMs	; remove timers
	jsr	Coke_RemoveTimer
	ldaa	#TIMER_Money_Purchase
	jsr	Coke_RemoveTimer
	ldx	#CommandTable		; remove commands
	jsr	Coke_RemoveCommandTable
	ldaa	#ID_Money		; remove IPC handler
	jsr	Coke_UnregisterIPC
	clra				
	staa	PORT_Money
	clc
	rts


; Command_SetCREMs (byte cremstate)

Command_SetCREMs subroutine
	jsr	Coke_GetChar		; get the param
	staa	money_cremsactive	; store it for the timer function
	ldaa	#COKE_ACK
	rts


; Command_SetLight (byte lightstate)

Command_SetLight subroutine
	jsr	Coke_GetChar			; get the param
	tsta					; on or off?
	beq	.off
	bset	money_portvalue, #BIT_light	; if on, set the bit
	bra	.set
.off
	bclr	money_portvalue, #BIT_light	; if off, clear the bit
.set
	sei
	ldaa	money_portvalue			; write it out
	staa	PORT_Money
	cli

	ldaa	#COKE_ACK
	rts


; Command_AllowPurchase ()

Command_AllowPurchase subroutine
	bset	money_portvalue, #BIT_purchase	; set the purchase pulse bit
	sei
	ldaa	money_portvalue			; write it out
	staa	PORT_Money
	cli

	ldaa	#TIMER_Money_Purchase		; install the timer 
	ldx	#PurchaseTimerFunction
	ldy	#PURCHASEPULSETIME
	jsr	Coke_SetTimer

	ldaa	#COKE_ACK			
	rts


; Command_ReleaseNickel ()

Command_ReleaseNickel subroutine
	inc	money_nickelcount	; say there's one more nickel
					; to be released
	ldaa	#COKE_ACK
	rts


; Command_CheckNickelTube ()

Command_CheckNickelTube subroutine
	ldaa	PORT_Money		; get data from board
	bita	#BIT_tubeswitch		; is the tube empty?
	bne	.fail			; if so, fail
	ldaa	#COKE_ACK		; otherwise, succeed
	rts
.fail
	ldab	#ERROR_Money_NickelTubeEmpty
	ldaa	#COKE_FAIL
	rts


; PurchaseTimerFunction clears the purchase bit.

PurchaseTimerFunction subroutine
	psha

	bclr	money_portvalue, #BIT_purchase	; clear Mr. Bit
	sei
	ldaa	money_portvalue			; write it out
	staa	PORT_Money
	cli

	ldaa	#TIMER_Money_Purchase		; remove this timer
	jsr	Coke_RemoveTimer

	pula
	rts	


; CREMsTimerFunction refreshes the CREM timer and allows change to be
; deposited.

CREMsTimerFunction subroutine
	tst	money_cremsactive	; should crems be refreshed?
	beq	.done			; if not, leave.

	psha
	pshb

	sei				; we don't want to be interrupted
	ldaa	money_portvalue
	oraa	#BIT_cremreset		; set the crem reset bit
	staa	PORT_Money		; write it out
	mul				; wait a little while for the
	mul				; capacitor to drain
	mul
	ldaa	money_portvalue
	staa	PORT_Money
	cli

	pulb
	pula
.done
	rts


; _debounce macro is used to detect and debounce a particular switch.
; _debounce #bitmask money_debouncevariable #MESSAGE_MoneyInserted
;           #otherbitmask
;
; For the nickel and dime switches, a message is sent when the switch
; is hit.  For the motor switch, a message is sent when it is releasd.
;

	mac _debounce

	brset	money_debouncestate ,{1},.debounce
					; are we debouncing this bit?
	bitb	{1}			; did this bit change from last time?
	beq	.endbit
	clr	{2}			; set debounce count
	bset	{2}, #DEBOUNCETIME
	bset	money_debouncestate ,{1} ; say that we are debouncing it
	bra	.endbit
.debounce
	bitb	{1}			; is the bit different than its state?
	bne	.stilldifferent
	bclr	money_debouncestate ,{1}	; if not, forget about it!
	bra	.endbit
.stilldifferent
	dec	{2}			; lower debouncecount
	bne	.endbit			; if not zero, we're outa here
	bclr	money_debouncestate ,{1}	; we win!  clear debounce state
	bita	{1}			; is it being hit or released?
	beq	.zero

	bset	money_state, {1}	; if hit, set state bit

	if	{3} != 0		; nickel or dime debounce code...
	bita	{4}			; check if the other switch is down
	xgdx				; stash stuff in x
	beq	.onlyone
	bset	money_state, {4}		; if so, set it prematurely
	bclr	money_debouncestate, {4}	; and clear its debounce
	ldaa	#MESSAGE_Money_QuarterInserted
	bra	.msg				; and send the quarter message
.onlyone
	ldaa	{3}		; otherwise, send the single coin message
.msg
	jsr	Coke_SendMessage
	xgdx
	endif				; end nickel or dime code

	bra	.endbit

.zero
	bclr	money_state, {1}		; if release, clear state bit
	if	{3} == 0			; motor switch code...
	bclr	money_portvalue, #BIT_motor
	ldaa	money_portvalue
	staa	PORT_Money
	clr	money_motoractive		; clear the motor active flag
	endif					; end motor switch code
.endbit
	endm


; HookFunction is called during an interrupt proc to scan and
; debounce the switches, and take the appropriate actions.

HookFunction	subroutine
	tst	money_nickelcount	; any nickels to be released?
	beq	.nonickels
	tst	money_motoractive	; are we already all over it?
	bne	.nonickels

	bset	money_portvalue, #BIT_motor	
	ldaa	money_portvalue		; set the motor bit
	staa	PORT_Money		; turn on the motor
	dec	money_nickelcount	; one less nickel
	inc	money_motoractive	; motor is active now.
.nonickels

	ldaa	PORT_Money		; get the current switch state
	anda	#MONEY_MASK		; set inactive bits to 0
	eora	#1

	tab				; put press in b
	eorb	money_state		; put xor between press and state in b
	bne	HookDosomething		; if not the same, do something
	tst	money_debouncestate	; are we debouncing anything?
	bne	HookDosomething		; if not, we leave early
HookFunctionEnd
	_endhook HookFunction

HookDosomething

	_debounce #$4, money_debounce0, #MESSAGE_Money_NickelInserted, #$8
	_debounce #$8, money_debounce1, #MESSAGE_Money_DimeInserted, #$4
	_debounce #$1, money_debounce2, #$0, #$0

	jmp	HookFunctionEnd
	

; version stuff

	_versionstuff

; command table

CommandTable
	dc.b	CMD_Money_QueryVersion
	dc.w	Command_QueryVersion
	dc.b	CMD_Money_SetCREMs
	dc.w	Command_SetCREMs
	dc.b	CMD_Money_SetLight
	dc.w	Command_SetLight
	dc.b	CMD_Money_AllowPurchase
	dc.w	Command_AllowPurchase
	dc.b	CMD_Money_ReleaseNickel
	dc.w	Command_ReleaseNickel
	dc.b	CMD_Money_CheckNickelTube
	dc.w	Command_CheckNickelTube

	dc.b	0


; data segment

