	PAGE	,132
	NAME    EXAMPLES
;************
;
;	examplea.asm
;
;	This file contains demonstration programs using the 
;	CLIPPER assembly interface.
;
;	Function source.....
;
;		ISPRINTER()
;		TONE()
;		CURDIR()
;		BIN2I()
;		BIN2W()
;		BIN2L()
;		I2BIN()
;		L2BIN()
;
	INCLUDE	EXTENDA.INC


;***************
;
;	define segment names
;
	CODESEG	EXAMPLEA
	DATASEG


;***************
;
;	declaration of public functions
;
	CLpublic <ISPRINTER, TONE, CURDIR>
	CLpublic <BIN2I, BIN2W, BIN2L, I2BIN, L2BIN>


;***************
;
;	Static data
;
	CLstatic <long nbuff 0>

	; storage for full pathname and pointer to address it
	CLstatic <byte ASCIIZ <<64 DUP(0)>>, cptr PATH ASCIIZ>


;***************
;
;	Equates
;

$define FALSE			0000H
$define TRUE			0001H

	; for TONE()
$define TIMER_COMMAND		00B6H		; value for timer setup
$define TIMER_COMMAND_REGISTER	0043H		; port address
$define TIMER_LATCH_REGISTER	0042H		; port address
$define PORT_PB			0061H		; port address
$define SPEAKER_ON		00000011B 	; bit mask
$define CLOCK_RATE_HIGH		0012H		; 1.19318 MHz as 32 bit value
$define CLOCK_RATE_LOW		34DCH

	; for CURDIR()
$define GET_CURDIR		0047H		; DOS request number


;*******
;
;	ISPRINTER()
;	Tom Rettig, Brian Russell
;	11/01/85
;
;	Logical true if the printer is online and ready, otherwise false.
;
;	status = ISPRINTER()
;
;		status  -   logical.
;
;	Placed in the public domain by Tom Rettig Associates.
;
	; function declaration
	; return types include void, char, int, long, double, date, and log
	CLfunc log ISPRINTER

	; begin code
	CLcode
		MOV	AH, 02H			; printer status function
		MOV	DX, 0			; which printer to check
		INT	17H			; read printer status

		MOV	BX, FALSE
		CMP	AH, 90H			; 90H means not busy
		JNE	ISPRINTER_RET		; return false if AH != 90H
		MOV	BX, TRUE

ISPRINTER_RET:
	; return logical value to Clipper (declared "log" above)
	CLret	BX


;******
;
;	declare dummy segment to access BIOS data area
;	no code is generated by this declaration
;
BIOS_DATA	SEGMENT AT 40H

		ORG	6CH
TIMER_LOW	LABEL	WORD			; time of day is stored here

BIOS_DATA	ENDS


;***************
;
;	begin local assembler routines
;
	WORKFUNCS


;******
;
;	delay processing a specified number of timer tics
;	the count is contained in the DX register
;	each tic is 1/18 second
;
TIME_DELAY	PROC	NEAR

		PUSH	ES			; preserve


	; ES = segment of BIOS data area
		MOV	AX, BIOS_DATA		; load segment value
		MOV	ES, AX

		ASSUME	ES:BIOS_DATA		; (tell MASM what's in ES)


	; delay at least one tick
		MOV	BX, TIMER_LOW		; fetch current time
T1:
		CMP	BX, TIMER_LOW		; loop 'til TIMER_LOW changes
		JE	T1


	; delay loop
T2:
		MOV	AX, TIMER_LOW		; fetch current time
		SUB	AX, BX			; AX = number of ticks so far
		CMP	AX, DX			; compare with requested delay
		JL	T2			; keep looping if AX < DX


		POP	ES			; restore
		ASSUME	ES:NOTHING		; (tell MASM nothing in ES)

		RET				; near return

TIME_DELAY	ENDP


;***************
;
;	end of local assembler routines
;
	ENDWORK


;******
;
;	TONE()
;	Dennis L. Dias
;	12/09/87
;
;	Produce a tone of the specified frequency and duration.  If the
;	frequency is less than 20 Hz wait the specified duration without
;	producing a tone.
;
;	TONE(frequency, duration)
;
;		frequency:	numeric -- cycles per second
;		duration:	numeric -- 18ths of a second
;
	CLfunc void TONE <int frequency, int duration>

	CLcode
		XOR	DX, DX			; delay one timer tic
		CALL	TIME_DELAY

	; 1.19318 MHz / frequency
		MOV	BX, frequency
		CMP	BX, 20
		JB	SILENCE

	; select timer channel 2; read/write LSB, MSB; mode 3; binary
		MOV	AL, TIMER_COMMAND
		OUT	TIMER_COMMAND_REGISTER, AL

		MOV	DX, CLOCK_RATE_HIGH
		MOV	AX, CLOCK_RATE_LOW

		DIV	BX			; AX = correct Hz divisor

	; output LSB, MSB (this sets the frequency)
		OUT	TIMER_LATCH_REGISTER, AL
		MOV	AL, AH
		OUT	TIMER_LATCH_REGISTER, AL

	; save current setting of port pb
		IN	AL, PORT_PB
		PUSH	AX

	; turn on speaker data and timer gate bits
		OR	AL, SPEAKER_ON
		OUT	PORT_PB, AL

	; speaker is on..wait the requested duration
		MOV	DX, duration
		CALL	TIME_DELAY

	; shut that thing off!!
		POP	AX
		OUT	PORT_PB, AL

		JMP	SHORT TONE_RET

SILENCE:
	; just delay
		MOV	DX, duration
		CALL	TIME_DELAY

TONE_RET:

	; no return value
	CLret


;******
;
;	CURDIR()
;	Dennis L. Dias
;	12/17/87
;
;	Get and return the current directory path.
;	Note that a null string means that either an error
;	has occurred, or the root directory is current.
;
;	string = CURDIR(drive)
;
;		drive:   drive letter (A, B, ...)
;		     :	 current drive if omitted.
;
	CLfunc char CURDIR <char drive>

	CLcode
		PUSH	DS			; preserve
		LDS	SI, PATH		; point to mem block
		MOV	BYTE PTR [SI],0		; null string if error
		MOV	DL, 0			; assume default drive

		TESTNUL	drive			; test if parameter supplied
		JZ	FILL_ASCIIZ

	; parameter supplied..get specified drive letter
		PUSH	ES			; preserve
		LES	BX, drive		; load pointer
		MOV	DL, ES:[BX]		; get drive letter
		AND	DL, 01011111B		; ensure upper case
		SUB	DL, ('A' - 1)		; convert to number ('A' = 1)
		POP	ES			; restore

FILL_ASCIIZ:
		DOSREQ	GET_CURDIR		; fill with full path name

		POP	DS			; restore

	; return pointer to directory path
	CLret	PATH


;*******
;	BIN2I()
;	Bri and Richie
;
	CLfunc int BIN2I <char str>

	CLcode
		LES	BX, str
		MOV	AX, ES:[BX]

	CLret	AX


;*******
;	BIN2W()
;	Bri and Richie
;
	CLfunc long BIN2W <char str>

	CLcode
		LES	BX, str
		MOV	AX, ES:[BX]
		MOV	DX, 0

	CLret	DX AX


;*******
;	BIN2L()
;	Bri and Richie
;
	CLfunc long BIN2L <char str>

	CLcode
		LES	BX, str
		MOV	AX, ES:[BX]
		MOV	DX, ES:[BX+2]

	CLret	DX AX


;*******
;	I2BIN()
;	Bri and Richie
;
;	Note -	since the CL macros can't (currently) return strings
;		containing null bytes, the function is declared 'void'
;		and a separate call to _retclen is used...
;
	CLfunc void I2BIN <int num>

	CLcode
		MOV	AX, num
		MOV	WORD PTR nbuff, AX

	; note parameter order
		Ccall	_retclen <OFFSET(nbuff), SEG(nbuff), 2>

	CLret


;*******
;	L2BIN()
;	Bri and Richie
;
;	Note -	since the CL macros can't (currently) return strings
;		containing null bytes, the function is declared 'void'
;		and a separate call to _retclen is used...
;
	CLfunc void L2BIN <long num>

	CLcode
		MOV	AX, LSW(num)
		MOV	DX, MSW(num)

		MOV	WORD PTR nbuff[0], AX
		MOV	WORD PTR nbuff[2], DX

	; note parameter order
		Ccall	_retclen <OFFSET(nbuff), SEG(nbuff), 4>

	CLret


	; end of assembly
		END

; eof examplea.asm

