;************************************************************************
; This program grabs a frame at 5.7fps, and sends it to the PC.
; Upon starting, it measures the exposure using the 16x16 pixel center
; portion of the image. It does not make any measurements afterwards.
; It can also increase or decrease exposure depending if it receives a
; 'U' or 'L' from the PC.
; Keep the Fujinon lens focused at 7ft or so, and f11.
; Image grabbing routine is optimized for speed
;************************************************************************
; Note on variable names: _b at the end of a variable name implies that
;                         the variable is a byte long.
;
; Note on image width: If width of an image is 160 pixels, the column array
;                      is from 0-159, not 1-160...

;************************************************************************
; The following section defines parameters related to processing the image
;************************************************************************
PATCH_SIZE      equ     127                  ; Maximum available size for
                                             ; the patch (for all its data)
PATCH_WIDTH     equ     030h                 ; Width of patch in pixels
PATCH_X0_IMG    equ     020h                 ; X0 of patch in image
PATCH_Y0_IMG    equ     060h                 ; Y0 of patch in image

; NOTE: Sum of PATCH_WIDTH and PATCH_X0_IMG should not exceed length of a row
;       of pixels in the image
;************************************************************************
; The end of section which defines parameters related to processing the image
;************************************************************************

;************************************************************************
; The following section defines C166's pin functions w.r.t. CCD interface
;************************************************************************

DIR_P_2         equ     00ffh               ; Port 2 LSB = O/P for control,
                                            ; MSB = I/P for data

PARM_CTR4       equ     0000000001001001b   ; MODE for TIMER4's counter mode
                                            ; count = UP, CTR4=EN,
                                            ; COUNTER MODE = EN,
                                            ; +ve TRANSITION on T4IN

PARM_CTR2       equ     0000000001001001b   ; MODE for TIMER2's counter mode
                                            ; count = UP, CTR2=EN,
                                            ; COUNTER MODE = EN,
                                            ; +ve TRANSITION on T2IN

PARM_TMR5       equ     0000000000000111b   ; MODE for TIMER5's timer mode
                                            ; count = UP, TMR5=EN,          
                                            ; TIMER MODE = EN,            

IMAGE_16X12     equ     04b00h              ; Memory size for 160X120 image

IMAGE_12X16     equ     04b00h              ; Memory size for 120X160 image

IMAGE_12X12     equ     03840h              ; Memory size for 120X120 image

IMAGE_16X16     equ     06400h              ; Memory size for 160X160 image

PIX_160         equ     0a0h                ; 160 pixels

PIX_120         equ     078h                ; 120 pixels

;-------------------------------------------------------------------------

;-------------------------------------------------------------------------
; CCD control mode is formed by the following signals on the low byte of
; PORT_2. 
;
; By default it means that this mode of the camera should be used upon
; startup and then different settings changed in the program as desired.
; The control word forming the default settings should be put out on
; the LOW byte of PORT 2 upon startup.
;
; The different bits control the following control lines going to the
; CCD:
;
; P2.0 = CCD_OE- (ACTIVE LOW). A LOW(0) on this enables the CCD output, a
;                             HIGH(1) disables the CCD output. LOW is default.

; P2.0     equ    CCD_OE ;*******************

;
; The following two signals control the clock rate divisor. Higher divisors
; means slower frame rates. (Assuming a 12MHz clock on CCD)
; P2.1 = SEL1         | LOW   | HIGH   | LOW    | HIGH    
; P2.2 = SEL2         | LOW   | LOW    | HIGH   | HIGH
;  FRAME RATE (fps)   | 22.7  | 11.4   | 5.7    | 2.8(default) 

; P2.1     equ    SEL1   ;*******************
; P2.2     equ    SEL2   ;*******************

;
; The following two signals control the image size to be clocked out
; P2.3 = FMT1         | LOW     | HIGH    | LOW     | HIGH
; P2.4 = FMT2         | LOW     | LOW     | HIGH    | HIGH
;  FRAME SIZE(pixels)  160x120   120x160   120x120   160x160
;                      (default)

; P2.3    equ     FMT1    ;*******************
; P2.4    equ     FMT2    ;*******************

;
; The following three signals control exposure of the camera
; P2.5 = MODE1  LOW selects external exposure, HIGH selects automatic
;               exposure.
; P2.6 = EUP    A HIGH on this pin means that exposure will be increased
;               upon pulses on ECLK. A LOW means exposure will be
;               decreased.
; P2.7 = ECLK   An active high pulse changes the exposure by 6.25% in the
;               direction indicated by EUP (see above). Frequency of ECLK
;               should be less than CLK1 to CCD but need not be synchronous.
;               131 ECLK pulses change exposure from max to min.
;               139 ECLK pulses change exposure from min to max.
;               In moving from min to max, ECLK counts of 54 and 77 must
;               be avoided.
EXP_DEFAULT     equ     08bh        ; 139d pulses take exp from min to max
EXP_CHANGE      equ     07h         ; This is how much exposure is changed
                                    ; in the SEND_IMAGE routine upon receiving
                                    ; an 'L', or a 'U'.
EXP_CHK         equ     0BAh        ; If the middle of the image averages
                                    ; to this number, the exposure is O.K.
LIM             equ     010h        ; Exposure checked in an image can lie in
                                    ; the following range:
                        ; (EXP_CHK - LIM) < IMAGE AVERAGE < (EXP_CHK + LIM)
                
; THE DEFAULT CONTROL BYTE IS ****

;CCD_DEF_CTRL    equ     07h                 ; Default control word for the
;                                            ; CCD, 2.8 fps

CCD_DEF_CTRL    equ     05h                 ; Default control word for the
                                            ; CCD, 5.7 fps

;-------------------------------------------------------------------------
; Synchronization pulses to and from the CCD
;-------------------------------------------------------------------------

; P3.1        equ     FRAME_SYN       ; This signal is an output to the CCD.
                                    ; Upon a HIGH-TO-LOW signal, the CCD is
                                    ; reset. The CCD puts out data as long as
                                    ; this signal is kept LOW...
                                    
; P3.5        equ     PCLK            ; This signal is the PIXEL CLOCK. Valid
                                    ; data is available upon LOW-to-HIGH
                                    ; transition of the signal.
                                    
; P3.7        equ     FRAME_ST        ; A HIGH going pulse on this line
                                    ; indicates the beginning of a new frame.
                                    ; The three pulses on PCLK after this
                                    ; signal goes LOW indicate that the DATA
                                    ; on the data lines is the EXPOSURE
                                    ; SETTING (first two bytes), and the GAIN
                                    ; SETTING (third byte)
;***************************************************************************
; The end of section which defines C166's pin functions w.r.t. CCD interface
;***************************************************************************


;-------------------------------------------------------------------------
;org 80h
;            jmpa    cc_UC, CC_T0_ISR       ; Setup ISR vector

;-------------------------------------------------------------------------
; The following sections declares names for GPRs used for different
; operations in the program, e.g., r5 is used for rough work like reading
; the data into it from P2 and yhen transferring the MSByte into memory
; for storage

;r1      equ     IMAGE_PTR
;r5      equ     RW                         ; GPR 5
;rh5     equ     RW_H                       ; MSByte of GPR5
;rl5     equ     RW_L                       ; LSByte of GPR5
;r7      equ     PIXEL_CTR
;r6      equ     comparator for image size
;-------------------------------------------------------------------------


org 2000h

start:
            calla   cc_UC, INIT             ; Initialize the system

MAIN_LOOP: 
;            calla   cc_UC, START_T5         ; Time the grabbing routine
            calla   cc_UC, GRAB_ONE
;            calla   cc_UC, STOP_T5          ; Find the elapsed time

            mov     r0, #78h                ; Height of image = 120 pixels
            mov     r3, #0a0h               ; Width of image = 160 pixels
            mov     r4, #IMAGE1             ; Set address of image to average
            mov     r6, #028h               ; 40d strips in the image
            calla   cc_UC, V_AV_IMG         ; call the averaging routine

;            calla   cc_UC, CREAT_IMG        ; For debugging &&&&&&&&&&&&&&
;                                            ; USE WITH 'DEBUG.INC'

;            mov     r0, #IMAGE1             ; Set up address of image &
;            mov     r1, #IMAGE_16X12        ; image size for 'SEND_IMAGE'
;            calla   cc_UC, SEND_IMAGE       ; Send image to terminal

            mov     r1, #PATCH_X0_IMG       ; Set x0 of patch in 'IMAGE1'
            mov     r2, #PATCH_Y0_IMG       ; Set y0 of patch in 'IMAGE1'
            mov     r3, #0A0h               ; Width of image = 160 pixels
            mov     r4, #IMAGE1             ; Address of image
            mov     r7, #PATCH_WIDTH        ; Width of patch
            mov     r8, #PATCH              ; Location of 'PATCH' in memory
            mov     r9, #01h                ; Height of patch
            calla   cc_UC, CREAT_PATCH

MATCHING:

            mov     r5, #0h                 ; Set x0 of patch to match
            mov     r6, #0h                 ; Set y of patch to be 0 as 
                                            ; it is a 1d patch
            mov     r7, #PATCH_WIDTH        ; Set width of patch
            mov     r8, #0h                 ; Set x0 in image to start matching
            mov     r9, #PATCH_Y0_IMG       ; Set y in image to be matched over 
            mov     r10, #0a0h              ; Set width of image
            mov     r15, #PATCH             ; Set address of patch
            mov     r13, #0ffffh            ; Set upper threshold for match
            calla   cc_UC, MATCH_PATCH

; **************** The following four instructions take the degree of match
; **************** and display it on the terminal screen on PC.
            calla   cc_UC, CRLF             
            calla   cc_UC, PRSPHX
            mov     r0, r1
            calla   cc_UC, PRSPHX
; ****************

            calla   cc_UC, GRAB_ONE

            calla   cc_UC, START_T5         ; Time the grabbing routine
            mov     r0, #78h                ; Height of image = 120 pixels
            mov     r3, #0a0h               ; Width of image = 160 pixels
            mov     r4, #IMAGE1             ; Set address of image to average
            mov     r6, #028h               ; 40d strips in the image
            calla   cc_UC, V_AV_IMG         ; call the averaging routine
            calla   cc_UC, STOP_T5          ; Find the elapsed time

;            mov     r0, #IMAGE1             ; Set up address of image &
;            mov     r6, #IMAGE_16X12        ; image size for 'SEND_IMAGE'
;            calla   cc_UC, SEND_IMAGE       ; Send image to terminal
;            jmpa    cc_UC, MAIN_LOOP        ; Goto Main loop

            jmpa    cc_UC, MATCHING
;----------------------------------------------------------------------------
; Setup TIMER 4 as a counter to count by 1. Basically, the timer 4 is made
; to act as a counter upon +ve transitions (LOW-to-HI) on T4IN (PCLK). It is
; initially setup and always reinitialized to a value of 0FFFFh so that just
; one transition on T4IN overflows it to 0000h, thus setting T4IR. This flag
; is being monitored by the controller which then reads the current data on
; PORT2 (bits 8-15) as the pixel data corressponding to the current PIXEL_CLK.
; Thus, T4IR should be cleared after reading the data and the value in the
; counter should be reinitialized to 0FFFFh.
;----------------------------------------------------------------------------
SETUP_TMR4:
            push    r1
            mov     r1, #PARM_CTR4
            mov     T4CON, r1
            mov     T4, #0ffffh             ; Setup the T4 register to
                                            ; overflow on next transition
            bclr    T4IR                    ; Clear timer 4's IRQ
            pop     r1 
            ret
;----------------------------------------------------------------------------
; Setup TIMER 2 as a counter to count by 1. Basically, the timer 2 is made
; to act as a counter upon +ve transitions (LOW-to-HI) on T2IN (FRM_ST). It is
; initially setup and always reinitialized to a value of 0FFFFh so that just
; one transition on T2IN overflows it to 0000h, thus setting T2IR. This flag
; is being monitored by the controller which thus finds out that a new frame
; is starting. The next three values on the data lines (each accompnied by
; PCLK) are EXPOSURE SETTING (first two bytes) and gain (third byte).
; Thus, T2IR should be cleared after reading the data and the value in the
; counter should be reinitialized to 0FFFFh.
;----------------------------------------------------------------------------
SETUP_TMR2:
            push    r1
            mov     r1, #PARM_CTR2
            mov     T2CON, r1
            mov     T2, #0ffffh             ; Setup the T2 register to
                                            ; overflow on next transition
            bclr    T2IR                    ; Clear timer 2's IRQ
            pop     r1 
            ret

;----------------------------------------------------------------------------
;                             SETUP_TMR5
; Setup TIMER 5 as a timer to measure time. Basically, the timer 5 is made
; to start from zero upon setting of T5R to 1 and stop at the clearing of T5R.
; It can be used to measure time from the moment START_T5 routine is called to
; the moment STOP_T5 routine is called. STOP_T5 returns a count in r0 and the
; elapsed time is (count x 200ns)
;----------------------------------------------------------------------------
SETUP_TMR5:
            push    r1
            mov     r1, #PARM_TMR5
            mov     T5CON, r1
            mov     T5, #0h
            bclr    T5IR                    ; Clear timer 5's IRQ
            pop     r1 
            ret
;----------------------------------------------------------------------------            
;                              START_T5
; Initializes T5 to 0000h and start the timer
;----------------------------------------------------------------------------
START_T5:
            push    r1
            mov     r1, #00h                ; Clear T5's count
            mov     T5, r1
            pop     r1
            bset    T5R                     ; Start T5
            ret
;----------------------------------------------------------------------------
;                              STOP_T5
; Stops T5 and returns the accumulated time (count really as it has to be
; multiplied with 200ns to get the time) in r0
;----------------------------------------------------------------------------
STOP_T5:
            bclr    T5R                     ; Stop the timer
            mov     r0, T5
            ret
;----------------------------------------------------------------------------
;                               INIT

; Setup ports, default control words, wait states etc.
;----------------------------------------------------------------------------
INIT:
            or      SYSCON, #000fh          ; put wait states to 0
            mov     P2, #CCD_DEF_CTRL       ; Setup default values for CCD
                                            ; Control byte.
            mov     r5, #DIR_P_2            ; Setup the direction bits of P2
            mov     DP2, r5
            bclr    P2.7                    ; Clear ECLK
            mov     r6, #IMAGE_16X12        ; Image size to be grabbed
            mov     r1, #PIX_160            ; Width of image to be grabbed
            movb    X_IMAG_b, rl1           ; Init. image width variable
            mov     r1, #PIX_120            ; Heifht of image to be grabbed
            movb    Y_IMAG_b, rl1           ; Init. image height variable  

            bclr    DP3.5                   ; Set port 3.5 as an input (PCLK)
            bclr    DP3.7                   ; Set port 3.7 as an input (FRM_ST)
            bset    P3.1                    ; Set FRAME_SYN to clear the CCD
            bset    DP3.1                   ; Set P3.1 as output (FRAME_SYN)
            calla   cc_UC, SETUP_TMR4       ; Setup the TIMER 4 as a counter
            calla   cc_UC, SETUP_TMR2       ; Setup the TIMER 2 as a counter
            calla   cc_UC, SETUP_TMR5       ; Setup the TIMER 5 as a timer
            
            mov     r6, #EXP_DEFAULT
            mov     EXPOSURE_b, r6

            calla   cc_UC, SETUP_EXP        ; Setup exposure...
            ret

;----------------------------------------------------------------------------
;                             GRAB_ONE
;
; This routine grabs one frame from the beginning and returns.
;
; Input variables: None
; Returned variables: Exposure(not assigned yet), Gain(not assigned yet),
;                     Image itself
; GPR usage: r1 = pointer to beginning of image
;            r5 = temprory storage of pixel value
;----------------------------------------------------------------------------
GRAB_ONE:
            mov     r1, #IMAGE1             ; Get address for storing data

ACQ_FRM:    bclr    T2IR                    ; clear the T2 IRQ (FRAME_ST) flag
                                            ; to clear any old junk
            mov     T2, #0ffffh             ; Reinitialize the counter

            bclr    P3.1                    ; Clear frame synch. to synch CCD
            bclr    P2.0                    ; Clear the CCD_OE- to allow it
                                            ; to start putting out the image

CHK_T2_1:   jnb     T2IR, CHK_T2_1          ; Wait here until a rising edge on
                                            ; the FRM_ST is observed
            bclr    T2IR                    ; clear the T4 IRQ flag
            mov     T2, #0ffffh             ; Reinitialize the counter

            bclr    T4IR                    ; Clear the T4 IRQ flag (prepare
                                            ; to read pixels)
            mov     T4, #0ffffh             ; Reinitialize the counter

; Wait for the MSByte of exposure setting
CHK_T4EM:   jnb     T4IR, CHK_T4EM          ; Wait here until a rising edge on
                                            ; the PCLK.
; read the MSByte of exposure setting
            bclr    T4IR                    ; clear the T4 IRQ flag
            mov     T4, #0ffffh             ; Reinitialize the counter

; Wait for the LSByte of exposure setting
CHK_T4EL:   jnb     T4IR, CHK_T4EL          ; Wait here until a rising edge on
                                            ; the PCLK.
; read the LSByte of exposure setting
            bclr    T4IR                    ; clear the T4 IRQ flag
            mov     T4, #0ffffh             ; Reinitialize the counter

; Wait for the GAIN setting
CHK_T4G:    jnb     T4IR, CHK_T4G           ; Wait here until a rising edge on
                                            ; the PCLK.
; read the MSByte of gain setting
            bclr    T4IR                    ; clear the T4 IRQ flag
            mov     T4, #0ffffh             ; Reinitialize the counter

CHK_T4:     jnb     T4IR, CHK_T4            ; Wait here until a rising edge on
                                            ; the PCLK.
            mov     r5, P2                  ; Get the data into r5 (RW)
            movb    [r1], rh5               ; Get just the PIXEL data into
                                            ; address pointed to by r1
                                            ; i.e., (IMAGE_PTR) & inc it
            bclr    T4IR                    ; clear the T4 IRQ flag
            mov     T4, #0ffffh             ; Reinitialize the counter
            add     r1, #01h                ; Make dptr point to next location

            jnb     T2IR, CHK_T4            ; If a new frame has not started
                                            ;  then go back for more pixels
                                            ;  of current frame
                                            
            bclr    T2IR                    ; else, clear the T2 IRQ flag
            mov     T2, #0ffffh             ; Reinitialize the counter
            bset    P2.0                    ; Set CCD_OE- to disable it
            bset    P3.1                    ; Set frame synch.
            ret
;----------------------------------------------------------------------------
;                             EXP_LOW
;
; This routine takes the count in r3 and lowers the exposure by that much.
; It also changes the variable EXPOSURE by subtracting r3 from EXPOSURE.
; If 'EXPOSURE' value adds up to less than 0, it becomes 0.
; Receives: r3 = No. of ECLKs the exposure should be lowered by.
;----------------------------------------------------------------------------
EXP_LOW:
            bclr    P2.5
            bclr    P2.6                    ; Make exposure change dir -ve
            push    r1
            push    r2
            push    r3
PULSE_EL:
            bset    P2.7                    ; HIGH on ECLK
            mov     r0, #30h
            calla   cc_UC, PAUSE            ; Wait for a while
            bclr    P2.7                    ; LOW on ECLK
            sub     r3, #01h                ; Decrement ECLKs required
            cmp     r3, #0h                 ; See if all ECLKs are done
            jmpa    cc_UGT, PULSE_EL        ;  If not, go back
            bset    P2.6                    ; Make exposure change dir +ve
            pop     r3                      ; Prepare to calculate 'EXPOSURE'
            mov     r1, #0h                 ; Init. r0
            movb    rl1, EXPOSURE_b         ; Get EXPOSURE
            cmp     r1, r3                  ; Subtract change from old exposure
            jmpa    cc_ULE, EXP_MIN_LO      ; If exposure <= the -ve change, 
                                            ;     goto EXP_MIN_LO
            sub     r1, r3                  ;  else, calc. the new exposure
            movb    EXPOSURE_b, rl1          ; Store the new value of 'EXPOSURE'
            jmpa    cc_UC, EXP_LO_DON
EXP_MIN_LO:
            mov     r1, #0h
            mov     [r2], r1                ; Store the new value of 'EXPOSURE'
EXP_LO_DON:
            pop     r2 
            pop     r1
            movb    rl0, #'D'               ; Setup rl0 so next image is 
                                            ; discarded upon return from this
                                            ; routine                 
            ret
;----------------------------------------------------------------------------
;                             EXP_HI
;
; This routine takes the count in r3 and increases the exposure by that much.
; It also changes the variable EXPOSURE by adding r3 from EXPOSURE.
; If 'EXPOSURE' value adds up to more than 139, it becomes 139.
; Receives: r3 = No. of ECLKs the exposure should be increased by.
;----------------------------------------------------------------------------
EXP_HI:
            bclr    P2.5
            bset    P2.6                    ; Make exposure change dir +ve
            push    r1
            push    r2
            push    r3

PULSE_EH:
            bset    P2.7                    ; HIGH on ECLK
            mov     r0, #30h
            calla   cc_UC, PAUSE            ; Wait for a while
            bclr    P2.7                    ; LOW on ECLK
            sub     r3, #01h                ; Decrement ECLKs required
            cmp     r3, #0h                 ; All pulses done ??
            jmpa    cc_UGT, PULSE_EH        ;  If not, go back

            bset    P2.6                    ; Make exposure change dir +ve
            pop     r3                      ; Prepare to calculate new 'EXPOSURE'
            mov     r1, #0h                 ; Init. r0
            movb    rl1, EXPOSURE_b         ; Get 'EXPOSURE'
            add     r1, r3                  ; Add change from old exposure
            cmp     r1, #EXP_DEFAULT        
            jmpa    cc_ULE, EXP_SET_MAX     ; If new exposure <= the MAX, 
                                            ;     goto EXP_SET_HI
            mov     r1, #08bh               ;  else, new exposure is 139

EXP_SET_MAX:
            movb    EXPOSURE_b, rl1         ; Store new 'EXPOSURE'
EXP_HI_DON:
            pop     r2 
            pop     r1
            movb    rl0, #'D'               ; Setup rl0 so next image is 
                                            ; discarded upon return from this
                                            ; routine                 

            ret
;----------------------------------------------------------------------------
;                             SETUP_EXP
; This routine finds the average of a 16x16 pixel patch in the middle of the
; image and compares it with a suitable constant 'EXP_CHK'. If
; (EXP_CHK - LIM) < IMAGE AVERAGE < (EXP_CHK + LIM), then exposure is all right.
;              r1 (X of pixel), r2 (Y of pixel), r3 (width of image)
;           r4 (base address of image)

;----------------------------------------------------------------------------
SETUP_EXP:
            calla   cc_UC, GRAB_ONE
            calla   cc_UC, GRAB_ONE

            mov     r5, #00h                ; This will have the sum of pixels
            mov     r3, #0a0h               ; Width of image = 160 pixels
            mov     r4, #IMAGE1             ; Set address of image
            mov     r2, #034h               ; Get y of starting pixel

ST_NEW_ROW:
            mov     r1, #48h                ; Get x of starting pixel
SUM_ROW:
            calla   cc_UC, GET_PIXEL
            add     r5, r0
            add     r1, #01h                ;
            cmp     r1, #58h                ; See if the row is done
            jmpa    cc_ULT, SUM_ROW         ; If not, continue with it

            add     r2, #01h
            cmp     r2, #44h                ; See if all the rows done
            jmpa    cc_ULT, ST_NEW_ROW      ; If not, start a new row

            mov     MDL, r5                 ; Make r5 the dividend
            mov     r5, #100h               ; Divide by (16d x 16d = 100h)
            divU    r5                      ; Sum of pixels/# of pixels
            mov     r5, MDL                 ; Get quotient in r5

; **** Following 3 lines for debugging
            calla   cc_UC, CRLF
            mov     r0, r5                  ; Prepare to print to terminal
            calla   cc_UC, PRTHEX
; *****************            
            mov     r0, #EXP_CHK            ; Calculate
            sub     r0, #LIM                ;         EXP_CHK - LIM
            mov     r1, #EXP_CHK            ; Calculate             
            add     r1, #LIM                ;         EXP_CHK + LIM 
            cmp     r5, r0                  ; Check if
                                            ;  IMAGE AVERAGE < (EXP_CHK - LIM)
            jmpa    cc_ULT, INC_EXPOSURE    ; If yes, increase exposure
            cmp     r5, r1                  ; Check if                        
                                            ;  IMAGE AVERAGE > (EXP_CHK - LIM)
            jmpa    cc_UGT, DEC_EXPOSURE    ; If yes, decrease exposure       
            jmpa    cc_UC, EXP_RIGHT        ; If it lies within boundries, good!

INC_EXPOSURE:
            mov     r3, #EXP_CHANGE         ; Increase the exposure by 2
            calla   cc_uc, EXP_HI           ; 
            jmpa    cc_UC, SETUP_EXP        ; Check again

DEC_EXPOSURE:
            mov     r3, #EXP_CHANGE         ; Decrease the exposure by 2
            calla   cc_uc, EXP_LOW          ; 
            jmpa    cc_UC, SETUP_EXP        ; Check again
            
EXP_RIGHT:
            ret
;----------------------------------------------------------------------------
;                                   GET_PIXEL
; This routine the pixel value whose ROW and COLUMN locations are specified
; in r1, and r2. These two variables should be set before calling this
; routine, and the corressponding pixel value will be returned in r0.
;
; This routine assumes a 64KByte memory with DPP0, DPP1, DPP2, and DPP3
; pointing to Pages 0, 1, 2, and 3 respectively.

; (Note: GPRs r5-r8 have not been used to facilitate moving data from one block
; to another by using this routine in combination with the PUT_PIXEL routine
; by calling them successively one after the other with minimal calculations.)

; Receives: r1 (X of pixel), r2 (Y of pixel), r3 (width of image)
;           r4 (base address of image)
; Destroys: r0
; Returns: Value of pixel specified by r1 & r2 in r0
;----------------------------------------------------------------------------

GET_PIXEL:
            push    r1
            push    r2
            push    r3
            push    r4
            mov     r0, #00h                ; Clear r0

; Required pixel's address = (Base address of image1) +
;                            (i.e., width of image) * (Y co-ordinate of pixel)
;                            + (X co-ordinate of pixel)

            mulu    r3, r2                  ; The result is bound to be 16
            mov     r2, MDL                 ; bits, therefore get LS 16 bits
            add     r2, r4
            add     r2, r1
            movb    rl0, [r2]               ; Get pixel value at calculated
                                            ; addr
            pop     r4
            pop     r3
            pop     r2
            pop     r1
            ret
;----------------------------------------------------------------------------
;                                   PUT_PIXEL
; This routine puts the value in rl0 in the pixel location whose ROW and
; COLUMN locations are specified in r1, and r2. These two variables should be
; set before calling this routine.
;
; This routine assumes a 64KByte memory with DPP0, DPP1, DPP2, and DPP3
; pointing to Pages 0, 1, 2, and 3 respectively.

; Receives: r0 pixel value to be assigned, r5 (X of pixel), r6 (Y of pixel),
;           r7 (width of image), r8 (base address of image)

; (Note: GPRs r1-r4 have not been used to facilitate moving data from one block
; to another by using this routine in combination with the GET_PIXEL routine
; by calling them successively one after the other with minimal calculations.)

; Destroys: Nothing
; Returns:  Nothing
;----------------------------------------------------------------------------

PUT_PIXEL:
            push    r5
            push    r6
            push    r7
            push    r8

; Required pixel's address = (Base address of image1) +
;                            (i.e., width of image) * (Y co-ordinate of pixel)
;                            + (X co-ordinate of pixel)

            mulu    r7, r6                  ; The result is bound to be 16
            mov     r6, MDL                 ; bits, therefore get LS 16 bits
            add     r6, r8
            add     r6, r5
            movb    [r6], rl0               ; Get pixel value at calculated
                                            ; addr
            pop     r8
            pop     r7
            pop     r6
            pop     r5
            ret
;----------------------------------------------------------------------------
;                                CREAT_PATCH
;
; This routine creates a patch in the image 'IMAGE1' in a seperate memory
; block. The location, width, and height of the patch in 'IMAGE1' must be
; specified in GPRs. Also, the width and height of patch must be specified in
; GPRs. The routine will place the 'x' and 'y' of the first pixel in the
; variables 'X0_PAT_b' and 'Y0_PAT_b'and width and height of patch in the
; variables 'WTH_PAT_b', 'HGT_PAT_b' whose old contents will be destroyed.

; Destroys: Old contents of memory block where the patch is stored.

; GPR usage: rl0 = pixel data, 
;            r1 = x (column) of 1st pixel of patch in image
;            r2 = y (row) of 1st pixel of patch in image
;            r3 = Width of image 'IMAGE1'
;            r4 = Base address of image 'IMAGE1'
;            r5 = x being written in the patch
;            r6 = y being written in the patch
;            r7 = Width of patch
;            r8 = Base address of memory block
;                 where the patch is stored
;            r9 = Height of patch

; Receives: r1-r4, r7-r8 with contents as pointed out above.
; Returns:  x0 of patch in the 'IMAGE1' in variable 'X0_PAT_b'
;           y0 of patch in the 'IMAGE1' in variable 'Y0_PAT_b'
;           width of patch in variable 'WTH_PAT_b'
;           height of patch in variable 'HGT_PAT_b'
; Destroys: r1, r5, r6, r10

;----------------------------------------------------------------------------
CREAT_PATCH:
            mov     r10, r1                 ; Save x0 of patch in 'IMAGE1'
                                            ; for future recovery in this
                                            ; routine.

            mov     r5, #X0_PAT_b           ; Save x0 of patch in 'IMAGE1'
            movb    [r5], rl1
            mov     r5, #Y0_PAT_b           ; Save y0 of patch in 'IMAGE1'
            movb    [r5], rl2
            mov     r5, #WTH_PAT_b          ; Save width of patch in 'IMAGE1'
            mov     r0, r7                  ; r7 is not byte addressable
            movb    [r5], rl0               ; Write byte
            mov     r5, #HGT_PAT_b          ; Save height of patch in 'IMAGE1'
            mov     r0, r9                  ; r9 is not byte addressable
            movb    [r5], rl0               ; Write byte
            mov     r5, #00h                ; Initialize x in patch
            mov     r6, #00h                ; Initialize y in patch

WR_PAT_PIX:
            calla   cc_UC, GET_PIXEL
            calla   cc_UC, PUT_PIXEL
            add     r1, #01h                ; Point to next column in 'IMAGE1'
            add     r5, #01h                ; Inc column
            cmp     r7, r5                  ; Compare r5 with r7
            jmpa    cc_UGT, WR_PAT_PIX
            mov     r1, r10                 ; Restore x0 of patch in 'IMAGE1'
            add     r2, #01h                ; Point to next line in 'IMAGE1'
            mov     r5, #00h                ; Refresh the col # for the next line
            add     r6, #01h                ; Inc line
            cmp     r9, r6                  ; Compare r9 with r6
            jmpa    cc_UGT, WR_PAT_PIX

            ret
;----------------------------------------------------------------------------
;                                V_AV_IMG
;
; This routine averages a part of the image in the vertical direction. The
; location, width, and height of the image must be specified in GPRs before
; calling this routine. This routine also needs the number of strips of 
; averaged rows, e.g., if a 120 line high image is to be averaged over 3 line
; high strips, it would result in an image in which there would be 40 strips
; with each strip consisting of three lines and the data in each column of
; each strip (3 pixels) would be identical. Even though the resulting image
; can be stored in 1/NO_STRIPS of space of the original image, for simplicity,
; the image will be stored over the same space as the original image.
;                  The no. of strips in the image must be an integral multiple
; of the total number of horizontal lines in the image.
;                  This routine starts by calculating the number of lines in
; each strip based on the height of the image and no. of strips required.
; Then it sums the columns in the each strip and divides the sum by the the
; number of pixels in each column of each strip to calculate the average.
; It then overwrites the specified region with the averaged value. The whole
; image will be averaged this way strip by strip. This way the image can be
; split in as many horizontal strips (averaged vertically) as desired. This
; also gives the freedom to average a thin strip or a thick one by simply
; changing the no. of strips in the image.

; Destroys: Old contents of memory block of the averaged region.

; GPR usage: r0 = Height of image (value received by the routine)
;            rl0 = pixel data (usage during the routine) 
;            r1 = x (column) of 1st pixel of patch in image
;            r2 = y (row) of 1st pixel of patch in image
;            r3 = Width of image 'IMAGE1' (for 'GET_PIXEL' routine)
;            r4 = Base address of image 'IMAGE1' (for 'GET_PIXEL' routine)
;            r5 = The x being written in 'IMAGE1'
;            r6 = The y being written in 'IMAGE1' (usage during the routine)
;            r6 = No. of patches required (Received by the routine)
;                 (This number must be less than half of height of image to
;                  allow atleast 2 line averaged strips. Also, this number
;                  must be such that the height of the image is an integral
;                  multiple of this number)
;            r7 = Width of image 'IMAGE1' (for 'PUT_PIXEL' routine)
;            r8 = Base address of image 'IMAGE1' (for 'PUT_PIXEL' routine)
;            r9 = Lines/strip
;            r10 = line count for current strip being averaged
;            r11 = x0 of current strip being averaged
;            r12 = y0 of current strip being averaged
;            r13 = sum of pixels of the current column of the current strip
;            r14 = Height of image (initialized by r0)

; Receives: r0, r3, r4, r6 with contents as pointed out above.
; Returns:  The image in form of averaged strips

; Destroys: 

;----------------------------------------------------------------------------
V_AV_IMG:
            mov     r14, r0                 ; Store height of image
            mov     MDL, r0                 ; Put the height of image as dividend
            mov     MDH, #00h               ; Clear MDH
            divu    r6                      ; Perform Height_IMG/#_STRIPS =
                                            ;    lines/strip
            mov     r9, MDL

            mov     r1, #0h                 ; Initialize the column pointers
            mov     r5, #0h                 ; for routines 'GET_PIXEL' and
                                            ; 'PUT_PIXEL'.

            mov     r11, #0h                ; Initialize x0, and y0 of current
            mov     r12, #0h                ; strip to point to the top left
                                            ; of the first strip...
            mov     r7, r3                  ; Set width of image for 'PUT_PIXEL'
                                            ; routine
            mov     r8, r4                  ; Set base address of image for 
                                            ; 'PUT_PIXEL'

AV_A_COL:   
            mov     r2, r12                 ; Make y for 'GET_PIXEL' &
            mov     r6, r12                 ; 'PUT_PIXEL' point to y0 of
                                            ; current strip
            mov     r10, #0h                ; Make the line count for the
                                            ; current strip equal to zero
            mov     r13, #0h                ; Init SIGMA Pix x,y

GET_COL_PIX:                                ; r1, r2 and r5, r6 must already
            calla   cc_UC, GET_PIXEL        ;  be pointing to right addresses
            add     r13, r0
            add     r2, #01h
            add     r10, #01h               ; Dec the lines/strip
            cmp     r10, r9                 ; See if the whole column of the
                                            ; line is summed.
            jmpa    cc_ULT, GET_COL_PIX     ;    if not, go back...

            mov     MDL, r13                ;    if yes, find the average
            mov     MDH, #0h                ;    i.e., 
            divu    r9                      ;        (SIGMA Pix x,y / y)
            mov     r0, MDL                 ; Put the averaged val in r0
            mov     r10, #0h                ; Init line count for writing
                                            ; the current strip.

PUT_COL_PIX:
            calla   cc_UC, PUT_PIXEL
            add     r6, #01                 ; Increment the dest. for next val
            add     r10, #01h               ; Increment line no. in strip
            cmp     r10, r9                 ; Check if the whole column of the
                                            ; line has been written.
            jmpa    cc_ULT, PUT_COL_PIX     ;    if not, go back...
            add     r1, #01h                ;    if yes, point to the next col
            add     r5, #01h
            cmp     r5, r7                  ; Check if the whole strip averaged
            jmpa    cc_ULT, AV_A_COL        ;  If yes, check if all strips done
            cmp     r6, r14                 ; If at the end of the strip's right
                                            ; end, check to see if at the end of image.
            jmpa    CC_UGE, DONE_V_AVG
            mov     r12, r6                 ; The current line number is the
                                            ; first line in the next strip to
                                            ; which is to be averaged. The next
                                            ; strip is just below the current
                                            ; one
            mov     r1, #0h                 ; Make line numbers for 'GET_PIXEL'
            mov     r5, #0h                 ; and 'PUT_PIXEL' routines point
                                            ; to the top of the image
            jmpa    cc_UC, AV_A_COL

DONE_V_AVG:            
            ret

;----------------------------------------------------------------------------
;                           MATCH_PATCH
;
; This routine matches a one dimensional across the width of a vertically
; averaged image. It uses the following relation to find the best match:
;
; min(x) SIGMA(i=0 --> i=N-1) |Patch_pix(i) - Image_pix(i+x)|
; The above summation is repeated for each value of x from x=0 to
; x=Width_of_image - Width_of_patch. The value of x for which the summation
; gives the lowest answer is probably the patch we are looking for and its
; location in the current image is given by x

; Destroys the old contents of registers used below
; Receives: r5 = x_start_of_patch, r6 = y_start_of_patch, r7 = patch_width
;           r8 = x_img, r9 = y_img, r10 = img_width, 
;           r13 = upper threshold for the match (Should be 0ffffh if no 
;                 guesses are made). Suppose a patch is matched across a row
;                 and a match is found, then the upper row or lower or both 
;                 can be searched with the value obtained from the first search
;                 as a threshold. Each of these patch searches will tell if 
;                 a better match was found or not and depending on the 'y' in
;                 image of these searches, it might be possible to determine
;                 vertical motion. 
;           r15 = patch address
;
; Returns: r0 = best match, r1 = location of patch in image
;            if r0 = same as original r13, means no match found. 
;            High values mean no match or barely a match
;
; GPR usage: rl0 = pixel data (usage during the routine) & general 
;            r1 = x (column) of 1st pixel of patch in image (for 'GET_PIXEL')
;            r2 = y (row) of 1st pixel of patch in image (for 'GET_PIXEL')
;            r3 = Width of image 'IMAGE1' (for 'GET_PIXEL' routine)
;            r4 = Base address of image 'IMAGE1' (for 'GET_PIXEL' routine)
;            r5 = x_start_of_patch 
;            r6 = y_start_of_patch
;            r7 = patch_width
;            r8 = x_img
;            r9 = y_img
;            r10 = img_width
;            r11 = SIGMA(r5=0 --> r5=patch_w) |Pat_pix(r5) - Img_pix(r5+r8)|
;            r12 = Pat_pix
;            r13 = Best_match
;            r14 = Best_match's x
;            r15 = patch address

;----------------------------------------------------------------------------
MATCH_PATCH:
            mov     r13, #0ffffh
            mov     r11, #0h
            
MATCH_N_COL:
            mov     r1, r5
            mov     r2, r6
            mov     r3, r7
            mov     r4, r15
            calla   cc_UC, GET_PIXEL
            mov     r12, r0
;            push    r0                      ; DEBUGGING &&&&&&&&&&&&&&&&
            
            mov     r1, r8
            add     r1, r5                  ; Calculate which pixel in the
            mov     r2, r9                  ; image is to be compared depending
                                            ; on the corressponding pixel no
                                            ; in the patch
            mov     r3, r10
            mov     r4, #IMAGE1
            calla   cc_UC, GET_PIXEL
            
            sub     r12, r0                 ; diff_pix = pat_pix - img_pix
            jnb     PSW.0, POS_ANS          ; If the ans of above calc. was
                                            ; +ve, don't change its sign
            neg     r12                     ;   if it was -ve, DO
            
POS_ANS:    add     r11, r12                ; Find SIGMA ... af all till now
            add     r5, #01h                ; Point to next pixel in patch
;            pop     r4                      ; Debugging &&&&&&&&&&&&&&&&&&&&&
;            nop                             ; debugging BP no log  &&&&&&&&&&
;            nop                             ; debugging BP log  &&&&&&&&&&&&&
            cmp     r5, r7
            jmpa    cc_ULT, MATCH_N_COL     ; Go back if whole patch not matched                        
            cmp     r11, r13                ; Whole patch done. check if this
                                            ; matching with the best till now
            jmpa    cc_UGE, NO_REPLACE      ; If this is not better, go there                                                                           
            mov     r13, r11                ;   else, replace old best with
            mov     r14, r8                 ;   the new best with its x-pixel
                                            ;   location in image
            
NO_REPLACE:
            mov     r11, #0h                ; Init the SIGMA register
            mov     r5, #0h                 ; Re-init patch's x0 so that the
                                            ; comparison can start from 
                                            ; beginning of patch
            add     r8, #01h                ; Increment x0 og image so that
                                            ; the patch may be matched to
                                            ; a region one pixel right of
                                            ; the previous comparison

            mov      r0, #0h                ; Check if the patch has been
            add      r0, r8                 ; fully moved across the image
            add      r0, r7
            nop                             ; DEBUGGING BP no logging &&&&&&
            nop                             ; DEBUGGING BP  logging &&&&&&
            cmp      r0, r10                                               
            jmpa     cc_ULT, MATCH_N_COL    ;  if not, go back and compare
                                            ;  another patch

            mov      r0, r13                ; Best match returned in r0
            mov      r1, r14                ;  & its location in r1
            nop                             ; DEBUGGING log, stop, &&&&&&&&
            ret                                                                
            

;----------------------------------------------------------------------------

; INCLUDE FILES:

#include "ser_166.inc"
#include "debug.inc"

;----------------------------------------------------------------------------
org 4000h
;-------------------------- VARIABLES & DATA------------------------------
EVEN
    EXPOSURE_b: db  0               ; Stores the exposure setting (ECLK count)
    X0_PAT_b:   db  0               ; Stores X0 location of patch in image
    Y0_PAT_b:   db  0               ; Stores Y0 location of patch in image
    WTH_PAT_b:  db  0               ; Stores patch's width in no. of pixels(columns)
    HGT_PAT_b:  db  0               ; Stores patch's height in no. of pixels(rows)
    PATCH:      ds  PATCH_SIZE      ; Location for storing the patch                              

    X_IMAG_b:   db  0               ; Reserve a byte for width of image
    Y_IMAG_b:   db  0               ; Reserve a byte for height of image

    IMAGE1:     db  127             ; Next 25K is for image data

; END OF FILE
