home *** CD-ROM | disk | FTP | other *** search
/ Piper's Pit BBS/FTP: ibm 0040 - 0049 / ibm0040-0049 / ibm0040.tar / ibm0040 / IMGPROC.ZIP / C4.ZIP / DIGITIZE.ASM next >
Encoding:
Assembly Source File  |  1990-04-06  |  28.1 KB  |  978 lines

  1. ;Copyright 1990 by John Wiley & Sons, Inc.
  2. ;          All Rights Reserved.
  3. ;
  4. ;Generic Video Digitizer Routines in Turbo C - Computer Independent
  5. ;
  6. ; This version utilizes the 8253 timer/counter to time the sync pulses
  7. ; and should therefore be somewhat PC independent.
  8. ;
  9. ; written by Craig A. Lindley
  10. ; last update: 05/17/89
  11. ;
  12. ;NOTE: most code in this file is written as inline code for speed reasons.
  13. ;      Any change to this structure might stop the digitizer from working.
  14. ;      Any change in register usage might also cause it to stop working.
  15. ;      Be careful changing the parameter passing linkage with C.
  16. ;
  17. _TEXT    segment    byte public 'CODE'
  18.       DGROUP    group    _DATA,_BSS
  19.       assume    cs:_TEXT,ds:DGROUP,ss:DGROUP
  20. _TEXT    ends
  21.  
  22. _DATA    segment word public 'DATA'
  23. ;
  24. Field1Found    DW    False    ;True after field 1 of video located
  25. Field1Done      DW      False   ;True after field 1 has been digitized
  26.  
  27. PrtPortData    DW    0    ;data output port
  28. PrtPortIn    DW    0    ;data input port (5 bits)
  29. PrtPortCont    DW      0    ;cont lines output port
  30. ImageReqPtr    DW    0    ;ImageReq structure pointer passed from C
  31. DigitInit    DW    False    ;True when digitizer has been initialized
  32. CompType    DW    0    ;Holds type of PC configured
  33. ;
  34. ;these variables are only used when digitizing an Interlaced image. They
  35. ;contain the address of where the next column of digitized video will be
  36. ;stored. they are necessary because Interlaced data in a single frame must
  37. ;be stored in sequential locations in the picture buffer. because two passes
  38. ;through the picture buffer are necessary it is necessary to save when the
  39. ;next column of video should be stored when we get to digitizing it.
  40. ;
  41. PColSeg         DW      0       ;segment for storage for this column of video
  42. PColOff         DW      0       ;Offset in PColSeg for this column storage
  43. ;
  44. _DATA    ends
  45.  
  46. _BSS    segment word public 'BSS'
  47. _BSS    ends
  48. ;
  49. ;
  50. ;General Definitions
  51. ;
  52. True        EQU    0FFH        ;all ones is true
  53. False        EQU    0        ;all zeros is false
  54. SegOff        EQU    (0FFFFH/10H)+1    ;paragraphs/segment
  55. ;
  56. ;PrtPortCont bit definitions
  57. ;
  58. Strobe        EQU    1        ;used to latch pixel count data
  59. SyncReset    EQU    2        ;reset for sync latch
  60. Go        EQU    4        ;starts pixel counter
  61. HighLow        EQU    8        ;selects highlow pixel count latch
  62.                     ;and highlow output data
  63. PrtPortContSafe    EQU    0BH        ;when written to PrtPortCont
  64.                     ;forces all bits (4) to zero. Go bit
  65.                     ;is special because it has inverter
  66.                     ;in the hardware.
  67. ;Bit combinations
  68. ;
  69. SetGo            EQU    PrtPortContSafe OR  Go
  70. SetStrobe        EQU    PrtPortContSafe AND NOT Strobe
  71. SetHighLow        EQU    PrtPortContSafe AND NOT HighLow
  72. SetHighLowAndGo        EQU    PrtPortContSafe AND NOT HighLow OR Go
  73. SetSyncReset        EQU    PrtPortContSafe AND NOT SyncReset
  74. SetHighLowAndStrobe    EQU    PrtPortContSafe AND NOT HighLow AND NOT Strobe
  75. SetSyncResetAndGo    EQU    PrtPortContSafe AND NOT SyncReset OR Go
  76. ResetSyncAndEOC        EQU    PrtPortContSafe AND NOT SyncReset AND NOT HighLow
  77. ;
  78. ;PrtPortIn bit definitions
  79. ;
  80. SyncEOC        EQU    8        ;bit monitored to detect sync
  81.                     ;and end of conversion (EOC).
  82. ;
  83. ;Video specific definitions
  84. ;
  85. HBlankingOffset    EQU    47        ;additional count required for horiz
  86.                     ;blanking. 3.81 usec from rising edge
  87.                     ;of sync pulse at 12.38 MHz.
  88. VBlankingOffset    EQU    16        ;sync pulses to consume before active
  89.                     ;video in field.
  90. SyncsField1    EQU    272        ;Number of sync pulses in field 1
  91. SyncsField2    EQU    271        ;ditto for field 2
  92. ;
  93. ;ImageReq definitions
  94. ;
  95. ;This structure is sent to this code from the high level C code to tell the
  96. ;digitizer what to digitize. This declaration does not allocate space, it
  97. ;just defines the offsets of the various fields. It must correspond exactly
  98. ;with the C structure ImageReq defined in the file gvideo.h for things to
  99. ;work properly.
  100. ;
  101. ImageReq    struc
  102. ;
  103. ComputerType    DW    0    ;used to adjust delays according to CPU speed
  104. PrtBase        DW    0    ;printer port to use with digitizer
  105. HMode        DW    0    ;low or high resolution mode selector 320/640
  106.                 ;pixels per line.
  107. VMode        DW    0    ;non Interlace or Interlace mode. 200/480
  108.                 ;lines per frame of video.
  109. NumberOfPasses    DW    0    ;determines number of passes across video
  110. Flags        DD    0    ;misc flags
  111. PictBufOff    DW    0    ;Offset/Segment of picture buffer
  112. PictBufSeg    DW    0
  113. FirstLine    DW    0       ;digitized portion of video selectors
  114. FirstPixel    DW    0
  115. LastLine    DW    0
  116. LastPixel    DW    0
  117. ;
  118. ImageReq    ends
  119. ;
  120. ;The following are the equates for the various PC types. The delay MACROs
  121. ;must be adjusted to the speed of the PC. These are used to decode the
  122. ;configured type of PC and adjust the delay MACROs accordingly. These are
  123. ;all possible entries into the ComputerType field of the ImageReq.
  124. ;
  125. PC477        EQU    0
  126. PCAT6        EQU    1
  127. PCAT8        EQU    2
  128. PS210        EQU    3
  129. PS216        EQU    4
  130. PS220        EQU    5
  131. PS225        EQU    6
  132. PS233        EQU    7
  133.  
  134. LowRes        EQU    0        ;320 pixels/line
  135. HighRes        EQU    1        ;640 pixels/line
  136. NonInterlace    EQU    0        ;acquire a single field of video
  137. Interlace    EQU    1        ;acquire a frame of video
  138. ;
  139. ;
  140. ;8253 Timer Definitions
  141. ;Timer 2 is used for the timing of the sync pulses. This is a more accurate
  142. ;method than a software loop. All PCs have this timer/counter available
  143. ;it is normally used to produce the beep for the keyboard.
  144. ;
  145. ;The following are timer and I/O port addresses
  146. ;
  147. Timer2CountReg    EQU    42H        ;used to set counter values
  148. TimerCmdReg    EQU    43H        ;used to send mode cmds to timer chip
  149. Timer2GateReg    EQU    61H        ;gate reg 8255s address
  150. TermBitReg    EQU    62H        ;term bit reg 8255s address
  151. ;
  152. ;The following are bit assignments, masks and mode bytes
  153. ;
  154. TimerCount    EQU    18        ;at 840 nsec period =~ 15 usec
  155. Timer2GateBit    EQU    01H        ;gate is bit 0 of 8255 port
  156. TermCntBitMask    EQU    20H        ;term bit is bit 5 of 8255 port
  157. Timer2Mode    EQU    0B2H        ;timer 2 select; load LSB then MSB
  158.                     ;counter mode = 1; binary counter
  159. ;
  160. _TEXT    segment    byte public 'CODE'
  161. ;
  162. ;Delay MACROs
  163. ;
  164. ;Short delay. This is used to allow the computers bus to recover between
  165. ;sequential accesses of the same I/O port.
  166. ;
  167. SDelay    MACRO
  168.     jmp    short $+2
  169.     jmp    short $+2
  170.     ENDM
  171. ;
  172. ;Strobe delay. This is used to make sure the software generated strobes are
  173. ;long enough for the hardware to see.
  174. ;
  175. StbDel    MACRO
  176.     push    ax
  177.     pop    ax
  178.     push    ax
  179.     pop    ax
  180.     push    ax
  181.     pop    ax
  182.     push    ax
  183.     pop    ax
  184.     ENDM
  185. ;
  186. ;Start of Assembly Language Procedures
  187. ;
  188. ;
  189. ; Procedure InitializeTimer2
  190. ;
  191. ; This procedure sets up the 8253 timer for use as a sync timer. Mode 1 of
  192. ; the counter is utilized. In this mode, when the gate signal transitions
  193. ; from a low to a high level, the counter is loaded with a previously set
  194. ; value and the counter starts counting down towards zero. When zero is
  195. ; reached, the terminal bit goes from a low to a high level. This procedure
  196. ; sets the mode for timer 2 and sets in the count for use by the Delay
  197. ; procedure.
  198. ;
  199. ; INPUT:  none.
  200. ; OUTPUT: none but timer 2 is initialized and the count is loaded.
  201. ; USES:   ax register.
  202. ; CALL:   not callable from C.
  203. ;
  204. ;
  205. InitializeTimer2    proc    near
  206. ;
  207.     mov    al,Timer2Mode        ;load mode value
  208.     out    TimerCmdReg,al        ;send it to the 8253
  209.  
  210.     SDelay
  211.  
  212.     mov    ax,TimerCount        ;get the timers count
  213.     out    Timer2CountReg,al    ;set the LSB of the count
  214.  
  215.     SDelay
  216.  
  217.     mov    al,ah            ;get the MSB of count
  218.     out    Timer2CountReg,al    ;set the MSB of the count
  219.  
  220.     ret
  221. ;
  222. InitializeTImer2    endp
  223. ;
  224. ; Procedure Delay
  225. ;
  226. ; This procedure uses timer 2 to delay for approximately 15 microseconds
  227. ; time it is called.
  228. ;
  229. ; INPUT:  none.
  230. ; OUTPUT: none but timer 2 is used to produce a delay
  231. ; USES:   ax register
  232. ; CALL:   not callable from C.
  233. ;
  234. ;
  235. Delay    proc    near
  236. ;
  237.     push    dx            ;save register
  238.     in    al,Timer2GateReg    ;read the 8255 port
  239.  
  240.     SDelay
  241.  
  242.     and    al,NOT Timer2GateBit    ;set bit 0 low
  243.     out    Timer2GateReg,al    ;set gate bit low at timer 2
  244.  
  245.     SDelay
  246.  
  247.     or    al,Timer2GateBit    ;set bit 0 high
  248.     out    Timer2GateReg,al    ;set gate bit high at timer 2
  249.  
  250.     SDelay
  251.  
  252. Del1:    in    al,TermBitReg        ;read the terminal bit port
  253.     and    al,TermCntBitMask    ;is the timer period over ?
  254.     jnz    Del2            ;if yes jmp
  255.  
  256.     SDelay
  257.  
  258.     jmp    short    Del1
  259. ;
  260. Del2:   SDelay
  261.     pop    dx            ;restore register
  262.     ret
  263. ;
  264. Delay    endp
  265. ;
  266. ;
  267. ; Procedure InitializeDigitizer
  268. ;
  269. ; This procedure initializes the digitizer hardware in preparation
  270. ; for usage. It is necessary to set the bits in the PrtPortCont latch
  271. ; to initialize digitizer. The HighLow line must be strobed to clear
  272. ; the SyncEOC line (because the EOC latch is then reset). If this is not
  273. ; done it is possible that the SyncEOC line will remain in a low state
  274. ; forever not allowing the Sync signal to leave the digitizer.
  275. ;
  276. ; INPUT:  near pointer to the ImageReq data structure.
  277. ; OUTPUT: none but the digitizer hardware is initialized.
  278. ; USES:   ax,bx,dx registers.
  279. ; CALL:   callable from C.
  280. ; PROTOTYPE: InitializeDigitizer(sturct ImageReq *)
  281. ;
  282.     Public    _InitializeDigitizer
  283. ;
  284. _InitializeDigitizer    proc    near
  285. ;
  286.     push    bp                  ;prepare to retrieve the near pointer
  287.     mov    bp,sp            ;to the ImageReq structure
  288. ;
  289. ;get and store the pointer from C which points at the ImageReq structure
  290. ;
  291.     mov    bx,[bp+4]        ;bx pts at ImageReq
  292.     mov    ImageReqPtr,bx        ;save in local var
  293. ;
  294. ;first thing to do is to retrieve the address of the printer port to use
  295. ;for the digitizer. we must know this for any communication with the
  296. ;digitizer. with the base address ,PrtBase, of the port known, we can easily
  297. ;calculate the other important port addresses.
  298. ;
  299.     mov    ax,[bx].PrtBase        ;get port number to use
  300.     mov    PrtPortData,ax
  301.     inc    ax            ;port+1= PrtPortIn
  302.     mov    PrtPortIn,ax
  303.     inc    ax            ;port+2= PrtPortCont
  304.     mov    PrtPortCont,ax
  305.     mov    ax,[bx].ComputerType    ;read the computer type
  306.     mov    CompType,ax        ;store locally in ds
  307. ;
  308. ;now start the initialization of the digitizer hardware
  309. ;
  310.     mov    dx,PrtPortCont        ;pt at control latch bits
  311.     mov    al,PrtPortContSafe    ;initialize control bits
  312.     out    dx,al            ;sent to the digitizer
  313. ;
  314.     call    Delay            ;let things stabilize
  315. ;
  316.     mov    al,ResetSyncAndEOC    ;set HighLow bit high
  317.     out    dx,al            ;to clear EOC input to
  318.  
  319.     StbDel
  320. ;
  321.     mov    al,PrtPortContSafe    ;initialize control bits
  322.     out    dx,al            ;sent to the digitizer
  323.  
  324.     SDelay
  325.  
  326.     mov    ax,0            ;set pixel count to 0
  327.     call    SetPixelCount           ;send to hardware counters
  328.  
  329.     SDelay
  330.  
  331.     call    InitializeTimer2    ;initialize the sync timer
  332.     mov    DigitInit,True        ;indicate the digitizer has been
  333.                     ;initialized.
  334.     pop    bp            ;restore bp to enable a return
  335.     ret                             ;to C code.
  336. ;
  337. _InitializeDigitizer    endp
  338. ;
  339. ;
  340. ; Procedure _SyncsPerField
  341. ;
  342. ; This procedure counts the number of sync pulses (of all variety) that
  343. ; occur in a single field of video. It must do its counting in 1/30 of
  344. ; a second field time. Field 1 should contain 272 syncs while field 2
  345. ; should contain 271.
  346. ;
  347. ; INPUT:  none.
  348. ; OUTPUT: number of syncs in the monitored field returned in ax.
  349. ; USES:   ax,cx,dx registers. bx perserved.
  350. ; CALL:   callable from C.
  351. ; PROTOTYPE: unsigned short SyncsPerField ( void )
  352. ;
  353.     Public    _SyncsPerField
  354. ;
  355. _SyncsPerField    proc    near
  356. ;
  357.         cli                            ;interrupts off
  358.         call    SyncsPerField          ;count them
  359.         sti                            ;ints back on
  360.         ret
  361. ;
  362. _SyncsPerField    endp
  363. ;
  364. ;
  365. ; Procedure SyncsPerField
  366. ;
  367. ; See discussion above
  368. ;
  369. ; INPUT:  none.
  370. ; OUTPUT: number of syncs in the monitored field returned in ax.
  371. ; USES:   ax,cx,dx registers. bx perserved.
  372. ; CALL:   not callable from C.
  373. ;
  374. ;
  375. SyncsPerField    proc    near
  376. ;
  377.     push    bx                      ;save register
  378.     mov    bx,7            ;initialize count to include all
  379.                                         ;vertical syncs will will miss
  380.         mov     dx,PrtPortCont          ;pt at control register
  381.     mov    al,ResetSyncAndEOC    ;hold sync latch and EOC reset
  382.     out    dx,al            ;so only actual sync signal will
  383.                                         ;be seen by the hardware.
  384.     SDelay
  385. ;
  386. ;read SyncEOC line to see if it is low
  387. ;
  388.     dec    dx            ;pt back at PrtPortIn
  389. spf1:    in    al,dx            ;read data in
  390.     and    al,SyncEOC
  391.     jz    spf1            ;jump if SyncEOC is still low.
  392. ;
  393. ;check once again. A vertical sync interval would never be high two
  394. ;reads in a row.
  395. ;
  396.     call    Delay
  397.     in    al,dx
  398.     and    al,SyncEOC
  399.     jz    spf1            ;jump if long sync. Line still low.
  400.  
  401.     SDelay
  402. ;
  403. ;when we get here a short sync interval has been detected. Now find
  404. ;the first long sync (vertical sync) interval with which to start the
  405. ;sync count.
  406. ;
  407.         call    FindLongSync
  408. ;
  409. ;1st long sync pulse found. Advance to 1st short sync interval
  410. ;
  411. spf2:    in    al,dx
  412.     and    al,SyncEOC
  413.     jz    spf2            ;jump if SyncEOC is still low.
  414. ;
  415. ;check again.
  416. ;
  417.     call    Delay
  418.     in    al,dx
  419.     and    al,SyncEOC
  420.     jz    spf2            ;jump if long sync. Line still low.
  421.  
  422.     SDelay
  423. ;
  424. ;short sync interval found again. Count up all syncs until new long sync
  425. ;is found. This indicates end of field.
  426. ;
  427. spf3:    in    al,dx            ;read input port
  428.     and    al,SyncEOC        ;mask all but sync bit
  429.     jnz    spf3            ;loop until bit active (low)
  430.  
  431.     SDelay
  432. ;
  433. ;Sync latch has gone low. Reset it.
  434. ;
  435.     inc    dx            ;now pt dx at PrtPortCont for output
  436.     mov    al,ResetSyncAndEOC    ;set SyncReset high
  437.     out    dx,al            ;do it
  438.  
  439.     StbDel
  440.  
  441.     mov    al,PrtPortContSafe    ;end SyncReset pulse
  442.     out    dx,al            ;do it
  443.  
  444. ;
  445. ;read again. Short syncs should be gone
  446. ;
  447.     call    Delay
  448.     dec    dx            ;pt back at PrtPortIn
  449.     in    al,dx
  450.     and    al,SyncEOC
  451.     jz    spf4            ;we're done when long sync detected
  452.     inc    bx            ;count the short sync
  453.     jmp    spf3            ;continue looking for long
  454. ;
  455. spf4:   inc     dx                      ;pt at control port
  456.         mov    al,ResetSyncAndEOC    ;set Sync and EOC reset high
  457.     out    dx,al
  458.  
  459.     SDelay
  460.  
  461.         dec     dx                      ;pt back at input
  462. ;
  463.     mov    ax,bx            ;result in ax for return
  464.     pop    bx
  465.     ret
  466. ;
  467. SyncsPerField    endp
  468. ;
  469. ;
  470. ; Procedure FindLongSync
  471. ;
  472. ; Assumes it is called during active video line. That is, short syncs
  473. ; are being detected. In the routine, we set the sync reset line and the
  474. ; EOC reset line (HighLow) and leave them. We are only interested in the
  475. ; detection of long (vertical) sync periods so we don't need the assistance
  476. ; of the on board sync latch IC8a. Setting these lines guarantees that only
  477. ; the actual sync pulse will be seen on the SyncEOC line. This saves us
  478. ; the time in resetting the latch inside of the loop.
  479. ;
  480. ; INPUT:  none
  481. ; OUTPUT: none but returns when long sync interval detected
  482. ; USES:   ax, dx registers
  483. ; CALL:   not callable from C.
  484. ; PROTOTYPE: none
  485. ;
  486. FindLongSync    proc    near
  487. ;
  488.     mov    dx,PrtPortCont        ;pt at control port
  489.     mov    al,ResetSyncAndEOC      ;set both sync and EOC reset bits
  490.     out    dx,al
  491.  
  492.     SDelay
  493.  
  494.     dec    dx            ;pt at input port
  495. fls1:    in    al,dx            ;read input port
  496.     and    al,SyncEOC        ;mask all but sync bit
  497.     jnz    fls1            ;loop until bit active (low)
  498. ;
  499. ;Sync latch has gone low. By the time we realize it and read port again
  500. ;all short syncs should be gone.
  501. ;
  502.         call    Delay                   ;wait 15 usec to be sure
  503.     in    al,dx                   ;read SyncEOC line again to be sure
  504.     and    al,SyncEOC
  505.     jnz    fls1            ;loop if line is now high => short
  506. ;
  507. ;when we get here long sync interval has been detected and we're done
  508. ;
  509.     SDelay
  510.     ret
  511. ;
  512. FindLongSync    endp
  513. ;
  514. ;
  515. ; Procedure SetPixelCount
  516. ;
  517. ; This procedure sets the pixel counter latch on the digitizer board to
  518. ; the 16 bit value in the ax register. The digitizer hardware only uses
  519. ; 12 of the 16 bits at this time.
  520. ;
  521. ; INPUT:  pixel count in ax
  522. ; OUTPUT: none
  523. ; USES:   ax,cx,dx registers
  524. ; CALL:   not callable from C.
  525. ;
  526. ;
  527. SetPixelCount    proc    near
  528. ;
  529.     mov    cx,ax            ;save pixel count in cx reg
  530. ;
  531.     mov    dx,PrtPortData        ;pt at output data port
  532.     mov    al,cl            ;get LS byte of count
  533.     out    dx,al            ;write LS byte of pixel count
  534.  
  535.     StbDel
  536.  
  537.     mov    dx,PrtPortCont        ;pt at control port to strobe counters
  538.     mov    al,SetStrobe        ;start the stobe pulse
  539.     out    dx,al
  540.  
  541.     StbDel
  542.  
  543.     mov    al,PrtPortContSafe    ;strobe ended
  544.     out    dx,al
  545.  
  546.     SDelay
  547.  
  548.     mov    dx,PrtPortData        ;pt at data port again
  549.     mov    al,ch            ;get MSB of original pixel count
  550.     out    dx,al             ;send to pixel counter
  551.  
  552.     StbDel
  553.  
  554.     mov    dx,PrtPortCont        ;pt at control port to set HighLow high
  555.     mov    al,SetHighLow
  556.     out    dx,al
  557.  
  558.     StbDel
  559.  
  560.     mov    al,SetHighLowAndStrobe  ;strobe into counters
  561.     out    dx,al
  562.  
  563.     StbDel
  564.  
  565.     mov    al,SetHighLow        ;reset Strobe leave HighLow still high
  566.     out    dx,al
  567.  
  568.     StbDel
  569.  
  570.     mov    al,SetSyncReset        ;reset sync latch
  571.     out    dx,al
  572.  
  573.     StbDel
  574.  
  575.     mov    al,PrtPortContSafe    ;HighLow now low
  576.     out    dx,al
  577.  
  578.     SDelay
  579.  
  580.     ret
  581. ;
  582. SetPixelCount    endp
  583. ;
  584. ;
  585. ; Procedure _SetPixelCount
  586. ;
  587. ; C callable version of above.
  588. ;
  589. ; INPUT:  pixel count
  590. ; OUTPUT: none
  591. ; USES:   ax,cx,dx registers
  592. ; CALL:   callable from C.
  593. ; PROTOTYPE: void SetPixelCount ( unsigned short )
  594. ;
  595. ;
  596.     Public    _SetPixelCount
  597. ;
  598. _SetPixelCount    proc    near
  599. ;
  600.     push    bp
  601.     mov    bp,sp
  602.     mov    ax,[bp+4]
  603.     call    SetPixelCount
  604.     pop    bp
  605.     ret
  606. ;
  607. _SetPixelCount    endp
  608. ;
  609. ;
  610. ; Procedure _GetPicture
  611. ;
  612. ; This procedure digitizes a complete monochrome picture. It stores
  613. ; the data for the picture in a buffer whos address is passed to it from C.
  614. ; The function InitializeDigitizer must be called before this one so that
  615. ; the hardware and software are setup correctly. All instructions for how
  616. ; the digitizer should digitize a picture are contained in the ImageReq
  617. ; data structure.
  618. ;
  619. ; INPUT:  BX is a near pointer to the ImageReq structure which contains all
  620. ;         the information for the control of the digitizer.
  621. ; OUTPUT: returns True is picture data in buffer, False if error
  622. ; USES:   all registers. saves bp,si and di registers as required by Turbo C
  623. ; CALL:   callable from C.
  624. ; PROTOTYPE: GetPicture();
  625. ;
  626.     PUBLIC    _GetPicture
  627. ;
  628. _GetPicture     proc    near
  629. ;
  630.     cmp    DigitInit,True        ;has digitizer been initialized ?
  631.     je    gp1            ;continue if so
  632.     mov    ax,False        ;return a false indication to C
  633.     ret
  634.  
  635. gp1:    push    bp            ;save for use by C
  636.     push    si            ;save si,di in case register vars
  637.     push    di                      ;used in C code.
  638. ;
  639.     mov    bx,ImageReqPtr        ;get ImageReq pointer into bx for use
  640.                     ;all struct references use bx as ptr
  641.     mov    es,[bx].PictBufSeg      ;point es:bp at picture data buffer
  642.     mov    bp,[bx].PictBufOff
  643.  
  644.         mov     PColSeg,es              ;establish addr of 1st video column
  645.         mov     PColOff,bp
  646.  
  647.         mov     Field1Done,False        ;indicate field 1 not yet digitized
  648.     mov    Field1Found,False    ;and has not been found yet
  649.  
  650.     mov    si,[bx].FirstPixel    ;get the first pixels (column) #
  651.     cmp    [bx].HMode,LowRes    ;320 pixel line ?
  652.     jne    gp2            ;jump if not
  653.     shl    si,1            ;if 320 pixel line pixel # * 2
  654.  
  655. gp2:    add     si,HBlankingOffset      ;add in the blanking interval
  656. ;
  657. ;this is the top of the loop which digitizes a complete column of pixels
  658. ;from the video signal. CPU register si is the pixel count across a line
  659. ;whereas register di is the line count down the video image.
  660. ;
  661. gp3:    mov    Field1Done,False    ;false until field 1 has been done
  662.         mov    di,[bx].FirstLine       ;initialize line count to that
  663.                     ;specified in the ImageReq every
  664.                     ;time thru this loop
  665.     mov    es,PColSeg        ;get address of this column
  666.     mov    bp,PColOff
  667. ;
  668.         mov    ax,si            ;get pixel count
  669.     call    SetPixelCount        ;load hardware pixel counters
  670. ;
  671. gp4:    cmp    Field1Found,True    ;have we located desired field before?
  672.     je     gp7            ;if yes just find long sync interval
  673. ;
  674. ;when we get here we need to find the start of the first field at least once
  675. ;
  676. gp5:    cli                ;interrupts off from now on
  677.     call    SyncsPerField        ;locate field 1
  678.     cmp    ax,SyncsField2        ;are we there ?
  679.     jmp    gp6            ;if start of field 1 then jump
  680.     sti                ;interrupts back on
  681.     call    Delay            ;delay for short period
  682.     call    Delay            ;delay for short period
  683.     call    Delay            ;delay for short period
  684.     jmp     short gp5        ;repeat until we find it
  685. ;
  686. ;start of first field found
  687. ;
  688. gp6:    mov    Field1Found,True    ;indicate it was found
  689.     jmp    short gp8
  690. ;
  691. ;when we get here we just need to find the start of every subsequent
  692. ;even or odd field
  693. ;
  694. gp7:    cli                ;interrupts off from here on
  695.     mov    di,[bx].FirstLine       ;initialize line count
  696.     call    FindLongSync        ;find vertical sync period
  697. ;
  698. ;when we get here we have located the start of a field. NOTE: both the
  699. ;Sync and the EOC reset lines are still held active because we are not
  700. ;afraid of missing a short sync. That is, we are still only interested in
  701. ;long sync intervals. In the code that follows, we will
  702. ;continuously read the input port until we see it go high indicating a
  703. ;short sync has been detected. At that point we are past all of the long
  704. ;sync pulses and can start counting out the vertical blanking interval.
  705. ;
  706. gp8:    in    al,dx
  707.     and    al,SyncEOC
  708.     jz    gp8            ;jump if SyncEOC is still low.
  709. ;
  710. ;check once more
  711. ;
  712.         call    Delay                   ;delay 15 usec to be sure its gone
  713.     in    al,dx
  714.     and    al,SyncEOC
  715.     jz    gp8            ;jump if long sync. Line still low.
  716.  
  717.     SDelay
  718. ;
  719. ;we've just found the 1st short sync interval. Its probably an equalization
  720. ;pulse. We must now consume all of the equalization and vertical blanking
  721. ;pulses to get to the start of the active video.
  722. ;
  723.         inc     dx                      ;pt at control port
  724.     mov    al,PrtPortContSafe    ;end SyncReset pulse
  725.     out    dx,al            ;so we can use latch to find all
  726.                               ;syncs no matter how small
  727.     SDelay
  728.  
  729.         dec     dx                      ;pt back at input port
  730. ;
  731. ;count off the number of lines in the field to ignor. If a full field/frame
  732. ;picture is being digitized then ignor only VBlankingOffset number. If a
  733. ;partial picture is being digitized, ignor VBlankingOffset + FirstLine number
  734. ;of lines.
  735. ;
  736.     mov    cx,VBlankingOffset    ;consume this many on default picture
  737. ;
  738. ;check for field 2 digitization
  739. ;
  740.         cmp     Field1Done,True         ;are we digitizing field 2 ?
  741.         jne     gp9            ;jmp if not
  742.         inc     cx                      ;if we are consume one more sync
  743.                                         ;pulse to get rid of 1/2 line
  744. gp9:    cmp    [bx].FirstLine,0    ;req pict starts at line 0 ?
  745.     je    gp10            ;jmp if so
  746.     add    cx,[bx].FirstLine    ;else add in additional lines to ignor
  747.  
  748. gp10:    in    al,dx            ;read input port
  749.     and    al,SyncEOC        ;mask all but sync bit
  750.     jnz    gp10            ;loop until sync seen
  751.  
  752.     SDelay
  753. ;
  754. ;Sync latch has gone low. Reset it.
  755. ;
  756.     inc    dx            ;now pt dx at PrtPortCont for output
  757.     mov    al,ResetSyncAndEOC    ;set SyncReset high
  758.     out    dx,al            ;do it
  759.  
  760.     StbDel
  761.  
  762.     mov    al,PrtPortContSafe    ;end SyncReset pulse
  763.     out    dx,al            ;do it
  764.  
  765.         SDelay
  766. ;
  767. ;Sync latch is now reset. SyncEOC line should go inactive (high) shortly
  768. ;because we are expecting only short sync pulses.
  769. ;
  770.     dec    dx            ;pt at PrtPortIn
  771.     dec    cx            ;one less sync to consume
  772.     jnz    gp10            ;still more ?
  773. ;
  774. ;we have now consumed all the vertical blanking sync pulses. Set Go so
  775. ;pixel counters will be triggered on rising edge of sync pulse from camera.
  776. ;
  777.     inc    dx            ;pt at control port
  778.     mov    al,SetGo        ;set the go bit so counters will be
  779.     out    dx,al            ;triggered by rising edge of sync
  780.  
  781.     SDelay
  782.  
  783.     dec    dx                      ;pt at input port
  784. ;
  785. ;we are now at the start of the active video line. We must now process each
  786. ;digitization in less than one line time of 63.5 usec.
  787. ;
  788. gp11:    in    al,dx            ;look for falling edge of sync pulse
  789.     and    al,SyncEOC
  790.     jnz    gp11
  791.  
  792.     SDelay
  793. ;
  794. ;line started with falling edge of SyncEOC
  795. ;
  796.     inc    dx            ;pt at Cont port
  797.     mov    al,SetSyncResetAndGo    ;reset sync latch and keep Go
  798.                     ;line high to start pixel count
  799.     out    dx,al            ;on rising edge of every sync
  800.  
  801.     StbDel
  802.  
  803.     mov    al,SetGo        ;end SyncReset but leave Go active
  804.     out    dx,al            ;do it
  805.  
  806.     SDelay
  807. ;
  808. ;Sync latch is now reset and pixel counters should be running.
  809. ;SyncEOC line should go active (low) shortly when the converted data becomes
  810. ;available.
  811. ;
  812.     dec    dx            ;pt at PrtPortIn
  813. gp12:    in    al,dx            ;read input port
  814.     mov    cl,al            ;copy data to cl reg
  815.     and    al,SyncEOC        ;mask all but EOC bit
  816.     jnz    gp12            ;loop until data ready
  817.  
  818.     SDelay
  819. ;
  820. ;we now have four bits of the video digital data in cl register as follows:
  821. ;           7  6  5  4  3  2  1  0
  822. ;           D  D  D  D EOC X  X  X
  823. ;after we shift it right four places it looks like
  824. ;           7  6  5  4  3  2  1  0
  825. ;           0  0  0  0  D  D  D  D
  826. ;
  827.     shr    cl,1
  828.     shr    cl,1
  829.     shr    cl,1
  830.     shr    cl,1
  831. ;
  832. ;prepare to retrieve the MS nibble of data from the digitizer
  833. ;
  834.     inc    dx            ;pt at Cont port
  835.     mov    al,SetHighLowAndGo    ;set High/Low high to get 2 MSBs.
  836.     out    dx,al                   ;this also resets EOC
  837.  
  838.     SDelay
  839.  
  840.     dec    dx
  841.  
  842.     in    al,dx            ;get the two MSBs
  843.     and    al,30H            ;mask all but bits of interest
  844.     or    cl,al            ;combine to get 6 total bits/pixel
  845. ;
  846.     mov    es:[bp],cl        ;store all 6 bits of data
  847. ;
  848. gp13:    inc    dx            ;pt at Cont port
  849.     mov    al,SetGo        ;HighLow low again leave Go active
  850.     out    dx,al            ;do it
  851.     dec    dx
  852. ;
  853. ;check to see if pointer for data storage (bp register) will leave a 64K
  854. ;segment. If so the segment register must be adjusted by SEGOFF so
  855. ;offset 0 into the segment points at the next available byte of storage.
  856. ;NOTE: when digitizing an interlaced picture, where it is necessary to
  857. ;skip every other location in the picture buffer, the check for segment end
  858. ;must be slightly different. To accomodate this, the code that follows is
  859. ;executed conditionally depending upon interlaced digitization or not.
  860. ;
  861.         cmp     [bx].VMode,Interlace    ;are we in interlace mode ?
  862.         je      gp15            ;jmp if so
  863. ;
  864. ;when we get here we are in non Interlace mode
  865. ;
  866.     cmp    bp,0FFFFH        ;at end of seg ?
  867.     jne    gp14            ;jump if not
  868.     mov    ax,es            ;get seg reg value
  869.     add    ax,SEGOFF        ;add offset
  870.     mov    es,ax            ;store it back
  871.                                         ;segment offset will inc to 0000
  872. ;
  873. ;check to see if we are done with a column of pixels
  874. ;
  875. gp14:    inc    bp            ;bump the data pointer
  876.     inc    di            ;inc the line count
  877.     cmp    di,[bx].LastLine    ;bottom of picture ?
  878.     jb    gp11
  879. ;
  880.     mov    PColSeg,es        ;save ptr to next storage location
  881.     mov    PColOff,bp
  882. ;
  883.         jmp     gp19            ;jmp to common exit code
  884. ;
  885. ;when we get here we are in Interlace mode
  886. ;
  887. gp15:    cmp    bp,0FFFEH        ;at end of seg ?
  888.     jb    gp16            ;jump if not
  889.     mov    ax,es            ;get seg reg value
  890.     add    ax,SEGOFF        ;add offset
  891.     mov    es,ax            ;store it back
  892.                     ;seg offset will inc to 0000
  893. ;
  894. gp16:    inc    bp            ;bump the data pointer
  895.     inc    bp            ;and again to leave room for data from
  896.                     ;other field
  897.     inc    di            ;inc the line count
  898.     mov    ax,[bx].LastLine    ;get last line of Interlaced frame
  899.     shr    ax,1            ;divide by two for last line per field
  900.     cmp    di,ax            ;bottom of field ?
  901.     jae    gp17
  902.     jmp    gp11
  903. ;
  904. ;we are now done with one field of video for the Interlaced image. Go
  905. ;back and digitize the other field.
  906. ;
  907. gp17:    cmp    Field1Done,True        ;done with this column in both fields ?
  908.     je    gp18            ;jmp if so
  909. ;
  910. ;when we get here we know we need to go back and do the other field
  911. ;
  912.     mov    Field1Done,True        ;set flag to say we're finished on
  913.                      ;next pass
  914.     mov    es,PColSeg          ;reload this columns pointer
  915.     mov    bp,PColOff
  916. ;
  917.     inc    bp            ;bump one to miss data from other
  918.                     ;field
  919.     jmp    gp7            ;get next fields data
  920. ;
  921. gp18:    mov    PColSeg,es        ;save addr of where next columns
  922.     dec    bp
  923.     mov    PColOff,bp        ;data should start
  924. ;
  925. ;we are now done with a column of the video display. Advance to next pixel
  926. ;or next column. This is true for both Interlace and non Interlace
  927. ;digitizations.
  928. ;
  929. gp19:    inc    dx            ;pt at Cont port
  930.     mov    al,PrtPortContSafe    ;reset all control lines
  931.     out    dx,al            ;just to be safe
  932.     SDelay
  933.     sti                ;interrupts back on because timing
  934.                     ;between frames is not that critical
  935.  
  936.     cmp    [bx].HMode,LowRes    ;a 320 pixel picture ?
  937.     jne     gp20            ;jmp if not
  938. ;
  939. ;when we get here we know we are digitizing a 320 pixel line picture. we
  940. ;must increment the pixel count twice (two 640 pixels = one 320 pixel)
  941. ;and check to see if we are done digitizing a picture. this is complicated
  942. ;by the fact that the pixel counts are actually twice as big so we must
  943. ;compare with twice the LastPixel value.
  944. ;
  945.     inc    si
  946.     inc    si
  947.     mov    ax,[bx].LastPixel    ;get the final pixel count
  948.     shl    ax,1            ;* 2 for comparison
  949.         add     ax,HBlankingOffset      ;added in blanking interval
  950.     cmp     si,ax            ;is the 320 pixel pict done ?
  951.         jae    gp21            ;jmp if so
  952.     jmp    gp3            ;if not do next pixel column
  953. ;
  954. ;when we get here we know we are digitizing a 640 pixel line picture. This
  955. ;is a much easier case than the 320 pixel picture shown above.
  956. ;
  957. gp20:    inc    si            ;bump pixel count once for high res
  958.     mov    ax,[bx].LastPixel    ;get last pixel #
  959.         add     ax,HBlankingOffset      ;added in blanking interval
  960.     cmp     si,ax            ;is the 640 pixel pict done ?
  961.     jae    gp21            ;if so jump
  962.     jmp    gp3            ;if not do next pixel column
  963. ;
  964. ;a complete picture is now digitized. Prepare to return to C.
  965. ;
  966. gp21:    pop    di
  967.     pop    si
  968.     pop    bp
  969.     mov    ax,True            ;indicate no error to C
  970.     ret
  971. ;
  972. _GetPicture    endp
  973. ;
  974. ;End of video routines
  975. ;
  976. _TEXT    ends
  977.     end
  978.