TweetFollow Us on Twitter

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 <My_ZPage
        pha
        lda <My_ZPage+1
        pha
                        ;
                        ; Start at slot 7.
                        ;
        lda #slot_7
        sta <My_ZPage+1      ;Zero Page
        sta slot+1      ;For Safe keeping
        stz <My_ZPage
        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 <My_ZPage+1
        dec a
        sta <My_ZPage+1
        sta slot+1
        cmp #slot_1
        bge @chk_smart
        lda #No_dev     ;No Device Error
                        ;
                        ; Clean exit
                        ;

@exit       tax
        pla
        sta <My_ZPage+1
        pla
        sta <My_ZPage
        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 <My_ZPage+1
        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 <My_ZPage
        lda slot+1
        sta <My_ZPage+1
        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
        jsr call_card
        dc.b    $00         ;Status Call Command Number
        dc.w    stat_list2
        bcs @error

        lda stat_data2      ;Get the Total Device
        sta dev_count       ;Count.

        lda #$03            ;Set up for DIB Status
        sta stat_code2      ;calls.

@loop   lda dev_num2        ;First time we increment
        cmp dev_count       ;a zero giving a device
        bge @error          ;number of 1.

        inc dev_num2
        jsr call_card
        dc.b    $00         ;Status Call Command Number
        dc.w    stat_list2
        bcs @error

        lda d_type
        cmp #$08            ;Is it Type = Scanner?
        bne @loop           ;No

        lda d_stype
        cmp #$A0            ;Subtype = $A0?
        bne @loop           ;No
                        ;
                        ; Scan string is a Pascal
                        ; string (a length byte
                        ; followed by ASCII). We
                        ; want to make sure that 
                        ; both the length and the 
                        ; text in 'scan_str' match
                        ; the data returned in
                        ; 'id_str_len' and 'id_str'.
                        ;
        ldx id_str_len
@str_loop   lda id_str_len,x
        cmp scan_str,x
        bne @loop
        dex
        bne @str_loop

        lda dev_num2    ;We have our scanner.
        sta scan_dnum
        lda #No_Err
        clc
        rts

@error  lda #No_dev     ;Device not found.
        sec
        rts

;*******************************************************

scan_str    dc.b    'APPLE    SCANNER ';4 Spaces between
                         ;1 Space after
dev_count   dc.b    $00

;*******************************************************

scan_dnum   dc.b    $00         ;Scanner Device Number

;*******************************************************

stat_list2  dc.b    $03         ;PCount = 3
dev_num2    dc.b    $00         ;Device number
        dc.w    stat_data       ;Data returned here
stat_code2  dc.b    $00         ;Status Code

;*******************************************************

stat_data2                  ;Our Buffer. Used over.
d_stat  dc.b    $00         ;Device Status Byte
blk_low dc.b    $00         ;Block Count (Low)
blk_mid dc.b    $00         ;Block Count (Mid)
blk_hi  dc.b    $00         ;Block Count (High)
id_str_len  dc.b    $00         ;ID String Length
id_str  dcb.b 16,$00        ;ID String (16 Bytes)
d_type  dc.b    $00         ;Device Type
d_stype dc.b    $00         ;Device Subtype
d_version   dc.w    $00         ;Version Word

;*******************************************************

SCANNING FOR 'STILL LIFE' FORMS, CAPTAIN

Now that we've found the scanner, we're ready to plant our thoughts in it. We do this by sending a few commands to the scanner, telling it what type of image we expect and what the scanner should do with the image before transferring it to us.

WE ARE ONE--OUR THOUGHTS ARE YOUR THOUGHTS
First, we send the scanner the halftone filter we want to use; then we set our scan window.

Halftone filter. Since we're going to do a halftone scan in our example, we issue a call to set the halftone filter. Note that we don't need to set this halftone filter if we choose to use one of the default filters or if we are going to scan in Line Art mode. A halftone filter is nothing more than a defined threshold for each pixel of a 4 by 4 block. As the image under the mask changes intensity, the filter causes more or fewer of the dots to be black; the rest of the dots are white. The 4 by 4 block then becomes darker or lighter depending on the number of dots that are set to white within it, simulating gray tones even though our graphic mode knows only black and white.

Setting the halftone filter is easy; picking the filter pattern that best suits your needs is harder. Use one of the built-in patterns unless you have a better one. We use a simple Bayer type filter for this example. See Figure 1 and Code Sample 3.

[IMAGE 051-75_Gulick_html1.GIF]

Figure 1 Simple Bayer Pattern

;*******************************************************
;
;   CODE SAMPLE 3
;
;   In this code segment, we issue an Apple Scanner SEND
;   command by using the Apple SCSI Card Generic SCSI
;   call ($2B). By so doing, we can send our halftone
;   filter to the scanner.
;
;*******************************************************
htone_filter
                        ;
                        ; Issue the call.
                        ;
        lda scan_dnum
        sta dev_num3

        jsr call_card
        dc.b    $04         ;Control Call Command Number
        dc.w    cmd_list3
        rts

;*******************************************************

cmd_list3   dc.b    $03         ;PCount = 3
dev_num3    dc.b    $04         ;Device number
        dc.w    filter_data     ;Pointer to data
        dc.b    $2B         ;Control Code

;*******************************************************

filter_data                 ;Our Data
        dc.w    24          ;Total Length of Parms
        dc.l    send_fltr       ;CDB Pointer (Long)
        dc.l    DCData3     ;DCMove Ptr (Long)
        dc.l    $00000000       ;Rqst Sense Ptr (Long)
        dc.b    $00         ;Reserved
        dc.b    $00         ;SCSI Status
        dc.b    $00         ;Command Count
        dc.l    $00000011       ;Trans Count (Long)
        dc.b    $00         ;DMA Mode
        dc.l    $00000000       ;Reserved (Long)

;*******************************************************


send_fltr   dc.b    $2A         ;Scanner SEND Command
        dc.b    $00         ;Reserved
        dc.b    $02         ;Transfer Type
        dc.b    $00         ;Reserved
        dc.b    $00         ;Reserved
        dc.b    $02         ;Transfer ID Byte
        dc.b    $00         ;Reserved
        dc.b    $00         ;Transfer Length (High)
        dc.b    $11         ;Transfer Length (Low)
        dc.b    $00         ;Reserved

;*******************************************************

DCData3 dc.l    send_data       ;Scanner SEND Data Ptr
        dc.l    $00000011       ;Transfer Count
        dc.l    $00000000       ;Offset
        dc.l    $00000000       ;Reserved

        dc.l    $00000000       ;DCStop
        dc.l    $00000000       ;Reserved
        dc.l    $00000000       ;Reserved
        dc.l    $00000000       ;Reserved

;*******************************************************

send_data   dc.b    $44         ;4 X 4 Matrix Size
        dc.b    $08         ;Pel 0
        dc.b    $88         ;Pel 1
        dc.b    $28         ;Pel 2
        dc.b    $A8         ;Pel 3
        dc.b    $C8         ;Pel 4
        dc.b    $48         ;Pel 5
        dc.b    $E8         ;Pel 6
        dc.b    $68         ;Pel 7
        dc.b    $38         ;Pel 8
        dc.b    $B8         ;Pel 9
        dc.b    $18         ;Pel 10
        dc.b    $98         ;Pel 11
        dc.b    $F8         ;Pel 12
        dc.b    $78         ;Pel 13
        dc.b    $D8         ;Pel 14
        dc.b    $58         ;Pel 15

;*******************************************************
Our scan window. Now that the scanner knows what halftone filter to use, we need to describe the scan window through which we'll view the document. Because we're using one of the Apple IIe graphics modes, our window will be fairly small. At 75 dpi in HiRes mode, or 150 dpi in Double HiRes mode, our window is about 3.75 inches across.

For the vertical screen, we have 192 pixels. At 75 dpi, our window is about 2.5 inches tall.

By using 75 dpi for HiRes and 150 dpi for Double HiRes, we can maintain a good aspect ratio. This allows us to display an image with minimum distortion.

In our example we use Double HiRes, so we first set the resolution for the X axis to 150 dpi and for the Y axis to 75 dpi. Then, we set our scan window's upper-left corner to absolute zero. See Code Sample 4.

;*******************************************************
;
;   CODE SAMPLE 4
;
;   In this code segment, we issue an Apple Scanner 
;   DEFINE WINDOW PARAMETERS command by using the Apple 
;   SCSI Card Generic SCSI call ($2B). This command 
;   defines the area of the scanner glass we want to scan.
;
;*******************************************************

def_window
                    ;
                    ; Issue the call.
                    ;
        lda scan_dnum
        sta dev_num4

        jsr call_card
        dc.b    $04     ;Control Call Command Number
        dc.w    cmd_list4
        rts

;*******************************************************


cmd_list4   dc.b    $03     ;PCount = 3
dev_num4    dc.b    $00     ;Device number
        dc.w    def_wndo    ;Pointer to data
        dc.b    $2B         ;Control Code

;*******************************************************

def_wndo                    ;Our Data
        dc.w    24          ;Total Length of Parms
        dc.l    def_wnd_cmd     ;CDB Pointer (Long)
        dc.l    DCData4     ;DCMove Ptr (Long)
        dc.l    $00000000       ;Rqst Sense Ptr (Long)
        dc.b    $00         ;Reserved
        dc.b    $00         ;SCSI Status
        dc.b    $00         ;Command Count
        dc.l    8+40            ;Trans Count (Long)
        dc.b    $00         ;DMA Mode
        dc.l    $00000000       ;Reserved (Long)

;*******************************************************

def_wnd_cmd dc.b    $24     ;Scanner Define Window
                            ;Parameters Command
        dc.b    $00         ;Reserved
        dc.b    $00         ;Reserved
        dc.b    $00         ;Reserved
        dc.b    $00         ;Reserved
        dc.b    $00         ;Reserved
        dc.b    $00         ;Transfer Length (High)
        dc.b    $00         ;Transfer Length (Mid)
        dc.b    8+40        ;Transfer Length (Low)
        dc.b    $80         ;Apple Bit

;*******************************************************

DCData4 dc.l    wndo_data       ;Scan Window Data Ptr
        dc.l    8+40            ;Transfer Count
        dc.l    $00000000       ;Offset
        dc.l    $00000000       ;Reserved

        dc.l    $00000000       ;DCStop
        dc.l    $00000000       ;Reserved
        dc.l    $00000000       ;Reserved
        dc.l    $00000000       ;Reserved

;*******************************************************
;   NOTE: Remember that all values longer than 1 byte 
;   are in reverse order from native 65xxx code.
;*******************************************************

wndo_data   dcb.b 6,$00     ;Reserved
        dc.b    $00         ;Transfer Length (High)
        dc.b    40          ;Transfer Length (Low)

        dc.b    $01         ;Window Identifier
        dc.b    $00         ;Reserved

        dc.b    $00         ;X Resolution (High)
        dc.b    150         ;X Resolution (Low)

        dc.b    $00         ;Y Resolution (High)
        dc.b    75          ;Y Resolution (Low)
                        ;
                        ; We will use the corner as
                        ; our upper-left position.
                        ; This is at coordinate 0,0.
                        ;
        dc.b    $00         ;Upper Left X (High)
        dc.b    $00         ;Upper Left X (Mid High)
        dc.b    $00         ;Upper Left X (Mid Low)
        dc.b    $00         ;Upper Left X (Low)

        dc.b    $00         ;Upper Left Y (High)
        dc.b    $00         ;Upper Left Y (Mid High)
        dc.b    $00         ;Upper Left Y (Mid Low)
        dc.b    $00         ;Upper Left Y (Low)
                        ;
                        ; Width is defined as the number
                        ; of 1/1200-inch increments on
                        ; the horizontal axis; must be on
                        ; a byte boundary for both the
                        ; start and end points. We will
                        ; set for 4 inches and drop the
                        ; extra.
                        ; 
        dc.b    $00         ;Width (High)
        dc.b    $00         ;Width (Mid High)
        dc.b    4*1200/256      ;Width (Mid Low)
        dc.b    4*1200      ;Width (Low)
                        ;
                        ; Length is defined as the number.
                        ; of 1/1200-inch increments on the
                        ; vertical axis. We want ≈ 2-1/2
                        ; inches (or 3072 increments).
                        ; 
        dc.b    $00         ;Length (High)
        dc.b    $00         ;Length (Mid High)
        dc.b    3072/256        ;Length 2.56*1200 (Mid Low)
        dc.b    3072            ;Length 2.56*1200 (Low)

        dc.b    $80         ;Median Brightness
        dc.b    $80         ;Median Threshold
        dc.b    $80         ;Median Contrast
        dc.b    $01         ;Image Composition (Halftone)
        dc.b    $01         ;Bits per Pixel
        dc.b    $00         ;Halftone Mask Always $00 (High)
        dc.b    $02         ;Downloaded Mask Pattern (Low)

        dc.b    $03         ;Padding Type
        dcb.b 2,$00         ;Reserved
        dc.b    $00         ;Compression Type (None)
        dcb.b 7,$00         ;Scanner Ref. is wrong
                        ; should be 7, 
                        ; not 5.

;*******************************************************

ENGAGE SCANNER
After telling the scanner how to scan, we need to tell it to start scanning. See Code Sample 5.

;*******************************************************
;
;   CODE SAMPLE 5
;
;   This code segment issues an Apple Scanner SCAN
;   command by using the Apple SCSI Card Generic SCSI
;   call ($2B). This starts the actual scanning.
;
;*******************************************************


start_scan
                    ;
                    ; Issue the call.
                    ;
        lda scan_dnum
        sta dev_num5

        jsr call_card
        dc.b    $04     ;Control Call Command Number
        dc.w    cmd_list5
        rts

;*******************************************************

cmd_list5   dc.b    $03     ;PCount = 3
dev_num5    dc.b    $00     ;Device number
        dc.w    scan_cmd    ;Pointer to data
        dc.b    $2B         ;Control Code

;*******************************************************
scan_cm                     ;Our Data
        dc.w    24          ;Total Length of Parms
        dc.l    do_scan     ;CDB Pointer (Long)
        dc.l    DCData      ;DCMove Ptr (Long)
        dc.l    $00000000   ;Rqst Sense Ptr (Long)
        dc.b    $00         ;Reserved
        dc.b    $00         ;SCSI Status
        dc.b    $00         ;Command Count
        dc.l    $00000001   ;Trans Count (Long)
        dc.b    $00         ;DMA Mode
        dc.l    $00000000   ;Reserved (Long)

;*******************************************************

do_scan dc.b    $1B     ;SCAN
                        ;Parameters Command
        dcb.b 3,$00     ;Reserved
        dc.b    1       ;Transfer Length (Low)
        dc.b    $00     ;Wait and Home Bits = 0

;*******************************************************


DCData5 dc.l    window_ID       ;Scan Window ID Ptr
        dc.l    1               ;Transfer Count
        dc.l    $00000000       ;Offset
        dc.l    $00000000       ;Reserved

        dc.l    $00000000       ;DCStop
        dc.l    $00000000       ;Reserved
        dc.l    $00000000       ;Reserved
        dc.l    $00000000       ;Reserved

;*******************************************************

window_ID   dc.b    $01         ;Window Identifier

;*******************************************************

ENERGIZING!
We can get data from the scanner in two ways. We could get it all at once and then manipulate it to go on the screen. In our example, we would need a buffer with 115,200 pixels or 14,400 bytes for the data: (4.0 inches * 150 dpi horizontally) * (2.56 inches * 75 dpi vertically).

To save the amount of RAM our program uses, however, we set up a buffer large enough for only one line; then we read each line from the scanner and display it until the entire image is on the screen. See Code Sample 6.

The data returned by the scanner is 8 pixels per byte. Bit 7 is the left- most pixel and bit 0 is the right-most pixel; a value of 1 means a black dot in the image. In the Apple II HiRes mode, we have 7 pixels per byte. Bit 0 is the left-most pixel and bit 6 is the right-most pixel; a value of 1 means a white dot. Because the formats are different, the program must convert the returned data, which it does as it goes, using code shown in Code Sample 6.


*******************************************************
;
;   CODE SAMPLE 6
;
;   In this code segment, we issue a series of calls to 
;   the Apple Scanner by using the Apple SCSI Card Generic
;   SCSI call ($2B). We first issue a GET DATA STATUS
;   call to see if there is enough data. Then we read 
;   in a single scan line with a READ call. The data is 
;   then converted and placed in a video buffer.
;
;*******************************************************
get_data
        stz scan_line   ;Init the scan line to 0.
                    ;
                    ; Issue the call.
                    ;
        lda scan_dnum
        sta dev_num6
        sta dev_num65

@get_data2  jsr call_card
        dc.b    $04     ;Control Call Command Number
        dc.w    cmd_list6
        bcs @out
                    ;
                    ; Is there enough data?
                    ; Enough data = 1 scan
                    ; line of 4 inches at 150
                    ; dpi (or 600 pixels). At
                    ; 8 pixels per byte, the
                    ; data will be padded to
                    ; 75 bytes.
                    ;
        lda scan_data
        bne @have_line
        lda scan_data+1
        bne @have_line
        lda scan_data+2
        cmp #rqst_cnt   ;Decimal 75
        blt get_data
                    ;
                    ; We have the data. Read
                    ; it.
                    ;
@have_line  jsr call_card
        dc.b    $04     ;Control Call Command Number
        dc.w    cmd_list65
        bcs @out
                    ;
                    ; Now we need to invert
                    ; the data.
                    ;
        lda #80     ;80 bytes/line for Double HiRes
        sta byte_count
        stz byte_index
@loop_1 lda #$07
        sta seven       ;Pixels/byte
@loop_2 ldx #rqst_cnt-2
        asl raw_image+\
        rqst_cnt-1      ;Shift bits out the top to
@loop_3 rol raw_image,x :the next byte 1 at a time
        dex
        bpl @loop_3
        ldx byte_index  ;Shift the last bit into
        ror screen,x    ;this byte. This reverses the
        dec seven       ;bit ordering and takes 8 bits 
        bne @loop_2     ;per byte down to 7.
        lsr screen,x
        inc byte_index
        dec byte_count
        bne @loop_1
                    ;
                    ; Move data to scan line.
                    ;
        ldx scan_line
        jsr on_screen
        inc scan_line
        bra @get_data2

@out        lda #$00
        clc
        rts

;*******************************************************

scan_line   dc.b    $00     ;Scan Line Index
byte_count  dc.b    $00     ;Number of bytes left
byte_index  dc.b    $00     ;Current Byte in use
seven       dc.b    $00     ;Count off 7 pixels
screen  dcb.b 80,0      ;Place to do the screen

;*******************************************************

cmd_list6   dc.b    $03     ;PCount = 3
dev_num6    dc.b    $00     ;Device number
        dc.w    gd_status   ;Pointer to data
        dc.b    $2B         ;Control Code
cmd_list65  dc.b    $03     ;PCount = 3
dev_num65   dc.b    $00     ;Device number
        dc.w    read        ;Pointer to data
        dc.b    $2B         ;Control Code

;*******************************************************

gd_status                   ;Our Data
        dc.w    24          ;Total Length of Parms
        dc.l    get_stat    ;CDB Pointer (Long)
        dc.l    DCData6     ;DCMove Ptr (Long)
        dc.l    $00000000   ;Rqst Sense Ptr (Long)
        dc.b    $00         ;Reserved
        dc.b    $00         ;SCSI Status
        dc.b    $00         ;Command Count
        dc.l    $0000000C   ;Trans Count (Long)
        dc.b    $00         ;DMA Mode
        dc.l    $00000000   ;Reserved (Long)

read                        ;Our Data
        dc.w    24          ;Total Length of Parms
        dc.l    get_data2   ;CDB Pointer (Long)
        dc.l    DCData65    ;DCMove Ptr (Long)
        dc.l    $00000000   ;Rqst Sense Ptr (Long)
        dc.b    $00         ;Reserved
        dc.b    $00         ;SCSI Status
        dc.b    $00         ;Command Count
        dc.l    rqst_cnt    ;Trans Count (Long)
        dc.b    $00         ;DMA Mode
        dc.l    $00000000   ;Reserved (Long)

;*******************************************************

get_stat    dc.b    $34     ;GET DATA STATUS
                            ;Parameters Command
        dcb.b 7,$00         ;Reserved
        dc.b    12          ;Transfer Length (Low)
        dc.b    $00         ;Wait and Home Bits = 0

get_data2   dc.b    $28     ;READ
                            ;Parameters Command
        dcb.b 4,$00         ;Reserved
        dc.b    $01         ;Window ID
        dc.b    $00         ;Transfer Length (High)
        dc.b    $00         ;Transfer Length (Mid)
        dc.b    rqst_cnt    ;Transfer Length (Low)
        dc.b    $00         ;Wait and Home Bits = 0

;*******************************************************

DCData6 dc.l    data_cnt    ;Data Pointer
        dc.l    12          ;Transfer Count
        dc.l    $00000000   ;Offset
        dc.l    $00000000   ;Reserved

        dc.l    $00000000   ;DCStop
        dc.l    $00000000   ;Reserved
        dc.l    $00000000   ;Reserved
        dc.l    $00000000   ;Reserved

DCData65    dc.l    raw_image   ;Data Pointer
        dc.l    rqst_cnt    ;Transfer Count
        dc.l    $00000000   ;Offset
        dc.l    $00000000   ;Reserved

        dc.l    $00000000   ;DCStop
        dc.l    $00000000   ;Reserved
        dc.l    $00000000   ;Reserved
        dc.l    $00000000   ;Reserved

;*******************************************************

data_cnt                ;Data Space
        dcb.b 2,$00     ;Reserved
        dc.b    $00     ;Data Length
        dc.b    $00     ;Block
        dc.b    $00     ;Window Identifier
        dcb.b 4,$00     ;Reserved
scan_data   dc.b    $00     ;Scan Data (High)
        dc.b    $00     ;Scan Data (Mid)
        dc.b    $00     ;Scan Data (Low)

raw_image   dcb.b 100,$00   ;Scanned Data Image

;*******************************************************

PUT IT ON THE SCREEN, ENSIGN
Because we display the image in black and white, we need to set up the graphic soft switches accordingly. In our example, we display our image in HiRes Page 1, and we assume black and white display. On a color video monitor, the image would appear in black and white. See Code Sample 7.

;*******************************************************
;
;   CODE SAMPLE 7
;
;   In this code segment, we toggle the HiRes soft 
;   switches so that we can see what was just scanned.
;
;*******************************************************

display
                    ;
                    ; Save the current state.
                    ;
        lda RDTEXT
        sta @text   ;Text/Graphics
        lda RDMIX
        sta @mixed  ;Mixed?

        lda RDPAGE2
        sta @page       ;Page 1 or 2

        lda RDHIRES
        sta @hires      ;HiRes Mode?

        lda RD80VID
        sta @80col      ;80-Column Mode?

        sta SET80VID    ;Set 80-Column Mode
        sta TXTCLR      ;Standard Apple II Graphics
        sta MIXCLR      ;Clear Mixed Mode
        sta TXTPAGE1    ;Page 1
        sta HIRES       ;HiRes Mode
        sta CLRAN3      ;Clear annunciator 3

        sta KBD_STRB    ;Clear Key Strobe
@key_loop   lda KBD     ;Get key
        bpl @key_loop   ;Wait for Key Press
        sta KBD_STRB    ;Clear Key Strobe
        cmp #ESC        ;ESC Key
        clc
        bne @chk_txt
        sec             ;Exit on ESC

        lda SETAN3      ;Set annunciator 3.

@chk_txt    lda @text
        bpl @chk_mix
        sta TXTSET      ;Text on

@chk_mix    lda @mixed
        bpl @chk_page
        sta MIXSET      ;Mixed on

@chk_page   lda @page
        bpl @chk_hires
        sta TXTPAGE2    ;Page 2

@chk_hires  lda @hires
        bmi @chk_40col
        sta LORES       ;HiRes Off

@chk_40col  lda @80col
        bmi @rts
        sta CLR80VID    ;80-Column on

@rts        rts

@text       dc.b    $00
@mixed      dc.b    $00
@page       dc.b    $00
@hires      dc.b    $00
@80col      dc.b    $00

;*******************************************************

FILE THE REPORT AND HEAD FOR HOME
Now, save the image in its displayable format. Save it as you would any file, using standard ProDOS MLI calls.

FINAL LOG ENTRY
The ability to bring printed images into the computer opens up many possibilities for you and for your customers. Programs that use graphics can import and add color to printed images. For example, users can put together files that include family photos. These files can then be transmitted electronically to others for viewing.

You can also give users control over a number of scan parameters. For example, you could allow them to position the scan window on a graphic representation of the scanner glass; users could then position the scan without adjusting the printed page on the scanner glass. Or you could allow users to specify the resolution of the scan, showing them how the scan window size changes.

Although not demonstrated here, Line Art mode provides very clean images of scanned text. If you use Line Art mode to support optical character recognition (OCR), users can import text and avoid retyping entire manuscripts.

The possibilities are endless. Have fun exploring them. That is, after all, what it is all about--doing more with your Apple II and having fun doing it.

THE SCANNING PROCESS

The scanning process involves five steps for your application, described briefly below. For general information about scanner technology and terminology, see the Apple Scanner Reference.

1. Initialize the scanner parameters
You must set the scanner parameters before you start a scan. These parameters determine how much space the image needs.

Use these commands:
    MODE SENSE ($1A)
    MODE SELECT ($15)
    SEND ($2A)
    DEFINE WINDOW PARAMETERS ($24)

2. Define an image buffer
The image buffer is free memory within the computer system that holds the bitmap image returned by the scanner. The size of the buffer dictates the amount of data you can retrieve from the scanner and thus the size of the image. If an image is larger than the available free memory, you can spool it to disk for later retrieval.

3. Start the scan
After you set the parameters, you can issue a scanner command to start scanning. When the scanner receives this command, it scans the image and places it in its internal memory.

Use this command:  SCAN ($1B)

4. Request the scanned data
You must read the image from the scanner as it is placed in the scanner's internal memory. Because the scanner's memory can hold only a small portion of the image being scanned, and because you must read the data to allow the scan to continue, you should poll the scanner promptly.

Use these commands:
    GET DATA STATUS ($34)
    READ ($28)

5. Save the image to a file
You can save the data in a number of formats: HiRes and Double HiRes for the Apple II family, Super HiRes for the Apple IIGS, and PICT or any other Macintosh image format. You can also store the data in other formats, such as GIF. The choice is yours.

MATTHEW GULICK According to his business cards, Matt Gulick is an all-around SCSI (say it out loud) guy--who hates to shave and refuses to wear shoes except when meeting with someone with a title of VP or higher. He dearly loves the strict dress code, highly regimented working hours, and totally controlled environment at Apple. His career here was preordained by his being "genetically defective at birth." This condition first visibly manifested itself at age 12 when he began reading computer punch cards for fun. He did temporarily buck his computer industry destiny by studying pre-vet medicine at Brigham Young University. However, after college he got back on track by working as an "electronic stuff" sales rep, and then he programmed for ParaMIS. Now he feels he's running the perfect scam: getting paid to play with computers. A member of the Dr. Demento Fan Club (DDFC), he fears his wife will sue him for dementing his four children, who only know the Weird Al versions of song lyrics. *

You should let users adjust the settings for Brightness, Threshold, and Contrast so they can customize the scan to the type of image being scanned (black and white or color; printed page or photo). If you let users choose Line Art or Grayscale, they can also optimize the scan for text or for an image. *

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Adobe Illustrator 24.0.3 - Professional...
You can download Adobe Illustrator for Mac as a part of Creative Cloud for only $20.99/month (or $9.99/month if you have also purchased an earlier software version). Adobe Illustrator for Mac is the... Read more
Adobe Dreamweaver CC 2020 20.1 - Build w...
Dreamweaver CC 2020 is available as part of Adobe Creative Cloud for as little as $20.99/month (or $9.99/month if you're a previous Dreamweaver customer). Adobe Dreamweaver CC 2020 allows you to... Read more
Adobe Audition 13.0.3 - Professional pos...
Audition is available as part of Adobe Creative Cloud for as little as $20.99/month (or $9.99/month if you're a previous Audition customer). Adobe Audition empowers you to create and deliver... Read more
Adobe After Effects 17.0.3 - Create prof...
After Effects is available as part of Adobe Creative Cloud for $52.99/month (or $20.99/month for a single app license). The new, more connected After Effects can make the impossible possible. Get... Read more
Audio Hijack 3.6.4 - Record and enhance...
Audio Hijack (was Audio Hijack Pro) drastically changes the way you use audio on your computer, giving you the freedom to listen to audio when you want and how you want. Record and enhance any audio... Read more
Eye Candy 7.2.3.96 - 30 professional Pho...
Eye Candy renders realistic effects that are difficult or impossible to achieve in Photoshop alone, such as Fire, Chrome, and the new Lightning. Effects like Animal Fur, Smoke, and Reptile Skin are... Read more
Notability 4.2.2 - Note-taking and annot...
Notability is a powerful note-taker to annotate documents, sketch ideas, record lectures, take notes and more. It combines, typing, handwriting, audio recording, and photos so you can create notes... Read more
Adobe Acrobat Reader 20.006.20034 - View...
Adobe Acrobat Reader allows users to view PDF documents. You may not know what a PDF file is, but you've probably come across one at some point. PDF files are used by companies and even the IRS to... Read more
Adobe Acrobat DC 20.006.20034 - Powerful...
Acrobat DC is available only as a part of Adobe Creative Cloud, and can only be installed and/or updated through Adobe's Creative Cloud app. Adobe Acrobat DC with Adobe Document Cloud services is... Read more
Day One 4.8 - Maintain a daily journal.
Day One is an easy, great-looking way to use a journal / diary / text-logging application. Day One is well designed and extremely focused to encourage you to write more through quick Menu Bar entry,... Read more

Latest Forum Discussions

See All

Marvel Strike Force introduces new brawl...
FoxNext's squad-based RPG Marvel Strike Force is set to receive some fresh characters from the X-Men and Iron Man series. They'll arrive as part of the game's latest update, which follows a sizable spending boycott on the title due to complaints... | Read more »
Speed Dating for Ghosts is a narrative a...
Speed Dating for Ghosts originally released on Steam back 2018, since then it has received honourable mentions for narrative during the Independent Games Festival. Now it's made its way over to iOS devices where it's available as a premium title... | Read more »
Fast-paced multiplayer title Tennis Star...
Tennis Stars: Ultimate Clash is the latest free-to-play tennis title to hit iOS and Android. It's said to be a fairly casual experience, offering easy-to-learn controls and fast-paced, mobile-friendly matches. [Read more] | Read more »
Super Mecha Champions' latest updat...
Super Mecha Champions' latest update sees the addition of a brand new character called R.E.D. Alongside that, there's news about the current season and a series of Emojis that have been added to the game. [Read more] | Read more »
Isle Escape: The House is an upcoming pu...
Isle Escape: The House is an upcoming puzzle game from Simeon Angelov that's intended to serve as an introduction to a saga they're planning on releasing in an episodic fashion. The first chapter is set to release for both iOS and Android on 29th... | Read more »
Company of Heroes, the classic RTS, is n...
Feral Interactive has finally released their highly anticipated iOS version of the strategy classic Company of Heroes. It's available now for iPad as a premium title and has had various tweaks to ensure that it's optimised for touch controls. [... | Read more »
Mario Kart Tour's Vancouver Tour ha...
With Mario Kart Tour's Valentine's Tour now at an end (suspiciously before Valentine's Day has even arrived), it's now time to move on to the all-new and exciting Vancouver Tour. This time around, the featured drivers are Hiker Wario and Aurora... | Read more »
A new PictoQuest update makes it a much...
PictoQuest is a charming little puzzle game, but it left us a little disappointed. The game just didn’t seem to use screen space effectively, to the point that using the touch controls (as opposed to the default virtual d-pad) could lead to errant... | Read more »
Alley is an atmospheric adventure game a...
Alley is an atmospheric adventure game that sees you playing as a young girl trapped in an inescapable nightmare. Surrounded by her worst fears, every step forward for her is a huge challenge that you'll help guide her through using some simple... | Read more »
Fight monsters and collect heroes in Cry...
From Final Fantasy to Chaos Rings, Japanese roleplaying games have found a large and loyal fanbase on mobile devices. If you’re seeking a more under-the-radar JRPG to escape into, Lionsfilm’s Cryptract could be the one. The game has been around... | Read more »

Price Scanner via MacPrices.net

Apple AirPods are on sale for $30 off today
Amazon has new 2019 Apple AirPods (non-Pro models) on sale today for $30 off MSRP, starting at $129. Shipping is free: – AirPods with Wireless Charging Case: $169 $30 off MSRP – AirPods with Charging... Read more
27″ 3.7GHz 6-Core 5K iMac on sale for $2099,...
B&H Photo has the 2019 27″ 3.7GHz 6-Core 5K iMac in stock today and on sale for $200 off Apple’s MSRP. Overnight shipping is free to many locations in the US: – 27″ 3.7GHz 6-Core 5K iMac: $2099 $... Read more
Save up to $250 on a 12.9″ iPad Pros with the...
Apple has Certified Refurbished 12.9″ iPad Pros available on their online store for up to $250 off the cost of new models. Prices start at $849. Each iPad comes with a standard Apple one-year... Read more
Save up to $220 on 11″ iPad Pros with these r...
Apple has Certified Refurbished 11″ iPad Pros available on their online store for up to $220 off the cost of new models. Prices start at $679. Each iPad comes with a standard Apple one-year warranty... Read more
8-Core 27″ iMac Pro available for $4249, Cert...
Apple has Certified Refurbished 27″ 3.2GHz 8-Core iMac Pros available for $4249 including free shipping. Their price is $750 off the cost of new models. A standard Apple one-year warranty is included... Read more
$749 MacBook Airs continue to be available on...
Amazon has the 2017 13″ 1.8GHz/128GB MacBook Air on sale today for only $749 shipped. That’s $250 off Apple’s original MSRP for this model and the cheapest new MacBook available from any Apple... Read more
HomePods on sale for $204 at Other World Comp...
Other World Computing has discounted, new, Apple HomePods on sale for up to $95 off Apple’s MSRP: – HomePod Space Gray: $207.99 $92 off MSRP – HomePod White: $204.99 $95 off MSRP These are the same... Read more
Get a Certified Refurbished iMac at Apple for...
Apple has Certified Refurbished 2019 21″ & 27″ iMacs available starting at $929 and up to $350 off the cost of new models. Apple’s one-year warranty is standard, shipping is free, and each iMac... Read more
A Look Back At The Top 5 Most Read Stories Of...
FEATURE: 02.21.20 The best of the best are now history and we’re not talking about Super Bowl LIV from earlier this month but rather, coverage from the past year (its second and first full one at... Read more
Apple offers wide range of discounted custom...
Save up to $610 on a custom-configured 21″ or 27″ iMac with these Certified Refurbished models available at Apple. Each iMac features a new outer case, free shipping, and includes Apple’s standard 1-... Read more

Jobs Board

Medical Assistant - *Apple* Valley Clinic -...
…professional, quality care to patients in the ambulatory setting at the M Health Fairview Apple Valley Clinic, located in Apple Valley, MN. Join the **M Health Read more
Geek Squad *Apple* Consultation Professiona...
**762475BR** **Job Title:** Geek Squad Apple Consultation Professional **Job Category:** Store Associates **Store NUmber or Department:** 001423-San Jose-Store **Job Read more
Medical Assistant - *Apple* Valley Clinic -...
…professional, quality care to patients in the ambulatory setting at the M Health Fairview Apple Valley Clinic, located in Apple Valley, MN. Join the **M Health Read more
Geek Squad *Apple* Consultation Professiona...
**756636BR** **Job Title:** Geek Squad Apple Consultation Professional **Job Category:** Store Associates **Store NUmber or Department:** 001053-Arundel Mills-Store Read more
Medical Assistant - *Apple* Valley Clinic -...
…professional, quality care to patients in the ambulatory setting at the M Health Fairview Apple Valley Clinic, located in Apple Valley, MN. Join the **M Health Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.