Winter 91 - SCANNING FROM PRODOS
SCANNING FROM PRODOS
MATT GULICK
This article shows just how easy it is to include support for scanner hardware in your
application program. With just a little effort, you can add significant functionality to
your program.
In this article, we explore using the Apple Scanner (a flatbed scanner) and the Apple
II High-Speed SCSI Card with either an Enhanced Apple IIe computer or an Apple IIGS
computer running the ProDOS-8 operating system. (A future article will cover
GS/OS.) The concepts presented here can be used for any scanner that can be connected
to an Apple IIe or Apple IIGS via the Apple II SCSI card.
For this article, we limit our discussion to the graphics modes available on the Apple
IIe (HiRes and Double HiRes modes). These modes are more limited in resolution and
color generation than the Super HiRes mode available on the IIGS, but they allow our
sample program to run on most of the current Apple II family of systems in use today.
We focus on 1-bit-per-pixel halftone and line art images. In so doing, we are able to
display the data on the screen easily.
PLAYING HIDE-AND-SEEK WITH THE SCANNER
...98, 99, 100. Ready or not, here we come. Under the ProDOS-8 operating system,
we don't have access to the loaded drivers that have been written for the GS/OS
environment. Since the scanner is a character device, data is returned in bytes rather
than in blocks. ProDOS-8 can't help us read from character devices, so we need to
walk the slots looking for the card we want and then talk to the card directly to find the
device we want.
APPLE HIGH-SPEED SCSI CARD, WHERE ARE YOU?
We must first find which slot the high-speed SCSI card is in. We start at slot 7 and
work our way down. In the following code segment, we look for a SmartPort device in
the current slot. If one is found, we must determine if it is a SCSI card that supports
extended SmartPort calls. Finally, we need to make sure that this is the type of card
we want. In other words, "Is this card from a vendor whose command set I
understand?" See Code Sample 1.
;*******************************************************
;
; CODE SAMPLE 1
;
; In this first code segment, we walk the slots starting
; at slot 7, looking first for a card of any kind. Once
; found, we check the ID bytes for a SmartPort card.
; Once found, we check the ID Type byte to see if it is
; a SCSI card. If the card passes all these tests, we
; then issue a Device $00 Status $00 call to further
; ensure that this is the Apple II High-Speed SCSI Card.
;
;*******************************************************
find_card
;
; Save the current Zero
; Page values before
; using them.
;
lda
pha
lda
pha
;
; Start at slot 7.
;
lda #slot_7
sta
sta slot+1 ;For Safe keeping
stz
stz slot
;
; Is it a SmartPort card?
;
@chk_smart ldy #Blk_sigl
lda (My_ZPage),y ;Block_device Signature Byte
cmp #$20 ;#1 = $20
bne @next_slot
ldy #Blk_sig2
lda (My_ZPage),y ;Block_device Signature Byte
bne @next_slot ;#2 = $00
ldy #Blk_sig3
lda (My_ZPage),y ;Block_device Signature Byte
cmp #$03 ;#3 = $03
bne @next_slot
ldy #SPort_sig
lda (My_ZPage),y ;SmartPort Signature Byte
bne @next_slot ;#1 = $00
;
; We have a SmartPort
; device. Is it SCSI with
; Extended SmartPort?
;
ldy #SPort_ID
lda (My_ZPage),y
and #Ext_SPort+
SCSI
cmp #Ext_SPort+
SCSI
bne @next_slot
;
; Is it an Apple II
; High-Speed SCSI Card?
;
jsr is_it_appl
bcc @exit
;
; Check the next slot.
;
@next_slot lda
dec a
sta
sta slot+1
cmp #slot_1
bge @chk_smart
lda #No_dev ;No Device Error
;
; Clean exit
;
@exit tax
pla
sta
pla
sta
txa
cmp #$01 ;Set Carry if Non-Zero.
rts
;
; This routine determines
; if the card is the new
; high-speed SCSI card.
;
is_it_appl ldy #$ff
lda (My_ZPage),y
clc
adc #$03 ;Set SmartPort Entry Address.
sta card_ntry
lda
sta card_ntry+1
jsr call_card
dc.b $00 ;Status Call Command Number
dc.w stat_list1
;
; Check the results.
;
lda stat_data+2 ;Low Byte of Vendor ID
cmp #$01 ;Must be $01
bne @non_apple
lda stat_data+3 ;High Byte of Vendor ID
bne @non_apple ;Must be $00
lda stat_data+4 ;Low Byte of Version
bne @non_apple ;Should be Null
lda stat_data+5 ;High Byte of Version
bne @non_apple ;Should be Null
clc ;Acc. 0 by previous LDA
bra @done
@non_apple lda #No_dev ;Device not found
sec
;
; Restore ZPage.
;
@done pha
php
lda slot
sta
lda slot+1
sta
plp
pla
rts
slot dc.w $0000
;*******************************************************
call_card jmp (card_ntry)
card_ntry dc.w $0000
;*******************************************************
stat_list1 dc.b $03 ;PCount = 3
dc.b $00 ;Device = Card
dc.w stat_data ;Data returned here
dc.b $00 ;Get Host Status Call
;*******************************************************
stat_data dcb.b 64,0 ;Our Buffer
;*******************************************************
FINDING THE SCANNER IN A HAYSTACK
Now that we've found the card, or at least a card (there may be more than one), we
need to ask the card, politely of course, if it has seen the scanner and if so, where. See
Code Sample 2.
"Excuse me SCSI card, we're taking a census and would like to ask you a few questions
if you don't mind. How many devices live at this slot? I see, and are any of them by
chance character devices? Hmmm, too bad. I'll try the next slot. Sorry to bother you,
and thank you for your time.
. . . a few slots later . . ."Hi, we're taking a poll and would like your response to a few
short questions. How many devices live at this slot? That many, great. Are any of them
character devices? Getting warmer. May we come in to talk to them? Thank you.
;*******************************************************
;
; CODE SAMPLE 2
;
; In this code segment, we walk the unit numbers from the
; SCSI card starting at unit 2 and going to unit 0 to
; get the actual unit number count. Once this is
; done, we start at unit 1 and walk forward until we
; find the scanner.
;
;*******************************************************
find_scanr
;
; First we issue a
; Status call to device
; number 2. This call
; forces the card to
; build its tables if it
; has not yet done so.
;
lda #$02
sta dev_num2
stz stat_code2
jsr call_card
dc.b $00 ;Status Call Command Number
dc.w stat_list2
bcs @error
;
; Now call unit 0 to
; find out the total
; device count.
;
stz dev_num2