
VERSIONSTRING equ "Doodad v2.02"

!
! Filename:     doodad.asm
! Module name:  Doodad
! Description:  doodad and clock display driver
!
! Commands:
!   string QueryVersion () - retrieve version string
!   SetTime (byte minutes, byte hours) - set clock
!   SetTime2 (word minutes) - set clock to number of minutes since midnight
!   IncTime () - increment clock one minute
!   StartAutoTime () - start clock auto-update
!   StopAutoTime () - stop clock auto-update
!   SetDoodad (byte pattern) - set doodad pattern
!   StartDoodadSequence () - start the current doodad sequence
!   StopDoodadSequence () - stop the current doodad sequence
!   SetDoodadSequence (pstring sequence) - set the current doodad sequence
!   SetDoodadSequenceResource (byte rezID) - set doodad sequence to resource
!   SetDoodadSequenceSpeed (word speed) - set doodad sequence speed
!
! IPC:
!   none
!
! Timers:
!   TIMER_Doodad - timer for doodad sequence
!   TIMER_Clock - timer for clock auto-update
!
! Hooks:
!   none
!
! Comments:
!   none :)
!
! Hardware notes:
!   To control the display, write a byte to PORT_Doodad:
!    bit 7:   clock count (pulse to count up one)
!    bit 6:   green doodad LED, active high
!    bit 5-1: red doodad LEDs (I forget which order) active high
!    bit 0:   clock /reset, active low
!
! History:
!   bv 9/16/98	- initial revision
!   bv 9/17/98	- added auto-inc stuff
!   bv 5/28/99	- converted to cokeOS v3 module
!   bv 6/16/99	- updated for new response style
!   bv 7/16/99	- updated for new IPC style

	include <coke/coke.inc>


; EntryPoint

EntryPoint	subroutine
	cmpa	#IPC_Coke_Hello
	beq	.init
	cmpa	#IPC_Coke_Goodbye
	beq	.free
	sec
	rts
.init
	clra
	clrb
	jsr	SetPattern	; clear doodad pattern
	jsr	SetTime		; set time to 12:00
	ldx	#CommandTable	; install command table
	jsr	Coke_InstallCommandTable
	ldaa	#ID_Doodad	; register IPC
	ldx	#EntryPoint
	jsr	Coke_RegisterIPC
	clc
	rts		
.free
	ldx	#CommandTable	; remove commands
	jsr	Coke_RemoveCommandTable
	ldaa	#TIMER_Clock	; remove timers
	jsr	Coke_RemoveTimer
	ldaa	#TIMER_Doodad
	jsr	Coke_RemoveTimer
	ldaa	#ID_Doodad	; remove IPC
	jsr	Coke_UnregisterIPC
	clc
	rts


; Doodad_SetTime sets the clock to the given time.  The time to set
; is given as the number of minutes since midnight.
; time to set is in d.

SetTime subroutine
	psha
	pshb
	pshx

	cpd	#60		; is the time less than 1:00?
	bhs	.not12		; if not, don't worry
	addd	#720		; if so, adjust to 12:xx
.not12
	std	doodad_time	; store the time value

	ldaa	doodad_pattern	; get pattern for low 6 bits
	anda	#$FE		; make /reset active (clear lo bit)
	staa	PORT_Doodad	; clear the display
	oraa	#$01		; stop clearing display
	staa	PORT_Doodad	; (/reset is high again)
	
	ldx	doodad_time	; get the time to count down
.countloop
	oraa	#$80		; set the count bit
	staa	PORT_Doodad	; increment the clock
	anda	#$7F		; clear the count bit
	staa	PORT_Doodad	; and write it
	dex			; decrement counter
	bne	.countloop	; if not done, keep at it

	pulx	
	pulb
	pula
	rts


; Doodad_IncTime increments the time by one minute.  It is smart -- it handles
; going from 12:59 to 1:00 and stuff.

IncTime subroutine
	psha
	pshb

	inc	doodad_time+1	; increment lo byte
	bne	.nocarry	; is it now zero?
	inc	doodad_time	; if so, increment hi byte
.nocarry
	ldd	doodad_time
	cpd	#780		; is it 13:00?
	blo	.noadjust	; if not, it's all cool
	ldd	#60		; if so, set it to 1:00
	jsr	SetTime		; and set it manually
	bra	.incdone	; that's it.
.noadjust
	ldaa	doodad_pattern	; get the pattern (lo bit is set)
	oraa	#$81		; set count
	staa	PORT_Doodad	; write it out
	anda	#$7F		; clear count bit
	staa	PORT_Doodad	; write it out
.incdone
	pulb
	pula
	rts


; Doodad_SetPattern sets the doodad pattern to the low six bits of the
; given value.
; pattern is in a.

SetPattern subroutine
	psha
	anda	#$3F		; clear out unused bits	
	sec			; shift in a 1 for /reset
	rola			; shift to compensate for hardware flaw
	staa	doodad_pattern	; store the thingee
	staa	PORT_Doodad	; write to the doodad
	pula
	rts


; Command_SetTime (minutes byte) (hours byte)

Command_SetTime subroutine
	jsr	Coke_GetChar	; get minutes
	psha			; stash it on stack
	jsr	Coke_GetChar	; get hours
	ldab	#60		; prepare to multiply by 60
	mul			; result is in d
	xgdx			; put result in x
	pulb			; put minutes in b
	abx			; add to mul result
	xgdx			; put whole shebang back in d
	jsr	SetTime		; set that there time
	ldaa	#COKE_ACK
	rts


; Command_SetTime2 (word minutes) 

Command_SetTime2 subroutine
	jsr	Coke_GetChar	; get lobyte
	tab			; put it in b
	jsr	Coke_GetChar	; get hibyte
	jsr	SetTime		; set the time
	ldaa	#COKE_ACK
	rts


; Command_IncTime ()

Command_IncTime subroutine
	jsr	IncTime		; inc the time
	ldaa	#COKE_ACK
	rts


; Command_StartAutoTime ()

Command_StartAutoTime subroutine
	ldx	#IncTime	; set a timer function to inc the clock
	ldy 	#7324
	ldaa	#TIMER_Clock
	jsr	Coke_SetTimer
	ldaa	#COKE_ACK
	rts


; Command_StopAutoTime ()

Command_StopAutoTime subroutine
	ldaa	#TIMER_Clock	; kill the timer function
	jsr	Coke_RemoveTimer
	ldaa	#COKE_ACK
	rts


; Command_SetDoodad (byte pattern)

Command_SetDoodad subroutine
	jsr	Coke_GetChar	; get the pattern
	jsr	SetPattern	; set it
	ldaa	#COKE_ACK
	rts


; Command_StartDoodadSequence ()

Command_StartDoodadSequence subroutine
	ldx	#DoodadTimerFunction	; start a timer to do the doodad
	ldy	doodad_speed
	ldaa	#TIMER_Doodad
	jsr	Coke_SetTimer
	ldaa	#COKE_ACK
	rts


; Command_StopDoodadSequence ()

Command_StopDoodadSequence subroutine
	ldaa	#TIMER_Doodad		; stop the doodad timer
	jsr	Coke_RemoveTimer
	ldaa	#COKE_ACK
	rts


; Command_SetDoodadSequence (byte length, [pattern bytes])

Command_SetDoodadSequence subroutine
	ldx	#doodad_buffer	; get the pointer to the buffer
	jsr	Coke_GetChar	; get sequence length
	tab			; put it in b for counting
	beq	.done		; if zero, then we go away now.
	staa	doodad_seqlength ; store it
	stx	doodad_startptr	; store in the ptr to start of sequence
	stx	doodad_currentptr	; store in the ptr to current position
.getloop
	jsr	Coke_GetChar	; get the pattern
	staa	0,x		; store it in the buffer
	inx			; increment pointer
	decb			; dec the counter
	bne	.getloop	; if not done, keep going
.done
	ldaa	#COKE_ACK
	rts


; Command_SetDoodadSequenceResource (byte resource id)

Command_SetDoodadSequenceResource subroutine
	jsr	Coke_GetChar		; get the rez id
	tab				; put into b
	jsr	Resource_GetResource	; get res pointer in x
	bcs	.badres			; if bad resource, quit now
	jsr	Resource_GetLength	; get length of sequence in d (b)
	stab	doodad_seqlength
	ldy	#doodad_buffer		; get the pointer to the buffer
	sty	doodad_startptr		; store in the ptr to start of seq
	sty	doodad_currentptr	; store in the ptr to cur position
.getloop
	ldaa	0,x			; get the character from the resource
	staa	0,y			; store it in the buffer
	inx				; increment pointer
	iny				; increment pointer
	decb				; dec the counter
	bne	.getloop		; if not done, keep going
.exit
	ldaa	#COKE_ACK
	rts
.badres
	ldab	#ERROR_Coke_BadResourceID
	ldaa	#COKE_FAIL
	rts
	

; Command_SetDoodadSequenceSpeed (word speed)

Command_SetDoodadSequenceSpeed subroutine
	jsr	Coke_GetChar		; get the paramater
	tab
	jsr	Coke_GetChar
	std	doodad_speed		; set the speed
	ldaa	#COKE_ACK
	rts


; DoodadTimerFunction

DoodadTimerFunction subroutine
	ldx	doodad_currentptr	; get pointer to the current pattern
	ldaa	0,x			;  get the pattern
	jsr	SetPattern		; set the pattern

	inx				; next pattern byte
	stx	doodad_currentptr	; store it
	xgdx				; put into d
	subd	doodad_startptr		; subtract start pointer
	cmpb	doodad_seqlength	 ; is it too big?
	blo	.done
	
	ldx	doodad_startptr		; if so, wrap to beginning
	stx	doodad_currentptr
.done
	rts
	

; version stuff

	_versionstuff

; command table

CommandTable subroutine
	dc.b	CMD_Doodad_QueryVersion
	dc.w	Command_QueryVersion
	dc.b	CMD_Doodad_SetTime
	dc.w	Command_SetTime
	dc.b	CMD_Doodad_SetTime2
	dc.w	Command_SetTime2	
	dc.b	CMD_Doodad_IncTime
	dc.w	Command_IncTime
	dc.b	CMD_Doodad_StartAutoTime
	dc.w	Command_StartAutoTime
	dc.b	CMD_Doodad_StopAutoTime
	dc.w	Command_StopAutoTime
	dc.b	CMD_Doodad_SetDoodad
	dc.w	Command_SetDoodad
	dc.b	CMD_Doodad_StartDoodadSequence
	dc.w	Command_StartDoodadSequence
	dc.b	CMD_Doodad_StopDoodadSequence
	dc.w	Command_StopDoodadSequence
	dc.b	CMD_Doodad_SetDoodadSequence
	dc.w	Command_SetDoodadSequence
	dc.b	CMD_Doodad_SetDoodadSequenceResource
	dc.w	Command_SetDoodadSequenceResource
	dc.b	CMD_Doodad_SetDoodadSequenceSpeed
	dc.w	Command_SetDoodadSequenceSpeed

	dc.b	0


; data segment

doodad_buffer
	dc.b	%00000001
	dc.b	%00000010
	dc.b	%00000100
	dc.b	%00001000
	dc.b	%00010000
	dc.b	%00100001
	dc.b	%00100010
	dc.b	%00100100
	dc.b	%00101000
	dc.b	%00110000
	ds	250

doodad_seqlength 	dc.b 10
doodad_currentptr 	dc.w doodad_buffer
doodad_startptr 	dc.w doodad_buffer
doodad_speed		dc.w 8
doodad_pattern		dc.b 0
doodad_time		dc.w 0
