
;
; Copyright (c) 1988 Commodore-Amiga, Inc.
;
; Executables based on this information may be used in software
; for Commodore Amiga computers.  All other rights reserved.
;
; This information is provided "as is"; no warranties are made.
; All use is at your own risk, and no liability or responsibility is assumed.
;

		SECTION	example,CODE
;=============================================================================
; An example to write to the CLI window every second until CTRL/C is pressed.
;=============================================================================
		NOLIST
		INCLUDE	"exec/types.i"
		INCLUDE	"exec/memory.i"
		INCLUDE	"exec/interrupts.i"
		INCLUDE	"hardware/intbits.i"
		INCLUDE	"libraries/dos.i"
		LIST

; first we define the global data we will be using throughout the program
	STRUCTURE globals,0
		APTR	SysLib		exec library base
		APTR	DosLib		dos library base
		APTR	IntServer	pointer to our interrupt server
		UWORD	Ticks		number of ticks that occured
		ULONG	OutHandle	the output file handle for writing
		APTR	ThisTask	current task address
		ULONG	WaitMask	sigs we will wait for
		ULONG	TickMask	what int handler signals task with
	LABEL globals_SIZEOF

; now we define what external library routines we will be using in this code
		XREF	_AbsExecBase,_LVOOpenLibrary,_LVOCloseLibrary
		XREF	_LVOAllocMem,_LVOFreeMem,_LVOFindTask
		XREF	_LVOAddIntServer,_LVORemIntServer
		XREF	_LVOAllocSignal,_LVOWait,_LVOSignal
		XREF	_LVOOutput,_LVOWrite

;============================================================================
;Standard initialisation to get the global data space and libraries required
;============================================================================
Main		moveq.l	#(globals_SIZEOF/2)-1,d0
10$		clr.w	-(sp)			clear global space
		dbra	d0,10$
		movea.l	sp,a5			a5 always points to globals
		movea.l	_AbsExecBase,a6		get exec.library base
		move.l	a6,SysLib(a5)		and stash it for later

		lea.l	DosName(pc),a1		open dos.library
		moveq.l	#33,d0			version 33 or greater
		jsr	_LVOOpenLibrary(a6)
		move.l	d0,DosLib(a5)		save the pointer
		beq	Exit			didn't get it

;============================================================================
; now get the memory for the interrupt server and initialise the data area
;============================================================================
		moveq.l	#IS_SIZE,d0		size of server node
		move.l	#MEMF_PUBLIC!MEMF_CLEAR,d1
		jsr	_LVOAllocMem(a6)	get some memory for it
		move.l	d0,IntServer(a5)	save pointer to server
		beq	Exit			didn't get server memory
		movea.l	d0,a1			fill in the structure
		move.b	#NT_INTERRUPT,LN_TYPE(a1)  set the node type
		move.b	#20,LN_PRI(a1)		set priority of the server
		lea.l	IntServerName(pc),a0	set up a name for the node
		move.l	a0,LN_NAME(a1)
		move.l	a5,IS_DATA(a1)		server can see globals
		lea.l	IntServerCode(pc),a0	set up pointer to the code
		move.l	a0,IS_CODE(a1)		in server init complete
		
;============================================================================
; do all the DOS initialisation to find the output handle and write a message
;============================================================================
		movea.l	DosLib(a5),a6		using dos library now
		jsr	_LVOOutput(a6)		get output file handle
		move.l	d0,OutHandle(a5)	and save it
		move.l	d0,d1			writing to stdout
		lea.l	Msg1(pc),a0
		move.l	a0,d2			pointer to msg in d2
		moveq.l	#Msg1End-Msg1,d3	length in d3
		jsr	_LVOWrite(a6)		write out the message

;============================================================================
; get a signal bit that the interrupt server can signal us with every second
;============================================================================
		movea.l	SysLib(a5),a6		using exec.library again
		moveq.l	#-1,d0			any signal will do
		jsr	_LVOAllocSignal(a6)
		moveq.l	#0,d1			convert signum to a mask
		bset.l	d0,d1
		move.l	d1,TickMask(a5)		and save it for int server
		ori.l	#SIGBREAKF_CTRL_C,d1	we're waiting for CTRL/C too
		move.l	d1,WaitMask(a5)		stash combined sig bits

;============================================================================
; generate a pointer to this task so that the interrupt server can find us.
;============================================================================
		suba.l	a1,a1			find this task
		jsr	_LVOFindTask(a6)
		move.l	d0,ThisTask(a5)		and stash the address

;============================================================================
; now that everything is initialised, its safe to add the interrupt server
;============================================================================
		move.w	#60,Ticks(a5)		initialise tick count
		movea.l	IntServer(a5),a1	get the intserver node
		moveq.l	#INTB_VERTB,d0		hooking into VBlank int
		jsr	_LVOAddIntServer(a6)	start it up

;============================================================================
; The main loop of this program. Waits for a signal from the interrupt server
; or from the user pressing CTRL/C and does the appropriate things.
;============================================================================
WaitLoop	move.l	SysLib(a5),a6		using exec for Wait
		move.l	WaitMask(a5),d0		get sigs we are waiting for
		jsr	_LVOWait(a6)		go to sleep
		btst.l	#SIGBREAKB_CTRL_C,d0	did we get a CTRL/C ?
		bne.s	Stopped			yes, exit the program

;============================================================================
; we were woken up by the interrupt routine so print out the word tick!
;============================================================================
		movea.l	DosLib(a5),a6		using dos.library again
		move.l	OutHandle(a5),d1	writing to CLI window
		lea.l	Msg2(pc),a0		printing this message
		move.l	a0,d2
		moveq.l	#Msg2End-Msg2,d3	this length
		jsr	_LVOWrite(a6)		write the message out
		bra.s	WaitLoop		and wait for more signals

;============================================================================
; user pressed CTRL/C so remove interrupt server and print the done message.
;============================================================================
Stopped		movea.l	SysLib(a5),a6		using exec.library
		movea.l	IntServer(a5),a1	removing this int server
		moveq.l	#INTB_VERTB,d0		from this server chain
		jsr	_LVORemIntServer(a6)	remove it

		movea.l	DosLib(a5),a6		now write out the done msg
		move.l	OutHandle(a5),d1	writing to the CLI window
		lea.l	Msg3(pc),a0		printing this message
		move.l	a0,d2
		moveq.l	#Msg3End-Msg3,d3	this length
		jsr	_LVOWrite(a6)		write it out

;============================================================================
; The main exit point of this program.  It uses the fact that the global
; memory is zeroed at startup time to determine which resources have been
; opened or allocated.  Cleanup is done in the same order as initialisation
; so that as soon as a zero value is found, cleanup is considered complete.
;============================================================================
Exit		movea.l	SysLib(a5),a6		using exec for cleanups
		tst.l	DosLib(a5)		did we get dos.library ?
		beq.s	ReallyExit		no more cleanup needed
		movea.l	DosLib(a5),a1		close dos library
		jsr	_LVOCloseLibrary(a6)

		tst.l	IntServer(a5)		did we get mem for intserver
		beq.s	ReallyExit		no, so no more cleanup
		movea.l	IntServer(a5),a1	free server memory
		moveq.l	#IS_SIZE,d0
		jsr	_LVOFreeMem(a6)

;============================================================================
; and the final exit point that cleans up our globals off the stack area.
;============================================================================
ReallyExit	lea.l	globals_SIZEOF(sp),sp	reclaim stack space
		moveq.l	#0,d0			non error return for CLI
		rts				bye-bye


;============================================================================
; This is the actual interrupt server that is called every 60th of a second
; on the vertical blank interrupt chain.  It is entered with a1 pointing to
; our global data (because we put a5 into IS_DATA) and a6 pointing to exec.
;============================================================================
IntServerCode	move.l	a6,-(sp)
		movea.l	_AbsExecBase,a6
		subq.w	#1,Ticks(a1)		decrement the tick count
		bne.s	IntDone			not at 0 yet

; ticks reached 0 so send the appropriate signal to the main task
		move.w	#60,Ticks(a1)		re-initialise tick count
		move.l	TickMask(a1),d0		we want to send this signal
		movea.l	ThisTask(a1),a1		to this task
		jsr	_LVOSignal(a6)		so it wakes up

; we return 0 here so that other handlers get called too.  A non zero return
; terminates the server chain and no server at a lower pri would get called
IntDone		moveq.l	#0,d0			other handlers get a chance
		move.l	(sp)+,a6
		rts


; Text used by the program.  It's OK to put them here because they are static
DosName		DC.B	'dos.library',0
		CNOP	0,2

IntServerName	DC.B	'tick server',0
		CNOP	0,2

Msg1		DC.B	'Interrupt server example starting',10
Msg1End		CNOP	0,2

Msg2		DC.B	'tick!',10
Msg2End		CNOP	0,2

Msg3		DC.B	'******* B-O-O-O-O-O-O-O-M *******',10
Msg3End		CNOP	0,2

		END
