home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast.iso / pcmag / vol9n01.zip / PCREMOTE.ASM < prev    next >
Assembly Source File  |  1989-11-27  |  59KB  |  1,756 lines

  1.     TITLE    PCREMOTE - Unattended Computer Access - 1989 by Terry Lahman
  2.     PAGE    60,132
  3. ;======================================================================
  4. ;
  5. ;  PCREMOTE - An unattended computer access utility.  Allows access to an
  6. ;  unattended computer from a manned computer.    The unattended computer
  7. ;  executes the TSR portion of the program and waits for the manned
  8. ;  computer to call.  For use with text only programs.    Like using the
  9. ;  phone lines and modems as a long extension cord for your keyboard
  10. ;  and monitor.
  11. ;
  12. ;    Usage:    PCREMOTE [ /M ] [ /2 ] [ /F ] [ /D ]
  13. ;
  14. ;======================================================================
  15. CSEG    SEGMENT PARA PUBLIC 'CODE'
  16.     ASSUME    CS:CSEG,DS:NOTHING,ES:NOTHING,SS:NOTHING
  17.  
  18. BS        EQU    8
  19. CR        EQU    13
  20. LF        EQU    10
  21. SPACE        EQU    32
  22.  
  23. ;----------------------------------------------------------------------
  24. ;  Start of code
  25. ;----------------------------------------------------------------------
  26.         ORG    100H            ;Starting offset for .com
  27. START:        JMP    INITIALIZE        ;Jump over resident code
  28.  
  29. ;----------------------------------------------------------------------
  30. ;  Data storage
  31. ;----------------------------------------------------------------------
  32.  
  33. COPYRIGHT    DB    "PCREMOTE Version 1.0 (c) 1989 Ziff Communications Co."
  34.         DB    CR,LF,"PC Magazine ",254," by Terry Lahman",CR,LF,"$",26
  35. CONNECT_FLAG    DB    0            ;0=not connected
  36.                         ;1=connected to manned system
  37. ACT_FLAG    DB    0            ;0=unattended prog not active
  38.                         ;1=unattended program is active
  39.                         ; do not run again
  40. OLDINT_8    DW    0,0            ;Old timer vector
  41. MANNED_FLAG    DB    0            ;0=Operate in unattended mode
  42.                         ;1=Operate in manned mode
  43. COMM_FLAG    DB    0            ;0=Use comm1
  44.                         ;1=Use comm2
  45. COMM_PORT    DW    0            ;Comm port address
  46. COMM_INT_STA    DB    0            ;Comm port interrupt status
  47.                         ;0=not transmitting data
  48.                         ;1=transmitting data
  49. SPEED_FLAG    DB    0            ;0=Use 1200 baud
  50.                         ;1=Use 2400 baud
  51. DESNOW_FLAG    DB    0            ;0=Do not use desnow code
  52.                         ;1=Use desnow code
  53. VIDEO_COPY    DW    0            ;Address of video ram copy
  54. VIDEO_SEGMENT    DW    0            ;Segment register for vid ram
  55. SHIFT_STATUS    DB    0            ;Current status of shift byte
  56. STACK_TOP    DW    INITIALIZE+256D     ;Top of stack for unattended
  57. OLD_SS        DW    0            ;Old stack segment
  58. OLD_SP        DW    0            ;Old stack pointer
  59. TEMP_REG    DW    0            ;Temp storage for register
  60. CURSOR_POSITION DW    0            ;Old cursor position
  61. VID_RAM_OFFSET    DW    0            ;Current compare offset
  62. ASCII_FLAG    DB    0            ;0=no data is pending
  63.                         ;1=received a FE
  64.                         ;2=received ASCII char
  65.                         ;4=received scan code
  66. SHIFT_FLAG    DB    0            ;0=no data is pending
  67.                         ;1=received a FD
  68. KEY_ONE     DB    0            ;ASCII char received
  69. KEY_TWO     DB    0            ;Scan code received
  70. BAUD_RATE    DB    0,60H            ;1200 BAUD divisor MSB LSB
  71.         DB    0,30H            ;2400 BAUD divisor MSB LSB
  72. IN_BUFF_SIZE    EQU    512D            ;Size for input buffer
  73. OUT_BUFF_SIZE    EQU    512D            ;Size for output buffer
  74. IN_BUFF_HEAD    DW    ?            ;Pointer to input buffer head
  75. IN_BUFF_TAIL    DW    ?            ;Pointer to input buffer tail
  76. IN_BUFF_BEGIN    DW    ?            ;Pointer to input buffer begin
  77. IN_BUFF_END    DW    ?            ;Pointer to input buffer end
  78. OUT_BUFF_HEAD    DW    ?            ;Pointer to output buffer head
  79. OUT_BUFF_TAIL    DW    ?            ;Pointer to output buffer tail
  80. OUT_BUFF_BEGIN    DW    ?            ;Pointer to output buffer begin
  81. OUT_BUFF_END    DW    ?            ;Pointer to output buffer end
  82. BLOCK_SIZE    EQU    16D            ;Block transfer size in words
  83. BLOCK_SIZEX2    EQU    BLOCK_SIZE*2        ;Block transfer size in bytes
  84. BLOCK_COUNT    DB    ?            ;Block number being processed
  85. BLOCK_POINTER    DW    0            ;Points to current video block
  86. TEMP_VIDEO_PTR    DW    ?            ;Pointer to temp video storage
  87. CR_COUNT    DB    ?            ;Number of CRs for speed sync
  88. MODEM_ATTENTION DB    CR,"AT",CR,0
  89. MODEM_SETUP1    DB    "ATE0 S12=40 Q0 V0 X1 S0=0",CR,0 ;Manned
  90. MODEM_SETUP2    DB    "ATE0 S12=40 Q1S0=2",CR,0 ;Unattended
  91. MODEM_SETUP3    DB    "AT&C1",CR,0        ;Enable DCD on 2400 baud modem
  92. MODEM_HANGUP    DB    "ATH0",CR,0
  93. MODEM_ESCAPE    DB    "+++",0
  94. TONE_DIAL    DB    "ATDT",0        ;Tone dial command
  95. PASS_MESSAGE    DB    "Enter password:",0    ;Enter password message
  96. PASSWORD_SIZE    DW    EXTRA_PW_SPACE-PASSWORD
  97. PASSWORD    DB    "PC MAGAZINE"
  98. EXTRA_PW_SPACE    DB    20-(EXTRA_PW_SPACE-PASSWORD) DUP(?)
  99. PASSWORD_BUFFER DB    20 DUP(?)
  100. EXIT_CODE    DB    0,45D            ;alt-x, code to exit program
  101.  
  102. ;======================================================================
  103. ;  Interrupt handlers.  Interrupt 8 is used in unattended mode only.
  104. ;  The communications interrupt is used in both modes.
  105. ;======================================================================
  106. ;----------------------------------------------------------------------
  107. ;  Interrupt 8 handling routine.  If program is already active do not run.
  108. ;  Run connect unattended if not connected, otherwise run unattended.
  109. ;----------------------------------------------------------------------
  110. INT8        PROC    NEAR
  111.         ASSUME    CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
  112.         PUSH    DS            ;Save data segment
  113.         PUSH    CS            ;Set data segment to code seg
  114.         POP    DS
  115.         PUSHF                ;Call old int 8
  116.         CALL    DWORD PTR OLDINT_8
  117. I8_10:
  118.         CLI                ;Disable interrupts
  119.         CMP    BYTE PTR ACT_FLAG,0    ;Check for program active
  120.         JNZ    I8_EXIT            ;Exit if progam is active
  121.         INC    BYTE PTR ACT_FLAG    ;Set program active flag
  122.         STI                ;Enable interrupts
  123.         CALL    SET_STACK        ;Create stack & save registers
  124.         CMP    BYTE PTR CONNECT_FLAG,0 ;Connected to manned?
  125.         JNZ    I8_20            ;Yes, then run unattended
  126.         CALL    CONNECT_UNATTENDED    ;No, check for connection
  127.         JMP    I8_30
  128. I8_20:
  129.         CALL    UNATTENDED        ;Run unattended
  130. I8_30:
  131.         CALL    RESET_STACK        ;Restore registers & stack
  132.         DEC    BYTE PTR ACT_FLAG    ;Clear program active flag
  133. I8_EXIT:
  134.         STI                ;Enable interrupts
  135.         POP    DS            ;Restore data segment
  136.         IRET
  137. INT8        ENDP
  138.  
  139. ;----------------------------------------------------------------------
  140. ;  Interrupt handling routine for communications interrupt.  Provides
  141. ;  interrupt driven I/O.  Transmit or receive a character.
  142. ;----------------------------------------------------------------------
  143. INT_COMM    PROC    NEAR
  144.         ASSUME    CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
  145.         PUSH    DS            ;Save data segment
  146.         PUSH    DX            ;Save registers
  147.         PUSH    BX
  148.         PUSH    AX
  149.         PUSH    CS            ;Set data segment to code seg.
  150.         POP    DS
  151.         MOV    DX,COMM_PORT        ;Get port base address
  152.         INC    DX            ;Point to int. id reg.
  153.         INC    DX
  154.         IN    AL,DX            ;Get the interrupt id byte
  155. IC_10:
  156.         CMP    AL,2            ;Transmit empty int?
  157.         JZ    IC_40            ;Yes transmit a byte
  158. ;
  159. ;    received data, get it and store in buffer
  160. ;
  161.         DEC    DX            ;Port base address
  162.         DEC    DX
  163.         IN    AL,DX            ;Get data from receive register
  164.         MOV    BX,IN_BUFF_TAIL        ;Get the buffer tail pointer
  165.         MOV    [BX],AL         ;Store the data in buffer
  166.         INC    BX            ;Point to next data storage
  167.         CMP    IN_BUFF_END,BX        ;Beyond end of buffer area?
  168.         JNE    IC_20            ;No, then don't reset
  169.         MOV    BX,IN_BUFF_BEGIN    ;Yes, reset to buffer begin
  170. IC_20:
  171.         CMP    BX,IN_BUFF_HEAD        ;Test for buffer full
  172.         JE    IC_30             ;If so,don't change ptr ,sorry
  173.         MOV    IN_BUFF_TAIL,BX        ;Save new tail pointer
  174. IC_30:
  175.         JMP    IC_70
  176. ;
  177. ;    transmit buffer empty, send a byte
  178. ;
  179. IC_40:
  180.         DEC    DX            ;Port base address
  181.         DEC    DX
  182.         MOV    BX,OUT_BUFF_HEAD    ;Get the buffer head pointer
  183.         CMP    BX,OUT_BUFF_TAIL    ;Test for data in buffer
  184.         JE    IC_60             ;If the same, no data so exit
  185.         MOV    AL,[BX]         ;Get the data
  186.         INC    BX            ;Point to next data in buffer
  187.         CMP    OUT_BUFF_END,BX        ;Beyond end of buffer area?
  188.         JNE    IC_50            ;No, then don't reset
  189.         MOV    BX,OUT_BUFF_BEGIN    ;Yes, reset to buffer begin
  190. IC_50:
  191.         MOV    OUT_BUFF_HEAD,BX     ;Save new head pointer
  192.         OUT    DX,AL            ;Send the data out the port
  193.         JMP    IC_70            ;Check for request pending
  194. IC_60:
  195.         MOV    BYTE PTR COMM_INT_STA,0    ;Reset transmitting data flag
  196. IC_70:
  197.         INC    DX            ;Point to int. id reg.
  198.         INC    DX
  199.         IN    AL,DX            ;Get the interrupt id byte
  200.         TEST    AL,1            ;Request pending?
  201.         JZ    IC_10            ;Yes, then process
  202. IC_EXIT:
  203.         MOV    AL,20H            ;Reset 8259
  204.         OUT    20H,AL
  205.         STI                ;Enable interrupts
  206.         POP    AX            ;Restore registers
  207.         POP    BX
  208.         POP    DX
  209.         POP    DS            ;Restore data segment
  210.         IRET
  211. INT_COMM    ENDP
  212.  
  213. ;----------------------------------------------------------------------
  214. ;  Create stack area and save all registers.
  215. ;----------------------------------------------------------------------
  216. SET_STACK    PROC    NEAR
  217.         ASSUME    CS:CSEG,DS:NOTHING,ES:NOTHING,SS:NOTHING
  218.         MOV    TEMP_REG,BX        ;Save BX
  219.         POP    BX            ;Save the return address
  220.         PUSH    AX            ;Save AX
  221. ;
  222. ;    make my own stack
  223. ;
  224.         CLI                ;Disable interrupts
  225.         MOV    AX,SS            ;Put old stack segment in AX
  226.         MOV    OLD_SS,AX        ;And save it
  227.         MOV    AX,SP            ;Put old stack pointer in AX
  228.         MOV    OLD_SP,AX        ;And save it
  229.         MOV    AX,CS            ;Get current segment
  230.         MOV    SS,AX            ;And put into stack segment
  231.         MOV    AX,STACK_TOP         ;Get top of stack address
  232.         MOV    SP,AX            ;And put into stack pointer
  233.         STI                ;Enable interrupts
  234. ;
  235. ;    save all the registers on the stack
  236. ;
  237.         PUSH    CX
  238.         PUSH    DX
  239.         PUSH    SI
  240.         PUSH    DI
  241.         PUSH    DS
  242.         PUSH    ES
  243.         PUSH    BP
  244.         MOV    AX,CS            ;Get code segment
  245.         MOV    DS,AX            ;Set data segment to code seg
  246.         MOV    ES,AX            ;Set extra seg to code seg
  247.         PUSH    BX            ;Restore return address
  248.         RET
  249. SET_STACK    ENDP
  250.  
  251. ;----------------------------------------------------------------------
  252. ;  Restore all registers and reset stack
  253. ;----------------------------------------------------------------------
  254. RESET_STACK    PROC    NEAR
  255.         ASSUME    CS:CSEG,DS:NOTHING,ES:NOTHING,SS:NOTHING
  256.         POP    BX            ;Save return address
  257. ;
  258. ;    restore the registers
  259. ;
  260.         POP    BP            ;Restore the registers
  261.         POP    ES
  262.         POP    DS
  263.         POP    DI
  264.         POP    SI
  265.         POP    DX
  266.         POP    CX
  267. ;
  268. ;    restore the original stack
  269. ;
  270.         CLI                ;Disable interrupts
  271.         MOV    AX,OLD_SP        ;Get old stack pointer
  272.         MOV    SP,AX            ;And restore it
  273.         MOV    AX,OLD_SS        ;Get old stack segment
  274.         MOV    SS,AX            ;And restore it
  275.         STI                ;Enable interrupts
  276.         POP    AX            ;Restore AX
  277.         PUSH    BX            ;Put return add back on stack
  278.         MOV    BX,TEMP_REG        ;Restore BX
  279.  
  280.         RET
  281. RESET_STACK    ENDP
  282.  
  283. ;======================================================================
  284. ;  The unattended routine will execute the connect routine to establish
  285. ;  a connection with the manned system.  Once connected it will execute 
  286. ;  the unattended routine to process incoming data and send any changed
  287. ;  video data to the manned system.
  288. ;======================================================================
  289.  
  290. ;----------------------------------------------------------------------
  291. ;  CONNECT_UNATTENDED - Check for ring codes, answer the phone and check
  292. ;  the password.  If correct, set connected flag.
  293. ;----------------------------------------------------------------------
  294. CONNECT_UNATTENDED PROC    NEAR
  295.     ASSUME    CS:CSEG,DS:CSEG,ES:CSEG,SS:NOTHING
  296.         MOV    BP,SP            ;Save stack pointer for exit
  297.         CALL    CHECK_CARRIER        ;Test for carrier present
  298.         JNZ    CU_10            ;Yes then check baud rate
  299.         JMP    CU_EXIT         ;No, then exit routine
  300. CU_10:
  301.         CALL    CLEAR_INBUFF        ;Clear the input buffer
  302.         XOR    AH,AH            ;Use input buffer
  303.         MOV    CX,10D            ;Number of char to check for CR
  304.         MOV    BYTE PTR CR_COUNT,5    ;Number of matches required
  305. CU_20:
  306.         CALL    CHECK_CARRIER        ;Check for carrier loss
  307.         JNZ    CU_30
  308.         JMP    IP_50            ;Carrier loss, reset and exit
  309. CU_30:
  310.         CALL    GET_BUFF_DATA        ;Try to get data from buffer
  311.         JNC    CU_20            ;Wait till their is data
  312.         CMP    AL,CR            ;Check for CR code
  313.         JNZ    CU_40            ;No so skip over
  314.         DEC    BYTE PTR CR_COUNT    ;Found a match dec count
  315.         JZ    CU_50            ;5 out of ten then 2400 baud
  316. CU_40:
  317.         LOOP    CU_20            ;Keep trying
  318.         XOR    AL,AL            ;No 5 out of 10, try 1200 baud
  319.         CALL    SET_BAUD_RATE
  320.         JMP    CU_10            ;Now wait for CR at 1200 baud
  321. CU_50:
  322.         MOV    BYTE PTR CONNECT_FLAG,1 ;Set connect flag
  323.         MOV    CX,3            ;3 tries to enter password
  324. CU_60:
  325.         MOV    SI,OFFSET PASS_MESSAGE    ;Point to enter password mess.
  326.         CALL    LOAD_ZSTRING        ;Load it into output buffer
  327.         CALL    GET_PASSWORD        ;Get the password
  328.         CALL    CHECK_PASSWORD        ;Check the password sent
  329.         JZ    CU_70             ;Jump if correct
  330.         LOOP    CU_60            ;Keep trying
  331.         MOV    AL,1            ;Use setup string 2
  332.         CALL    RESET_MODEM        ;Hangup and reset modem
  333.         JMP    CU_EXIT            ;Done, so exit
  334. CU_70:
  335.         MOV    AH,1            ;Use output buffer
  336.         XOR    AL,AL            ;Sync byte to send
  337.         MOV    CX,5            ;Send 5 of them
  338. CU_80:
  339.         CALL    PUT_BUFF_DATA        ;Send them
  340.         LOOP    CU_80
  341. CU_EXIT:
  342.         RET
  343. CONNECT_UNATTENDED ENDP
  344.  
  345. ;----------------------------------------------------------------------
  346. ;  Get the password from the manned system
  347. ;  Input - Nothing
  348. ;  Output - Password buffer contains password from manned system
  349. ;  Changes - DI, AX
  350. ;----------------------------------------------------------------------
  351. GET_PASSWORD    PROC    NEAR
  352.     ASSUME    CS:CSEG,DS:CSEG,ES:CSEG,SS:NOTHING
  353.         PUSH    CX              ;Save register
  354.         MOV    DI,OFFSET PASSWORD_BUFFER ;Point to password buffer
  355.         MOV    CX,20D              ;Zero buffer to clear previous
  356.         XOR    AL,AL              ; password
  357.         CLD
  358.         REP    STOSB
  359.         MOV    DI,OFFSET PASSWORD_BUFFER ;Pointer to buffer
  360.         MOV    CX,20D              ;Maximum password size
  361. GP_10:
  362.         CALL    CHECK_CARRIER        ;Check for carrier loss
  363.         JNZ    GP_20
  364.         JMP    IP_50            ;Carrier loss, reset and exit
  365. GP_20:
  366.         CALL    INPUT_PROCESSING    ;Get data & put in keybd buffer
  367.         CALL    GET_KEYSTROKE        ;Check for keystroke
  368.         JZ    GP_10            ;None, so wait
  369.         CMP    AL,60H            ;Check for lower case
  370.         JL    GP_30            ;No then leave it alone
  371.         AND    AL,5FH            ;Convert to upper case
  372. GP_30:
  373.         CMP    AL,CR            ;If it is a CR then exit
  374.         JZ    GP_EXIT
  375.         CMP    AL,BS            ;Is it a back space?
  376.         JNZ    GP_40            ;No, so save it
  377.         INC    CX              ;Resetcounter for BS
  378.         CMP    DI,OFFSET PASSWORD_BUFFER ;Already at start of buffer?
  379.         JZ    GP_60              ;Yes, then don't backspace
  380.         DEC    DI            ;Backspace buffer pointer
  381.         MOV    BYTE PTR [DI],0        ; and null the data
  382.         JMP    GP_50
  383. GP_40:
  384.         CLD                ;Forward
  385.         STOSB                ;Save the character
  386.         MOV    AL,'*'            ;Echo character
  387. GP_50:
  388.         MOV    AH,1            ;Use output buffer
  389.         CALL    PUT_BUFF_DATA        ; and store the character
  390. GP_60:
  391.         LOOP    GP_10            ;Receive up to CX characters
  392. GP_EXIT:
  393.         POP    CX            ;Restore register
  394.         RET
  395. GET_PASSWORD    ENDP
  396.  
  397. ;----------------------------------------------------------------------
  398. ;  Check the password in the buffer with correct password
  399. ;  Input - Nothing
  400. ;  Output - Zero set - correct password
  401. ;        Zero reset - Wrong password
  402. ;  Changes - SI, DI
  403. ;----------------------------------------------------------------------
  404. CHECK_PASSWORD    PROC    NEAR
  405.     ASSUME    CS:CSEG,DS:CSEG,ES:CSEG,SS:NOTHING
  406.         PUSH    CX              ;Save register
  407.         MOV    SI,OFFSET PASSWORD_BUFFER ;Pointer to buffer
  408.         MOV    DI,OFFSET PASSWORD      ;Pointer to password
  409.         MOV    CX,PASSWORD_SIZE    ;Number of compares to make
  410.         CLD                ;Compare forward
  411.         REPZ    CMPSB            ;Repeat while passwords match
  412.         POP    CX            ;Restore register
  413.         RET
  414. CHECK_PASSWORD    ENDP
  415.  
  416. ;----------------------------------------------------------------------
  417. ;  UNATTENDED - Process incoming data and check for changes in video 
  418. ;  data, format and send to manned system.  Maintains 18 or less characters
  419. ;  in output buffer, ensures maximum throughput.
  420. ;----------------------------------------------------------------------
  421. UNATTENDED    PROC    NEAR
  422.     ASSUME    CS:CSEG,DS:CSEG,ES:CSEG,SS:NOTHING
  423.         MOV    BP,SP            ;Save stack pointer for exit
  424.         CALL    INPUT_PROCESSING    ;Process any buffered data
  425.         MOV    AX,OUT_BUFF_HEAD    ;Get the head pointer
  426.         MOV    BX,OUT_BUFF_TAIL    ;Get the tail pointer
  427.         MOV    CX,18D            ;Check for bytes in buffer
  428. UA_10:
  429.         CMP    AX,BX            ;Less than 18 bytes in buffer
  430.         JZ    UA_30            ;Yes, then compare video
  431.         INC    AX            ;Increment head pointer
  432.         CMP    OUT_BUFF_END,AX        ;Beyond end of buffer area?
  433.         JNE    UA_20            ;No, then don't reset
  434.         MOV    AX,OUT_BUFF_BEGIN    ;Yes, reset to buffer begin
  435. UA_20:
  436.         LOOP    UA_10            ;Check all 18 bytes
  437.         JMP    UA_EXIT            ;More than 18, exit
  438. UA_30:
  439.         MOV    VID_RAM_OFFSET,0    ;Start at address 0
  440.         MOV    BYTE PTR BLOCK_COUNT,0    ;Reset block counter
  441. ;
  442. ;    compare the video copy with the video ram
  443. ;
  444. UA_40:
  445.         PUSH    DS            ;Save data segment
  446.         MOV    SI,VID_RAM_OFFSET    ;Get the current offset
  447.         MOV    DI,TEMP_VIDEO_PTR    ;Dest. ES:DI temp video buffer
  448.         MOV    AX,VIDEO_SEGMENT    ;Get video Segment register
  449.         MOV    DS,AX            ;Source DS:SI video RAM
  450. ;
  451. ;    transfer block_size words of data from video RAM to the temp buffer
  452. ;
  453.         MOV    CX,BLOCK_SIZE        ;Get count of words to transfer
  454.         CLD
  455.         CMP    BYTE PTR CS:DESNOW_FLAG,0 ;Check desnow flag
  456.         JZ    UA_70
  457.         SAL    CX,1            ;Convert words to bytes
  458.         MOV    DX,3DAH            ;CGA status port
  459. UA_50:
  460.         IN    AL,DX            ;Get status byte
  461.         TEST    AL,1            ;Test display enable
  462.         JNZ    UA_50            ;If in Hor. sync then wait
  463.         CLI                ;Disable interrupts
  464. UA_60:
  465.         IN    AL,DX            ;Get status byte
  466.         TEST    AL,1            ;Test display enable
  467.         JZ    UA_60            ;Wait for Hor. sync
  468.         MOVSB                ;Transfer one byte
  469.         STI                ;Enable interrupts
  470.         LOOP    UA_50            ;Transfer block size words
  471.         JMP    UA_80
  472. UA_70:
  473.         REP    MOVSW
  474. UA_80:
  475.         POP    DS            ;Restore data segment
  476. ;
  477. ;    compare the block from video RAM with the video copy
  478. ;
  479.         MOV    CX,BLOCK_SIZEX2     ;Number of words to compare
  480.         MOV    SI,TEMP_VIDEO_PTR    ;Point to block of video data
  481.         MOV    DI,VIDEO_COPY        ;Point to video copy
  482.         ADD    DI,VID_RAM_OFFSET    ;Adjust for current block
  483.         REPE    CMPSB            ;Compare while equal
  484.         JNE    UA_90            ;No match, format & send block
  485.         MOV    AX,VID_RAM_OFFSET    ;Get current block pointer
  486.         ADD    AX,BLOCK_SIZEX2     ;Point to next block
  487.         MOV    VID_RAM_OFFSET,AX    ;And save the pointer
  488.         INC    BYTE PTR BLOCK_COUNT    ;Increment current block count
  489.         CMP    AX,4000D        ;Check for end of video RAM
  490.         JNZ    UA_40            ;No, keep checking the RAM
  491.         MOV    VID_RAM_OFFSET,0    ;Yes, reset to begin of video
  492.         JMP    UA_100            ;Check for change in cursor
  493. ;
  494. ;    data doesn't match, format and send to manned system
  495. ;
  496. UA_90:
  497.         INC    CX            ;Adjust count
  498.         AND    CX,1            ;LSB indicates char or attr.
  499.         CALL    TRANSFER_BLOCK        ;Prepare to send block of data
  500. ;
  501. ;    Check for a change in the cursor position
  502. ;
  503. UA_100:
  504.         MOV    AX,40H            ;Set ES to BIOS data segment
  505.         MOV    ES,AX
  506.         MOV    BX,ES:[50H]        ;Get current cursor position
  507.         CMP    BX,CURSOR_POSITION    ;Compare with copy
  508.         JZ    UA_EXIT            ;No change, skip
  509.         MOV    CURSOR_POSITION,BX    ;Save new cursor position
  510.         MOV    AL,0D2H         ;Sync bits, set position
  511.         MOV    AH,1            ;Use output buffer
  512.         CALL    PUT_BUFF_DATA        ;Send sync byte
  513.         MOV    AL,BL            ;Low byte
  514.         CALL    PUT_BUFF_DATA
  515.         MOV    AL,BH            ;High byte
  516.         CALL    PUT_BUFF_DATA
  517. UA_EXIT:
  518.         RET
  519. UNATTENDED    ENDP
  520.  
  521. ;----------------------------------------------------------------------
  522. ;  Get data from the unattended input buffer and process
  523. ;  Input - Nothing
  524. ;  Output - Keyboard buffer or shift status is updated
  525. ;  Changes - Nothing
  526. ;----------------------------------------------------------------------
  527. INPUT_PROCESSING PROC     NEAR
  528.         PUSH    AX            ;Save register
  529.         PUSH    DX
  530.         PUSH    ES
  531.         MOV    AX,40H            ;Set ES to BIOS data area
  532.         MOV    ES,AX
  533. IP_10:
  534.         CMP    BYTE PTR CONNECT_FLAG,0 ;Are we connected
  535.         JZ    IP_20            ;No, don't check carrier
  536.         CALL    CHECK_CARRIER        ;Yes check for carrier loss
  537.         JZ    IP_50            ;Carrier loss, reset and exit
  538. IP_20:
  539.         MOV    AH,0            ;Use input buffer
  540.         CALL    GET_BUFF_DATA        ;Get a byte of data
  541.         JC    IP_30            ;If data then process
  542.         JMP    IP_EXIT            ;Otherwise exit
  543. ;
  544. ;    Check to see if expecting ASCII data
  545. ;
  546. IP_30:
  547.         CMP    ASCII_FLAG,0        ;Check ASCII flag
  548.         JZ    IP_70            ;0=not expecting data here
  549.         CMP    ASCII_FLAG,1        ;Check for received 1st byte
  550.         JNZ    IP_40            ;Jump if second byte
  551.         MOV    KEY_ONE,AL        ;Save scan code, byte one
  552.         INC    BYTE PTR ASCII_FLAG    ;Indicate receiving one byte
  553.         JMP    IP_10            ;Process next byte
  554. IP_40:
  555.         MOV    KEY_TWO,AL        ;Save ASCII code, byte two
  556.         MOV    AL,KEY_ONE        ;Get ASCII code
  557.         MOV    AH,KEY_TWO        ;Get scan code
  558.         CMP    AX,WORD PTR EXIT_CODE    ;Check for exit code
  559.         JNZ    IP_60            ;No,then continue processing
  560. IP_50:                        ;Otherwise reset connect & exit
  561.         CALL    CLEAR_INBUFF        ;Clear input buffer
  562.         CALL    CLEAR_OUTBUFF        ;Clear output buffer
  563.         MOV    BYTE PTR COMM_INT_STA,0    ;Reset transmitting data flag
  564.         CALL    IU_10            ;reinit and reset modem
  565.         CLI                ;Disable interrupts
  566.         MOV    BYTE PTR CONNECT_FLAG,0 ;Reset the connect flag
  567.         MOV    BYTE PTR ASCII_FLAG,0    ;Reset ASCII flag
  568.         MOV    BYTE PTR SHIFT_FLAG,0    ;Reset shift flag
  569.         MOV    BYTE PTR ES:[17H],0    ;Reset any shift status
  570.         MOV    SP,BP            ;Clean the stack
  571.         RET                 ;And exit unattended routine
  572. IP_60:
  573.         CALL    PUT_KEY_DATA        ;And stuff in keyboard buffer
  574.         MOV    BYTE PTR ASCII_FLAG,0    ;Reset ASCII flag for next data
  575.         JMP    IP_10            ;Process next byte
  576. ;
  577. ;    Check to see if expecting shift data
  578. ;
  579. IP_70:
  580.         CMP    BYTE PTR SHIFT_FLAG,0    ;Check shift flag
  581.         JZ    IP_80            ;0=not expecting data here
  582.         MOV    ES:[17H],AL        ;And save in shift status
  583.         MOV    BYTE PTR SHIFT_FLAG,0    ;Reset shift flag for next data
  584.         JMP    IP_10            ;Process next byte
  585. ;
  586. ;    Check to see if it's a sync byte
  587. ;
  588. IP_80:
  589.         CMP    AL,0FEH         ;Check for ASCII sync byte
  590.         JNZ    IP_90            ;If not then check for shift
  591.         INC    BYTE PTR ASCII_FLAG    ;Indicate received FEh
  592.         JMP    IP_10            ;Process next byte
  593. IP_90:
  594.         CMP    AL,0FDH         ;Check for shift sync byte
  595.         JNZ    IP_100            ;If not then throw away
  596.         INC    BYTE PTR SHIFT_FLAG    ;Indicate received FDh
  597. IP_100:
  598.         JMP    IP_10            ;Process till buffer empty
  599. IP_EXIT:
  600.         POP    ES            ;Restore registers
  601.         POP    DX
  602.         POP    AX
  603.         RET
  604. INPUT_PROCESSING ENDP
  605.  
  606. ;----------------------------------------------------------------------
  607. ;  Formats the data in temporary video buffer and puts it into the
  608. ;  output buffer
  609. ;  Input - CX=0 Transfer character data to output buffer
  610. ;       CX=1 Transfer attribute data to output buffer
  611. ;  Output - Nothing
  612. ;  Changes - AX, BX, CX, SI, DI
  613. ;----------------------------------------------------------------------
  614. TRANSFER_BLOCK    PROC    NEAR
  615.         OR    CX,CX            ;Set flags
  616.         JZ    TB_10            ;Jump if character data
  617.         MOV    AL,0FFH         ;Sync byte for attr. data
  618.         JMP    TB_20
  619. TB_10:
  620.         MOV    AL,0FEH         ;Sync byte for char. data
  621. TB_20:
  622.         MOV    AH,1            ;Use output buffer
  623.         CALL    PUT_BUFF_DATA        ;Put sync byte in output buff.
  624.         MOV    AL,BLOCK_COUNT
  625.         MOV    AH,1            ;Use output buffer
  626.         CALL    PUT_BUFF_DATA        ;Send the block number
  627.         MOV    SI,TEMP_VIDEO_PTR    ;Point to block of video data
  628.         ADD    SI,CX            ;Adjust for char. or attr.
  629.         MOV    DI,VIDEO_COPY        ;Point to video copy
  630.         ADD    DI,VID_RAM_OFFSET    ;Adjust for block offset
  631.         ADD    DI,CX            ; and character or attribute
  632.         MOV    CX,BLOCK_SIZE        ;Number of bytes to send
  633.         CLD                ;Forward direction
  634. TB_30:
  635.         LODSW                ;Get the unmatched data
  636.         MOV    AH,1            ;Use the output buffer
  637.         CALL    PUT_BUFF_DATA        ;Put the video data in out buff
  638.         STOSB                ;Save video data in copy
  639.         INC    DI            ;Adjust for word offset
  640.         LOOP    TB_30            ;Send block size bytes of data
  641.         RET
  642. TRANSFER_BLOCK    ENDP
  643.  
  644. ;----------------------------------------------------------------------
  645. ;  Put a byte of data into the unattended keyboard buffer.
  646. ;  Input - AL contains ASCII to be put into buffer.
  647. ;       AH contains scan code to be put into buffer.
  648. ;  Output - Carry Set - Byte placed in buffer successfully
  649. ;        Carry Reset - Buffer full, byte not stored in buffer
  650. ;  Changes - Nothing
  651. ;----------------------------------------------------------------------
  652. PUT_KEY_DATA    PROC    NEAR
  653.         PUSH    BX            ;Save registers
  654.         PUSH    SI
  655.         PUSH    DI
  656.         MOV    SI,1AH            ;Point to keyboard head pointer
  657.         CLI                ;Don't allow interrupts
  658.         MOV    BX,ES:[1CH]        ;Get the buffer tail pointer
  659.         MOV    DI,BX            ;Save the tail pointer
  660.         INC    BX            ;Point to next data storage
  661.         INC    BX
  662.         CMP    BX,3EH            ;Beyond end of buffer area?
  663.         JNE    PK_10            ;No, then don't reset
  664.         MOV    BX,1EH            ;Yes, reset to buffer begin
  665. PK_10:
  666.         CMP    BX,ES:[1AH]        ;Test for buffer full
  667.         JE    PK_EXIT         ;If the same, don't save it
  668.                         ; exit, carry is already reset
  669.         MOV    ES:[DI],AX        ;Store the data in buffer
  670.         MOV    ES:[1CH],BX        ;Save new tail pointer
  671.         STC                ;Indicate data stored OK
  672. PK_EXIT:
  673.         POP    DI
  674.         POP    SI
  675.         POP    BX
  676.         STI                ;Enable interrupts
  677.         RET
  678. PUT_KEY_DATA   ENDP
  679.  
  680. ;======================================================================
  681. ;  COMMON ROUTINES - These routines are common to both the unattended
  682. ;  processing portion of the program and the manned processing portion.
  683. ;======================================================================
  684.  
  685. ;----------------------------------------------------------------------
  686. ;  Get a byte of data from a buffer.  Byte pointed to by head pointer is
  687. ;  is next data byte.  If head=tail, no data in buffer.
  688. ;  Input - AH - Buffer to use 0=Input buffer, 1=Output buffer.
  689. ;  Output - Carry Set - Byte from buffer is in AL
  690. ;        Carry Reset - No data in buffer
  691. ;  Changes - AL
  692. ;----------------------------------------------------------------------
  693. GET_BUFF_DATA    PROC    NEAR
  694.     ASSUME    CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
  695.         PUSH    BX            ;Save registers
  696.         PUSH    SI
  697.         CMP    AH,0            ;Check which buffer to use
  698.         JNZ    GD_10            ;Jump for output buffer
  699.         MOV    SI,OFFSET IN_BUFF_HEAD    ;Point to input buffer
  700.         JMP    GD_20            ;Skip over out buffer
  701. GD_10:
  702.         MOV    SI,OFFSET OUT_BUFF_HEAD ;Point to output buffer
  703. GD_20:
  704.         CLI                ;Don't allow interrupts
  705.         MOV    BX,[SI]         ;Get the buffer head pointer
  706.         CMP    BX,2[SI]        ;Test for data in buffer
  707.         JE    GD_EXIT         ;If the same, no data so
  708.                         ; exit, carry is already reset
  709.         MOV    AL,[BX]         ;Get the data
  710.         INC    BX            ;Point to data in buffer
  711.         CMP    6[SI],BX        ;Beyond end of buffer area?
  712.         JNE    GD_30            ;No, then don't reset
  713.         MOV    BX,4[SI]        ;Yes, reset to buffer begin
  714. GD_30:
  715.         MOV    [SI],BX         ;Save new head pointer
  716.         STC                ;Indicate data is in AL
  717. GD_EXIT:
  718.         POP    SI            ;Restore registers
  719.         POP    BX
  720.         STI                ;Enable interrupts
  721.         RET
  722. GET_BUFF_DATA    ENDP
  723.  
  724. ;----------------------------------------------------------------------
  725. ;  Put a byte of data into a buffer.  Byte is stored at location
  726. ;  pointed to by tail pointer.
  727. ;  Input - AL contains data to be put into buffer.
  728. ;       AH - Buffer to use 0=Input buffer, 1=Output buffer
  729. ;  Output - Carry Set - byte placed in buffer successfully
  730. ;        Carry Reset - Buffer full, byte not stored in buffer
  731. ;  Changes - Nothing
  732. ;----------------------------------------------------------------------
  733. PUT_BUFF_DATA    PROC    NEAR
  734.         ASSUME    CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
  735.         PUSH    AX            ;Save registers
  736.         PUSH    BX
  737.         PUSH    DX
  738.         PUSH    SI
  739.         PUSH    DI
  740.         PUSH    DS
  741.         PUSH    CS            ;Set data segment to CS
  742.         POP    DS
  743.         CMP    AH,0            ;Check which buffer to use
  744.         JNZ    PD_10            ;Jump for output buffer
  745.         MOV    SI,OFFSET IN_BUFF_HEAD    ;Point to input buffer
  746.         JMP    PD_20            ;Skip over out buffer
  747. PD_10:
  748.         MOV    SI,OFFSET OUT_BUFF_HEAD ;Point to output buffer
  749. PD_20:
  750.         CLI                ;Don't allow interrupts
  751.         MOV    BX,2[SI]        ;Get the buffer tail pointer
  752.         MOV    DI,BX            ;Save the tail pointer
  753.         INC    BX            ;Point to next data storage
  754.         CMP    6[SI],BX        ;Beyond end of buffer area?
  755.         JNE    PD_30            ;No, then don't reset
  756.         MOV    BX,4[SI]        ;Yes, reset to buffer begin
  757. PD_30:
  758.         CMP    BX,[SI]         ;Test for buffer full
  759.         JE    PD_40             ;If so, exit carry is reset
  760.  
  761.         MOV    [DI],AL         ;Store the data in buffer
  762.         MOV    2[SI],BX        ;Save new tail pointer
  763.         STC                ;Indicate data stored ok
  764. PD_40:
  765.         PUSHF                ;Save the flags
  766.         CMP    BYTE PTR COMM_INT_STA,0    ;Transmit int. running?
  767.         JNZ    PD_50            ;Yes, so exit
  768.         MOV    AX,OUT_BUFF_HEAD    ;Is data in output buffer
  769.         CMP    AX,OUT_BUFF_TAIL
  770.         JZ    PD_50            ;No, so exit
  771.         MOV    BYTE PTR COMM_INT_STA,1    ;Set transmitting data flag
  772.         MOV    AH,1            ;Use the output buffer
  773.         CALL    GET_BUFF_DATA        ;Get data from output buffer
  774.         MOV    DX,COMM_PORT        ;Get port base address
  775.         OUT    DX,AL            ;Send the data out the port
  776. PD_50:
  777.         STI                ;Enable interrupts
  778.         POPF                ;Restore flags
  779.         POP    DS            ;Restore registers
  780.         POP    DI
  781.         POP    SI
  782.         POP    DX
  783.         POP    BX
  784.         POP    AX
  785.         RET
  786. PUT_BUFF_DATA    ENDP
  787.  
  788. ;----------------------------------------------------------------------
  789. ;  Clear the input buffer
  790. ;  Input - Nothing
  791. ;  Output - Nothing
  792. ;  Changes - Nothing
  793. ;----------------------------------------------------------------------
  794. CLEAR_INBUFF    PROC    NEAR
  795.         ASSUME    CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
  796.         PUSH    AX            ;Save register
  797.         CLI                ;Disable interrupts
  798.         MOV    AX,IN_BUFF_TAIL        ;Get buffer tail pointer
  799.         MOV    IN_BUFF_HEAD,AX        ;Make head equal tail
  800.         STI                ;Enable interrupts
  801.         POP    AX
  802.         RET
  803. CLEAR_INBUFF    ENDP
  804.  
  805. ;----------------------------------------------------------------------
  806. ;  Clear the output buffer
  807. ;  Input - Nothing
  808. ;  Output - Nothing
  809. ;  Changes - Nothing
  810. ;----------------------------------------------------------------------
  811. CLEAR_OUTBUFF    PROC    NEAR
  812.         ASSUME    CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
  813.         PUSH    AX            ;Save register
  814.         CLI                ;Disable interrupts
  815.         MOV    AX,OUT_BUFF_TAIL    ;Get buffer tail pointer
  816.         MOV    OUT_BUFF_HEAD,AX    ;Make head equal tail
  817.         STI                ;Enable interrupts
  818.         POP    AX
  819.         RET
  820. CLEAR_OUTBUFF    ENDP
  821.  
  822. ;----------------------------------------------------------------------
  823. ;  Reset the modem and send the setup string to initialize
  824. ;  Input - AL - 0 use setup string 1, 1 use setup string 2
  825. ;  Output - Nothing
  826. ;  Changes - Nothing
  827. ;----------------------------------------------------------------------
  828. RESET_MODEM    PROC    NEAR
  829.     ASSUME    CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
  830.         PUSH    SI            ;Save registers
  831.         PUSH    DX
  832.         PUSH    AX
  833.         CMP    BYTE PTR CONNECT_FLAG,0 ;Is modem connected?
  834.         JZ    RM_20            ;No then send setup only
  835.         CALL    CLEAR_OUTBUFF        ;Empty the output buffer
  836.         MOV    BYTE PTR CONNECT_FLAG,0 ;Reset connect flag
  837.         MOV    AL,1            ;Wait a second for guard time
  838.         CALL    DELAY
  839.         MOV    SI,OFFSET MODEM_ESCAPE    ;Send modem escape code
  840.         CALL    LOAD_ZSTRING
  841.         MOV    AL,2            ;Wait
  842.         CALL    DELAY
  843.         MOV    SI,OFFSET MODEM_HANGUP    ;Send modem hangup code
  844.         CALL    LOAD_ZSTRING
  845.         MOV    AL,1            ;Wait for a second
  846.         CALL    DELAY
  847. RM_20:
  848.         MOV    AL,SPEED_FLAG        ;Get speed flag
  849.         CALL    SET_BAUD_RATE
  850.         MOV    SI,OFFSET MODEM_ATTENTION ;Point to modem attention
  851.         CALL    LOAD_ZSTRING          ;Put it into output buffer
  852.         MOV    AL,1            ;Wait for a second
  853.         CALL    DELAY
  854.         POP    AX            ;Get setup string to use
  855.         CMP    AL,0            ;Test for string 1
  856.         JNZ    RM_30            ;No, then use string 2
  857.         MOV    SI,OFFSET MODEM_SETUP1    ;Point to modem setup string 1
  858.         JMP    RM_40
  859. RM_30:
  860.         MOV    SI,OFFSET MODEM_SETUP2    ;Point to modem setup string 2
  861. RM_40:
  862.         CALL    LOAD_ZSTRING        ;Load setup string to modem
  863.         MOV    AL,1            ;Wait a second
  864.         CALL    DELAY
  865.         MOV    SI,OFFSET MODEM_SETUP3    ;Point to modem setup string 3
  866.         CALL    LOAD_ZSTRING        ;Load setup string to modem
  867.         CALL    CLEAR_INBUFF        ;Clear the input buffer
  868.         POP    DX            ;Restore registers
  869.         POP    SI
  870.         RET
  871. RESET_MODEM    ENDP
  872.  
  873. ;----------------------------------------------------------------------
  874. ;  Check carrier reads the carrier status signal and sets Z flag to 
  875. ;  indicate status
  876. ;  Input - Nothing
  877. ;  Output - Zero flag 0 - Carrier
  878. ;        Zero flag 1 - No Carrier detected
  879. ;  Changes - Nothing
  880. ;----------------------------------------------------------------------
  881. CHECK_CARRIER    PROC    NEAR
  882.     ASSUME    CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
  883.         PUSH    AX            ;Save registers
  884.         PUSH    DX
  885.         MOV    DX,COMM_PORT        ;Get the comm base address
  886.         ADD    DX,6            ;Modem status register
  887.         IN    AL,DX            ;Get the current status
  888.         TEST    AL,10000000B        ;Data carrier detect
  889.         POP    DX            ;Restore registers
  890.         POP    AX
  891.         RET
  892. CHECK_CARRIER    ENDP
  893.  
  894. ;----------------------------------------------------------------------
  895. ;  DELAY - delay approximate number of seconds in AL
  896. ;  Input - AL
  897. ;  Output - Nothing (just waits till AL is zero)
  898. ;  Changes - Nothing
  899. ;----------------------------------------------------------------------
  900. DELAY        PROC    NEAR
  901.         PUSH    CX            ;Save registers
  902.         PUSH    DX
  903.         PUSH    DI
  904.         PUSH    AX
  905.         XOR    AH,AH            ;Read system time
  906.         INT    1AH
  907.         MOV    DI,DX            ;Save low tick count
  908.         MOV    SI,CX            ;Save high tick count
  909.         POP    AX            ;Get number of seconds to delay
  910.         PUSH    AX
  911.         XOR    CX,CX            ;Zero CX
  912.         MOV    CL,AL            ;Put seconds into loop counter
  913. D_10:
  914.         ADD    DI,19D            ;Approximate counts in a second
  915.         ADC    SI,0            ;Add carry to SI
  916.         LOOP    D_10
  917. D_20:
  918.         XOR    AH,AH            ;Read system time
  919.         INT    1AH
  920.         CMP    SI,CX
  921.         JNE    D_20
  922.         CMP    DI,DX            ;End of delay time
  923.         JGE    D_20            ;No, keep checking
  924.         POP    AX            ;Restore registers
  925.         POP    DI
  926.         POP    DX
  927.         POP    CX
  928.         RET
  929. DELAY        ENDP
  930.  
  931. ;----------------------------------------------------------------------
  932. ;  String at SI is placed in output buffer to be sent out serial port
  933. ;  Input - SI points to zero terminated string
  934. ;  Output - Nothing
  935. ;  Changes - SI
  936. ;----------------------------------------------------------------------
  937. LOAD_ZSTRING    PROC    NEAR
  938.         PUSH    AX            ;Save register
  939.         MOV    AH,1            ;Use output buffer
  940.         CLD                ;Forward
  941. LZ_10:
  942.         LODSB                ;Get a byte of data
  943.         CMP    AL,0            ;Check for zero
  944.         JZ    LZ_EXIT         ;Yes, then exit
  945.         CALL    PUT_BUFF_DATA        ;No, put in output buffer
  946.         JMP    LZ_10            ;Process next data
  947. LZ_EXIT:
  948.         POP    AX            ;Restore register
  949.         RET
  950. LOAD_ZSTRING    ENDP
  951.  
  952. ;----------------------------------------------------------------------
  953. ;  Check for a key in the keyboard buffer, if one is there, get it
  954. ;  Input - Nothing
  955. ;  Output - Zero flag = 1 no key in buffer
  956. ;        Zero flag = 0 key is in AX
  957. ;  Changes - AX
  958. ;----------------------------------------------------------------------
  959. GET_KEYSTROKE    PROC    NEAR
  960.     ASSUME    CS:CSEG,DS:NOTHING,ES:NOTHING,SS:NOTHING
  961.         MOV    AH,1            ;Check for keystroke
  962.         INT    16H            ;Keyboard BIOS
  963.         JZ    GK_EXIT         ;No key so exit
  964.         PUSHF                ;Save the zero flag
  965.         XOR    AH,AH            ;Get the keystroke
  966.         INT    16H
  967.         POPF                ;Restore the zero flag
  968. GK_EXIT:
  969.         RET
  970. GET_KEYSTROKE    ENDP
  971.  
  972. ;----------------------------------------------------------------------
  973. ;  Change the interrupt 8 vector to the interrupt service routine of
  974. ;  PCREMOTE
  975. ;  Input - CX points to starting buffer location
  976. ;  Output - Input and output buffer points are initialized
  977. ;  Changes - BX, CX
  978. ;----------------------------------------------------------------------
  979. INIT_BUFFERS    PROC    NEAR
  980.     ASSUME    CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
  981.         MOV    BX,OFFSET IN_BUFF_HEAD    ;In buffer will be here
  982.         MOV    WORD PTR [BX],CX    ; Set head pointer to buffer
  983.         MOV    WORD PTR 2[BX],CX    ;Set tail pointer to buffer
  984.         MOV    WORD PTR 4[BX],CX    ;Set begin of buffer
  985.         ADD    CX,IN_BUFF_SIZE     ;CX Points to end of in buffer
  986.         MOV    WORD PTR 6[BX],CX    ;Set end of buffer
  987.         MOV    BX,OFFSET OUT_BUFF_HEAD ;Out buffer after in buffer
  988.         MOV    WORD PTR [BX],CX    ; Set head pointer to buffer
  989.         MOV    WORD PTR 2[BX],CX    ;Set tail pointer to buffer
  990.         MOV    WORD PTR 4[BX],CX    ;Set begin of buffer
  991.         ADD    CX,OUT_BUFF_SIZE    ;CX Points to end of out buffer
  992.         MOV    WORD PTR 6[BX],CX    ;Set end of buffer
  993.         RET
  994. INIT_BUFFERS    ENDP
  995.  
  996. ;----------------------------------------------------------------------
  997. ;  Change the interrupt 8 vector to the interrupt service routine of
  998. ;  PCREMOTE
  999. ;  Input - Nothing
  1000. ;  Output - Interrupt vector 8 points to INT8
  1001. ;  Changes - AX, DX, BX, ES
  1002. ;----------------------------------------------------------------------
  1003. MODIFY_INT8    PROC    NEAR
  1004.     ASSUME    CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
  1005. ;
  1006. ;    Change interrupt 8 vector
  1007. ;
  1008.         MOV    AX,3508H        ;Get interrupt 8h vector
  1009.         INT    21H
  1010.         MOV    OLDINT_8,BX        ;And save it
  1011.         MOV    OLDINT_8[2],ES
  1012.         MOV    AX,2508H        ;Set interrupt 8h vector
  1013.         MOV    DX,OFFSET INT8        ; to point to new routine
  1014.         INT    21H
  1015.         RET
  1016. MODIFY_INT8    ENDP
  1017.  
  1018. ;----------------------------------------------------------------------
  1019. ;  Set baud rate to 1200 or 2400
  1020. ;  Input - AL -0 1200 baud, 1 2400 baud
  1021. ;  Output - Nothing
  1022. ;  Changes - Nothing
  1023. ;----------------------------------------------------------------------
  1024. SET_BAUD_RATE    PROC    NEAR
  1025.     ASSUME    CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
  1026.         PUSH    DX            ;Save registers
  1027.         PUSH    BX
  1028.         PUSH    SI
  1029.         PUSH    AX
  1030.         MOV    DX,COMM_PORT        ;Get port address
  1031.         ADD    DX,3            ;Line control register
  1032.         MOV    AL,83H            ;Toggle port address to
  1033.         OUT    DX,AL            ; prepare to set baud rate
  1034.         SUB    DX,2            ;Baud rate divisor MSB port
  1035.         POP    AX            ;Restore baud rate
  1036.         PUSH    AX
  1037.         XOR    AH,AH            ;Zero AH
  1038.         MOV    SI,AX            ;Save in index register
  1039.         SHL    SI,1            ;Multiply by 2, word address
  1040.         MOV    BX,OFFSET BAUD_RATE    ;Point to baud rates
  1041.         MOV    AL,[BX+SI]        ;Get baud rate MSB
  1042.         OUT    DX,AL            ; and set it
  1043.         DEC    DX            ;Baud rate divisor LSB port
  1044.         MOV    AL,1[BX+SI]        ;Get baud rate LSB
  1045.         OUT    DX,AL            ; and set it
  1046.         ADD    DX,3            ;Line control register
  1047.         MOV    AL,3            ;8 data bits,1 stop,no parity
  1048.         OUT    DX,AL            ;Set data bit pattern
  1049.                         ; and toggle port address
  1050.         POP    AX            ;Restore registers
  1051.         POP    SI
  1052.         POP    BX
  1053.         POP    DX
  1054.         RET
  1055. SET_BAUD_RATE    ENDP
  1056.  
  1057. ;======================================================================
  1058. ;  Initialize routines.  The initialize routine for unattended is first
  1059. ;  because it must remain resident.
  1060. ;======================================================================
  1061.  
  1062. ;-----------------------------------------------------------------------------
  1063. ;  Initialize the unattended program.
  1064. ;-----------------------------------------------------------------------------
  1065. INIT_UNATTENDED PROC    NEAR
  1066.     ASSUME    CS:CSEG,DS:CSEG,ES:CSEG,SS:NOTHING
  1067.         CALL    IU_10            ;Init pointers,clear video copy
  1068.         CALL    MODIFY_INT8        ;Change INT 8 vector
  1069. ;
  1070. ;    Terminate-Stay-Resident
  1071. ;
  1072.         MOV    DX,VIDEO_COPY        ;Start of video copy
  1073.         ADD    DX,4000D        ;Allow room for video copy
  1074.         INT    27H            ;Terminate-Stay-Resident
  1075. ;
  1076. ;    Initialize buffer pointers and video copy pointer
  1077. ;
  1078. IU_10:
  1079.         PUSH    ES            ;Save extra segment
  1080.         MOV    CX,OFFSET INITIALIZE    ;CX points to begin of buffer
  1081.         ADD    CX,256D         ;Leave room for TSR stack
  1082.         CALL    INIT_BUFFERS        ;Initalize the buffer pointers
  1083.         INC    CX            ;Point to copy of video ram
  1084.         MOV    TEMP_VIDEO_PTR,CX    ;Save address of temp video buf
  1085.         ADD    CX,BLOCK_SIZEX2     ;Save room for temp video data
  1086.         MOV    VIDEO_COPY,CX        ;Save address of video copy
  1087. ;
  1088. ;    fill video RAM image with with space code since screen
  1089. ;    of manned system is blanked when connected
  1090. ;
  1091.         PUSH    CS            ;Video copy is destination
  1092.         POP    ES            ;ES:DI points to video copy
  1093.         MOV    DI,WORD PTR VIDEO_COPY
  1094.         MOV    AX,0720H        ;Data to fill buffer
  1095.         CLD                ;Move upward
  1096.         MOV    CX,2000D        ;Move 2000 words
  1097.         REP    STOSW            ;Fill to force screen dump
  1098.         MOV    CURSOR_POSITION,0FFFFH    ;Force cursor position update
  1099.         MOV    AL,1            ;Use setup string 2
  1100.         CALL    RESET_MODEM        ;Reset the modem
  1101.         POP    ES            ;Restore extra segment
  1102.         RET
  1103. INIT_UNATTENDED ENDP
  1104.  
  1105. ;-----------------------------------------------------------------------------
  1106. ;  INITIALIZE - Initialize the program.  Determine whether it is manned
  1107. ;  or unattended by processing the command line.  Initialize the serial
  1108. ;  port.
  1109. ;-----------------------------------------------------------------------------
  1110. INITIALIZE    PROC    NEAR
  1111.     ASSUME    CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
  1112. ;
  1113. ;    Display copyright notice.
  1114. ;
  1115.         MOV    DX,OFFSET COPYRIGHT    ;Display copyright notice
  1116.         MOV    AH,9            ;Display string
  1117.         INT    21H
  1118. ;
  1119. ;    check to see if the program is already in memory
  1120. ;
  1121.         MOV    BYTE PTR START,0    ;Zero word to avoid false match
  1122.         XOR    BX,BX            ;Initialize search segment
  1123.         MOV    AX,CS            ;Save current segment in AX
  1124.         CLD                ;Clear direction flag
  1125. I_10:
  1126.         INC    BX            ;Increment search segment
  1127.         CMP    AX,BX            ;Reached current segment?
  1128.         JE    I_20            ;Yes, PCREMOTE not resident
  1129.         MOV    ES,BX            ;Point ES to search segment
  1130.         MOV    SI,OFFSET START     ;Start of compare area
  1131.         MOV    DI,SI            ;Make offsets equal
  1132.         MOV    CX,16D            ;Check 16 characters
  1133.         REPE    CMPSB            ;Compare the strings
  1134.         JNE    I_10            ;Compare failed
  1135.         MOV    AH,09H            ;Print string
  1136.         MOV    DX,OFFSET PROG_RES    ;Display program resident mess.
  1137.         INT    21H
  1138.         INT    20H            ;Terminate
  1139. ;
  1140. ;    Process command line for switches.
  1141. ;
  1142. I_20:
  1143.         PUSH    CS            ;Restore ES
  1144.         POP    ES
  1145.         MOV    BX,80H            ;Point to command line length
  1146.         MOV    AH,[BX]         ;Get command line length
  1147. I_30:
  1148.         OR    AH,AH            ;Check for commands
  1149.         JZ    I_70            ;None, so don't look
  1150.         INC    BX            ;Point to next data
  1151.         MOV    AL,[BX]         ;Get data
  1152.         DEC    AH            ;Decrement counter
  1153.         CMP    AL,"/"            ;Check for slash
  1154.         JNE    I_30            ;No, jump to check next data
  1155.         OR    AH,AH            ;Check for data after slash
  1156.         JZ    I_70            ;No, so don't process
  1157.         INC    BX            ;Point to next data
  1158.         MOV    AL,[BX]         ;Get data
  1159.         DEC    AH            ;Decrement counter
  1160.         CMP    AL,"2"            ;Check for comm2
  1161.         JNE    I_40            ;No, check for another switch
  1162.         INC    BYTE PTR COMM_FLAG    ;Set comm2 flag
  1163.         JMP    I_30            ;Process next switch
  1164. I_40:
  1165.         OR    AL,20H            ;Force data to lower case
  1166.         CMP    AL,"m"            ;Check for manned switch
  1167.         JNE    I_50            ;No, check for another switch
  1168.         INC    BYTE PTR MANNED_FLAG    ;Set manned flag
  1169.         JMP    I_30            ;Process next switch
  1170. I_50:
  1171.         CMP    AL,"f"            ;Check for fast speed
  1172.         JNE    I_60            ;No, check for another switch
  1173.         INC    BYTE PTR SPEED_FLAG    ;Set high speed flag
  1174.         JMP    I_30            ;Process next switch
  1175. I_60:
  1176.         CMP    AL,"d"            ;Check for desnow
  1177.         JNE    I_30            ;No, process next switch
  1178.         INC    BYTE PTR DESNOW_FLAG    ;Set desnow flag
  1179.         JMP    I_30            ;Process next switch
  1180.  
  1181. ;----------------------------------------------------------------------
  1182. ;  Initialize the serial port
  1183. ;----------------------------------------------------------------------
  1184.  
  1185. I_70:
  1186. ;
  1187. ;    get the comm port base address using 2* comm port flag as offset
  1188. ;
  1189.         PUSH    DS            ;Save data segment
  1190.         XOR    BX,BX            ;Zero BX
  1191.         MOV    BL,COMM_FLAG        ;Get comm port flag
  1192.         MOV    SI,BX            ;Save in index register
  1193.         SHL    SI,1            ;Multiply by 2, word address
  1194.         MOV    AX,40H            ;Point DS to BIOS data area
  1195.         MOV    DS,AX
  1196.         XOR    BX,BX            ;Point to comm port address
  1197.         MOV    AX,[BX+SI]        ;Get comm port address
  1198.         POP    DS            ;Restore data segment
  1199.         MOV    COMM_PORT,AX        ;Save comm port address
  1200. ;
  1201. ;    disable the interrupts on the 8250 and initialize DTR and RTS
  1202. ;
  1203.         CLI                ;Disable interrupts
  1204.         MOV    DX,COMM_PORT        ;Get UART base address
  1205.         ADD    DX,4            ;Modem control register
  1206.         MOV    AL,00001011B        ;Set DTR, RTS, and OUT2
  1207.         OUT    DX,AL
  1208. ;
  1209. ;    set the baud rate of the UART and initialize line control register
  1210. ;
  1211.         MOV    AL,SPEED_FLAG        ;Get speed flag
  1212.         CALL    SET_BAUD_RATE
  1213. ;
  1214. ;    modify the interrupt vector for the comm port and set 8259 mask
  1215. ;
  1216.         CMP    BYTE PTR COMM_FLAG,0    ;Determine INT vector to change
  1217.         JZ    I_80
  1218.         MOV    AL,11D            ;Vector for comm2
  1219.         MOV    BL,0F7H            ;Mask for 8259 comm2
  1220.         JMP    I_90
  1221. I_80:
  1222.         MOV    AL,12D            ;Vector for comm1
  1223.         MOV    BL,0EFH            ;Mask for 8259 comm1
  1224. I_90:
  1225.         MOV    AH,25H            ;Set interrupt for comm vector
  1226.         MOV    DX,OFFSET INT_COMM    ; to point to routine
  1227.         INT    21H
  1228.         IN    AL,21H            ;Get current 8259 int mask
  1229.         AND    AL,BL            ;Mask appropriate int bit
  1230.         OUT    21H,AL            ;And set new 8259 mask
  1231. ;
  1232. ;    enable the data received interrupt and reset the 8250
  1233. ;
  1234.         MOV    DX,COMM_PORT        ;Point to comm port
  1235.         INC    DX            ;Point to int enable reg
  1236.         MOV    AL,3            ;Enable data received int
  1237.         OUT    DX,AL
  1238.         DEC    DX            ;Point to base address
  1239.         MOV    CX,7            ;Reset the serial port
  1240. I_100:
  1241.         IN    AL,DX            ;Read registers to reset
  1242.         INC    DX
  1243.         LOOP    I_100
  1244. ;
  1245. ;    determine color or monochrome and save appropriate video segment
  1246. ;
  1247.         MOV    AH,0FH            ;Determine video mode
  1248.         INT    10H            ;By using BIOS int 10
  1249.         CMP    AL,7            ;Check for monochrome
  1250.         JZ    MONOCHROME              ;Jump if it is
  1251.         MOV    WORD PTR VIDEO_SEGMENT,0B800H ;Nope, it's CGA or EGA
  1252.         JMP    I_110                  ;Skip over
  1253. MONOCHROME:
  1254.         MOV    WORD PTR VIDEO_SEGMENT,0B000H ;It's a monochrome
  1255. I_110:
  1256. ;
  1257. ;    If manned then execute manned initialization, otherwise execute
  1258. ;    unattended initialization.
  1259. ;
  1260.         CMP    BYTE PTR MANNED_FLAG,0    ;Manned or unattended
  1261.         JNZ    INIT_MANNED        ;Init the manned routines
  1262.         JMP    INIT_UNATTENDED     ;Init the unattended routines
  1263. INITIALIZE    ENDP
  1264.  
  1265. ;----------------------------------------------------------------------
  1266. ;  Initialize the manned program.  Initialize buffers, and change INT 8
  1267. ;  vector.
  1268. ;----------------------------------------------------------------------
  1269. INIT_MANNED    PROC    NEAR
  1270.     ASSUME    CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
  1271.         MOV    CX,OFFSET LAST_BYTE    ;CX points to begin of buffer
  1272.         CALL    INIT_BUFFERS        ;Initalize the buffer pointers
  1273.         MOV    AX,VIDEO_SEGMENT    ;Set ES to point to video RAM
  1274.         MOV    ES,AX
  1275.         JMP    CONNECT_MANNED        ;Run manned portion of program
  1276. INIT_MANNED    ENDP
  1277.  
  1278. ;======================================================================
  1279. ;  Data used by manned portion of program only.  Not required to be
  1280. ;  resident for unattended mode.
  1281. ;======================================================================
  1282. BLOCK_DATA_COUNT DB    0            ;Number of bytes left to rec.
  1283. TYPE_TRANSFER    DB    0FFH            ;FF - No data transfer in prog.
  1284.                         ;00 - Received FE, char. data
  1285.                         ;01 - Received FF, attr. data
  1286. CUR_STATUS    DB    0            ;0=No cursor data being rec.
  1287.                         ; otherwise, byte count
  1288. CUR_LOW     DB    0            ;Low byte of cursor data
  1289. CUR_HIGH    DB    0            ;High byte of cursor data
  1290. ENTER_NUMBER    DB    CR,LF,CR,LF,"Enter phone number:$"
  1291. NO_CARRIER    DB    CR,LF,"No carrier.$"
  1292. MODEM_ERROR    DB    CR,LF,"Error.$"
  1293. TERMINATE_MESS    DB    CR,LF,"Returning to DOS.$"
  1294. PROG_RES    DB    CR,LF,"PCREMOTE is already resident.$"
  1295. EXIT_MESSAGE    DB    "╔══════════════════╗"
  1296.         DB    "║ OK to EXIT? (Y/N)║"
  1297.         DB    "╚══════════════════╝"
  1298.  
  1299. ;======================================================================
  1300. ;  The manned routine will execute the connect manned routine to call the
  1301. ;  unattended system.  These routines are only used in the manned mode.
  1302. ;======================================================================
  1303.  
  1304. ;----------------------------------------------------------------------
  1305. ;  Connect manned asks for the phone number to call, dials the number
  1306. ;  and waits for connect.  Once connected it sends bursts of 20 CRs at
  1307. ;  one second intervals.  When it receives alpha data it processes video
  1308. ;  data and waits for sync byte (00), then transfers control to the
  1309. ;  manned routine.
  1310. ;----------------------------------------------------------------------
  1311. CONNECT_MANNED    PROC    NEAR
  1312.         ASSUME    CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
  1313.         XOR    AL,AL            ;Use setup string 1
  1314.         CALL    RESET_MODEM        ;Reset the modem first
  1315.         MOV    DX,OFFSET ENTER_NUMBER    ;Point to enter number mess.
  1316.         MOV    AH,9            ;Display message
  1317.         INT    21H
  1318.         MOV    DX,OFFSET UNATTENDED    ;Unused area as keyboard buffer
  1319.         MOV    BX,DX            ;Enter max characters for input
  1320.         MOV    BYTE PTR [BX],40D
  1321.         MOV    AH,0AH            ;Buffered keyboard input
  1322.         INT    21H            ;Get the phone number
  1323.         MOV    AL,1            ;Wait a second
  1324.         CALL    DELAY
  1325.         MOV    SI,OFFSET UNATTENDED    ;Point to phone number
  1326.         INC    SI            ;Amount of data in key buffer
  1327.         XOR    AX,AX            ;Zero AX
  1328.         CLD                ;Forward
  1329.         LODSB                ;Get count
  1330.         OR    AL,AL            ;Check for no input
  1331.         JNZ    CM_10            ;If there is then continue
  1332.         JMP    EXIT_MANNED        ;No, then exit program
  1333. CM_10:
  1334.         PUSH    SI            ;Save pointer
  1335.         MOV    SI,OFFSET TONE_DIAL    ;Send the tone dial command
  1336.         CALL    LOAD_ZSTRING
  1337.         POP    SI            ;Restore pointer
  1338.         ADD    SI,AX            ;Point to end of buffer
  1339.         INC    SI            ;Include CR code
  1340.         MOV    BYTE PTR [SI],0     ;And put a zero on end
  1341.         DEC    SI            ;Adjust for previous INC
  1342.         SUB    SI,AX            ;Back to begin of buffer
  1343.         CALL    LOAD_ZSTRING        ;Dial the phone number
  1344.         MOV    AL,1            ;Wait a second
  1345.         CALL    DELAY
  1346.         CALL    CLEAR_INBUFF        ;Clear input buffer
  1347. CM_20:
  1348.         CALL    CHECK_CARRIER        ;Check for a connect signal
  1349.         JZ    CM_30            ;No, then check for err codes
  1350.         CALL    CLEAR_SCREEN        ;Yes, blank the screen
  1351.         MOV    BYTE PTR CONNECT_FLAG,1 ;Set the connect flag
  1352.         JMP    CM_60            ;Execute manned
  1353. CM_30:
  1354.         MOV    AH,0            ;Use input buffer
  1355.         CALL    GET_BUFF_DATA        ;Get data from buffer
  1356.         JNC    CM_20            ;No data, try again
  1357.         CMP    AL,"3"            ;No carrier code?
  1358.         JNZ    CM_50            ;No, check for other code
  1359. CM_40:        
  1360.         MOV    DX,OFFSET NO_CARRIER    ;Send no carrier message
  1361.         MOV    AH,09H
  1362.         INT    21H
  1363.         JMP    CONNECT_MANNED        ;Yes, reset modem and try again
  1364. CM_50:
  1365.         CMP    AL,"8"            ;2400 no answer code
  1366.         JZ    CM_40            ;Yes, display no carrier mess
  1367.         CMP    AL,"4"            ;Error code?
  1368.         JNZ    CM_20            ;No, check for other code
  1369.         MOV    DX,OFFSET MODEM_ERROR    ;Send modem command error mess
  1370.         MOV    AH,09H
  1371.         INT    21H
  1372.         JMP    CONNECT_MANNED        ;Yes, reset modem and try again
  1373. CM_60:
  1374.         MOV    AL,1            ;Wait for a second
  1375.         CALL    DELAY
  1376.         MOV    BYTE PTR CR_COUNT,20D    ;Send 20 CRs at a time
  1377. CM_70:
  1378.         CALL    CHECK_CARRIER        ;Check for carrier loss
  1379.         JNZ    CM_80            ;No, then continue
  1380.         JMP    EXIT_MANNED        ;Yes, then exit
  1381. CM_80:
  1382.         MOV    AX,OUT_BUFF_TAIL    ;Is output buffer empty?
  1383.         CMP    AX,OUT_BUFF_HEAD
  1384.         JNZ    CM_90            ;No, skip CR
  1385.         MOV    AL,CR            ;Send a CR for speed sync
  1386.         MOV    AH,1            ;Use output buffer
  1387.         CALL    PUT_BUFF_DATA
  1388.         DEC    BYTE PTR CR_COUNT    ;Decrement CR counter
  1389.         JZ    CM_60
  1390. CM_90:
  1391.         MOV    AH,0            ;Use input buffer
  1392.         CALL    GET_BUFF_DATA        ; and check for data
  1393.         JNC    CM_70            ;No data so keep checking
  1394.         CMP    AL,'@'            ;Alpha message?
  1395.         JL    CM_70            ;No, then wait for it
  1396. CM_100:
  1397.         CMP    AL,0            ;Is data a sync byte
  1398.         JNE    CM_110            ;No, then put data on screen
  1399.         CALL    CLEAR_SCREEN        ;Blank the screen
  1400.         JMP    MANNED            ;We're in, let's run program
  1401. CM_110:
  1402.         MOV    DL,AL            ;Prepare to display character
  1403.         MOV    AH,2            ; using DOS
  1404.         INT    21H            ;Display it
  1405. CM_120:
  1406.         CALL    CHECK_CARRIER        ;Check for carrier loss
  1407.         JNZ    CM_130            ;No, then continue
  1408.         JMP    EXIT_MANNED        ;Yes, then exit
  1409. CM_130:
  1410.         CALL    GET_KEYSTROKE        ;Check for a keystroke
  1411.         JZ    CM_150            ;If none, skip next routine
  1412. ;
  1413. ;    Check for exit code, if it is then exit
  1414. ;
  1415.         CMP    AX,WORD PTR EXIT_CODE    ;Check for exit code
  1416.         JNZ    CM_140            ;No, so continue
  1417.         CALL    CONFIRM_EXIT        ;Yes, confirm exit
  1418.         JNZ    CM_150            ;No, so continue, don't send
  1419.         JMP    EXIT_MANNED        ;Otherwise reset and exit
  1420. CM_140:
  1421.         CALL    SEND_KEYSTROKE        ;Send to unattended system
  1422. CM_150:
  1423.         MOV    AH,0            ;Use input buffer
  1424.         CALL    GET_BUFF_DATA        ; and check for data
  1425.         JNC    CM_120            ;No data, check for keys
  1426.         JMP    CM_100            ;Check for sync byte
  1427. CONNECT_MANNED    ENDP
  1428.  
  1429. ;----------------------------------------------------------------------
  1430. ;  Manned portion of the program.  Not RAM resident.  Sends keystrokes
  1431. ;  to the unattended computer.    Data from unattended computer is
  1432. ;  decoded and processed.
  1433. ;----------------------------------------------------------------------
  1434. MANNED        PROC    NEAR
  1435.         ASSUME    CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
  1436. ;
  1437. ;    Check for loss of carrier
  1438. ;
  1439.         CALL    CHECK_CARRIER        ;No, check for carrier loss
  1440.         JNZ    M_10            ;No loss so continue
  1441.         JMP    EXIT_MANNED        ;Otherwise reset and exit
  1442. ;
  1443. ;    Check to see if shift status has changed, if so, put new status
  1444. ;    in the output buffer
  1445. ;
  1446. M_10:
  1447.         MOV    AH,2            ;Prepare to get shift status
  1448.         INT    16H            ;Get shift status
  1449.         CMP    SHIFT_STATUS,AL     ;See if the same
  1450.         JE    M_20            ;If so then next routine
  1451.         MOV    SHIFT_STATUS,AL     ;Save new status
  1452.         MOV    AL,0FDH         ;Sync byte, to expect shift
  1453.         MOV    AH,1            ;Put into output buffer
  1454.         CALL    PUT_BUFF_DATA
  1455.         MOV    AL,SHIFT_STATUS     ;Get the shift status
  1456.         CALL    PUT_BUFF_DATA        ;Send to unattended computer
  1457. ;
  1458. ;    Check for keystoke, if so, put the ASCII code and scan code
  1459. ;    into the output buffer, check it for exit code
  1460. ;
  1461. M_20:
  1462.         CALL    GET_KEYSTROKE        ;Check for keystroke
  1463.         JZ    M_50            ;If none skip this routine
  1464. ;
  1465. ;    Check for exit code, if it is then exit
  1466. ;
  1467.         CMP    AX,WORD PTR EXIT_CODE    ;Check for exit code
  1468.         JNZ    M_40            ;No, so continue
  1469.         CALL    CONFIRM_EXIT        ;Yes, confirm exit
  1470.         JNZ    M_50            ;No, so continue, don't send
  1471.         JMP    EXIT_MANNED        ;Otherwise reset and exit
  1472. M_40:
  1473.         CALL    SEND_KEYSTROKE        ;Send keystroke
  1474. ;
  1475. ;    Check for receive data, if available, get data and decode
  1476. ;
  1477. M_50:
  1478.         MOV    AH,0            ;Get data from input buffer
  1479.         CALL    GET_BUFF_DATA
  1480.         JC    M_60            ;Data is there, so process
  1481.         JMP    M_EXIT            ;No data,so loop again
  1482. M_60:
  1483.         CMP    BYTE PTR TYPE_TRANSFER,0FFH ;Check transfer type
  1484.         JZ    M_100            ;If ff, check for sync byte
  1485. M_70:
  1486.         CMP    VID_RAM_OFFSET,0FFFFH    ;Received block no. yet?
  1487.         JNZ    M_80            ;Yes, then process as data
  1488.         MOV    BYTE PTR BLOCK_DATA_COUNT,BLOCK_SIZE ;Data counter
  1489.         MOV    BX,BLOCK_SIZEX2     ;Get block size in bytes
  1490.         MUL    BX            ;Block number X block size
  1491.         ADD    AL,TYPE_TRANSFER    ;Adjust for char. or attr.
  1492.         MOV    VID_RAM_OFFSET,AX    ;Save pointer to video RAM
  1493.         JMP    M_EXIT
  1494. M_80:
  1495.         MOV    DI,VID_RAM_OFFSET    ;Point to video RAM
  1496.         CALL    PUT_VIDEO_DATA        ;Store the data in video RAM
  1497.         INC    DI            ;Point to next video RAM loc.
  1498.         MOV    VID_RAM_OFFSET,DI      ;And save pointer
  1499.         DEC    BYTE PTR BLOCK_DATA_COUNT ;Dec. data counter
  1500.         JZ    M_90              ;End of data, reset variables
  1501.         JMP    M_EXIT            ;Otherwise continue
  1502. M_90:
  1503.         MOV    BYTE PTR TYPE_TRANSFER,0FFH ;Reset type transfer flag
  1504.         JMP    M_EXIT
  1505. M_100:
  1506.         CMP    BYTE PTR CUR_STATUS,0    ;Check cursor status
  1507.         JZ    M_110            ;If 0, check for sync byte
  1508.         XOR    BX,BX            ;Zero BX for index
  1509.         MOV    BL,BYTE PTR CUR_STATUS    ;Use as index for cursor data
  1510.         MOV    DI,OFFSET CUR_STATUS    ;Base address for cursor data
  1511.         MOV    [DI+BX],AL        ;Save the register data
  1512.         INC    BL            ;Increment count
  1513.         MOV    BYTE PTR CUR_STATUS,BL    ;And save it
  1514.  
  1515.         CMP    BL,3            ;Check to see if we have 3 byte
  1516.         JNZ    M_EXIT            ;No, so wait till enough data
  1517.         MOV    BH,0            ;Always use page one
  1518.         MOV    DX,WORD PTR CUR_LOW    ;Get cursor position
  1519.         MOV    AH,2            ;Set cursor function
  1520.         INT    10H
  1521.         MOV    BYTE PTR CUR_STATUS,0    ;Reset cursor status
  1522.         JMP    M_EXIT
  1523. M_110:
  1524.         PUSH    AX            ;Save the data
  1525.         AND    AL,0FEH         ;Mask out LSB
  1526.         CMP    AL,0FEH         ;Video data sync?
  1527.         JNZ    M_120            ;No, check for cursor sync
  1528.         POP    AX            ;Yes, restore data
  1529.         AND    AL,1            ;Save LSB
  1530.         MOV    TYPE_TRANSFER,AL    ;Set transfer type flag
  1531.         MOV    VID_RAM_OFFSET,0FFFFH    ;Prepare to receive block no.
  1532.         JMP    M_EXIT
  1533. M_120:
  1534.         CMP    AL,0D2H         ;Check for cursor data sync
  1535.         JNZ    M_130            ;If not, then throw away
  1536.         POP    AX            ;Restore data
  1537.         MOV    BYTE PTR CUR_STATUS,1    ;Set cursor status byte
  1538.         JMP    M_EXIT
  1539. M_130:
  1540.         POP    AX            ;Clean up stack
  1541. M_EXIT:
  1542.         JMP    MANNED            ;Do it again
  1543. MANNED        ENDP
  1544.  
  1545. ;----------------------------------------------------------------------
  1546. ;  Exit manned.  The exit code is sent, interrupt vector reset, and
  1547. ;  the modem is hung up and reset
  1548. ;  Input - Nothing
  1549. ;  Output - DOS
  1550. ;  Changes - everything
  1551. ;----------------------------------------------------------------------
  1552. EXIT_MANNED    PROC    NEAR
  1553.     ASSUME    CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
  1554.         MOV    AX,WORD PTR EXIT_CODE    ;Get the exit code
  1555.         CALL    SEND_KEYSTROKE        ;Send the exit code
  1556.         CALL    CLEAR_SCREEN         ;Blank the screen
  1557.         MOV    DX,OFFSET TERMINATE_MESS ;Display terminate call mess.
  1558.         MOV    AH,09H
  1559.         INT    21H
  1560.         XOR    AL,AL            ;Reset modem and exit
  1561.         CALL    RESET_MODEM
  1562.         MOV    AL,1            ;Wait a second
  1563.         CALL    DELAY
  1564. ;
  1565. ;  Disable the serial port interrupts and reset the 8259 mask
  1566. ;
  1567.         MOV    DX,COMM_PORT        ;Get port address
  1568.         INC    DX            ;Interrupt enable reg.
  1569.         XOR    AL,AL
  1570.         OUT    DX,AL            ;Disable all interrupts
  1571.         CMP    BYTE PTR COMM_FLAG,0    ;Determine mask bit to change
  1572.         JZ    EM_10
  1573.         MOV    BL,00001000B        ;Mask for 8259 comm2
  1574.         JMP    EM_20
  1575. EM_10:
  1576.         MOV    BL,00010000B        ;Mask for 8259 comm1
  1577. EM_20:
  1578.         IN    AL,21H            ;Get current 8259 int mask
  1579.         OR    AL,BL            ;Set appropriate int bit
  1580.         OUT    21H,AL            ;And set new 8259 mask
  1581.         INT    20H            ;Terminate program
  1582. EXIT_MANNED    ENDP
  1583.  
  1584. ;----------------------------------------------------------------------
  1585. ;  Clear screen.  This routine will blank the video display
  1586. ;  Input - Nothing
  1587. ;  Output - Screen is cleared
  1588. ;  Changes - AX, BX, CX, DX
  1589. ;----------------------------------------------------------------------
  1590. CLEAR_SCREEN    PROC    NEAR
  1591.     ASSUME    CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
  1592.         MOV    BX,0            ;Use video page one
  1593.         MOV    DX,0            ;Position cursor at row 0 col 0
  1594.         MOV    AH,2            ;Set cursor function
  1595.         INT    10H
  1596.         MOV    AX,0700H        ;Scroll down, clear screen
  1597.         MOV    BH,07H            ;White on black
  1598.         MOV    CX,0            ;Upper left corner
  1599.         MOV    DH,24D            ;Lower right corner
  1600.         MOV    DL,79D
  1601.         INT    10H            ;Video BIOS call
  1602.         RET
  1603. CLEAR_SCREEN    ENDP
  1604.  
  1605. ;----------------------------------------------------------------------
  1606. ;  Store the video data in AL in the memory location pointed to by DI
  1607. ;  Input - AL video data, ES:DI video RAM destination
  1608. ;  Output - Nothing
  1609. ;  Changes - DI is incremented
  1610. ;----------------------------------------------------------------------
  1611. PUT_VIDEO_DATA    PROC    NEAR
  1612.     ASSUME    CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
  1613. ;
  1614. ;    Check desnow flag, if set wait for horizontal sync to put in video RAM
  1615. ;
  1616.         PUSH    BX            ;Save registers
  1617.         PUSH    DX
  1618.         CMP    BYTE PTR DESNOW_FLAG,0    ;Check desnow flag
  1619.         JZ    PV_30            ;No, skip over
  1620.         CLD                ;Forward
  1621.         MOV    BL,AL            ;Save video data
  1622.         MOV    DX,3DAH            ;CGA status port
  1623.         CLI                ;Disable interrupts
  1624. PV_10:
  1625.         IN    AL,DX            ;Get status byte
  1626.         TEST    AL,1            ;Test display enable
  1627.         JNZ    PV_10            ;If in Hor. sync then wait
  1628. PV_20:
  1629.         IN    AL,DX            ;Get status byte
  1630.         TEST    AL,1            ;Test display enable
  1631.         JZ    PV_20            ;Wait for Hor. sync
  1632.         XCHG    AX,BX            ;Get video data
  1633. PV_30:
  1634.         STOSB                ;And put into video RAM
  1635.         STI                ;Enable interrupts
  1636.         POP    DX            ;Restore registers
  1637.         POP    BX
  1638.         RET
  1639. PUT_VIDEO_DATA    ENDP
  1640.  
  1641. ;----------------------------------------------------------------------
  1642. ;  Display OK to exit message and wait for response
  1643. ;  Input - Nothing
  1644. ;  Output - Zero flag set - exit, zero flag reset - do not exit
  1645. ;  Changes - CX, SI, DI
  1646. ;----------------------------------------------------------------------
  1647. CONFIRM_EXIT    PROC    NEAR
  1648.     ASSUME    CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
  1649.         PUSH    AX            ;Save the exit code
  1650. CE_10:
  1651.         MOV    AX,OUT_BUFF_HEAD    ;Wait until the out buffer
  1652.         CMP    AX,OUT_BUFF_TAIL    ; is empty
  1653.         JNZ    CE_10
  1654. ;
  1655. ;  Save the existing video data in the output buffer
  1656. ;
  1657.         CALL    SWITCH_DS_ES
  1658.         MOV    DI,ES:OUT_BUFF_BEGIN    ;Use output buffer as temp stor.
  1659.         MOV    SI,0            ;Upper left corner of video
  1660.         MOV    CX,3            ;Transfer 3 lines
  1661. CE_20:
  1662.         PUSH    CX            ;Save line counter
  1663.         MOV    CX,20D            ;Transfer 20 char. per line
  1664.         REPNZ    MOVSW
  1665.         ADD    SI,120D         ;Next line
  1666.         POP    CX            ;Restore line counter
  1667.         LOOP    CE_20
  1668. ;
  1669. ;  Display the ok to exit message
  1670. ;
  1671.         CALL    SWITCH_DS_ES
  1672.         MOV    DI,0            ;Upper left corner of video
  1673.         MOV    SI,OFFSET EXIT_MESSAGE    ;Exit message
  1674.         MOV    CX,3            ;Display three lines
  1675. CE_30:
  1676.         PUSH    CX            ;Save line counter
  1677.         MOV    CX,20D            ;Display 20 characters per line
  1678. CE_40:
  1679.         LODSB
  1680.         CALL    PUT_VIDEO_DATA        ;Display the character
  1681.         MOV    AL,7            ;White on black attribute
  1682.         CALL    PUT_VIDEO_DATA        ;Store attribute
  1683.         LOOP    CE_40
  1684.         ADD    DI,120D         ;Next line
  1685.         POP    CX            ;Restore line counter
  1686.         LOOP    CE_30
  1687. ;
  1688. ;  Wait for keystroke and convert to lower case
  1689. ;
  1690. CE_50:
  1691.         CALL    GET_KEYSTROKE        ;Check for keystroke
  1692.         JZ    CE_50            ;None there, try again
  1693.         OR    AL,20H            ;Convert to lower case
  1694. ;
  1695. ;  Restore the saved video data
  1696. ;
  1697.         MOV    SI,OUT_BUFF_BEGIN    ;Old video is in output buffer
  1698.         MOV    DI,0            ;Upper left corner of video
  1699.         MOV    CX,3            ;Transfer 3 lines
  1700. CE_60:
  1701.         PUSH    CX            ;Save line counter
  1702.         MOV    CX,20D            ;Transfer 20 char. per line
  1703.         REPNZ    MOVSW
  1704.         ADD    DI,120D         ;Next line
  1705.         POP    CX            ;Restore line counter
  1706.         LOOP    CE_60
  1707.         CMP    AL,'y'            ;Check for yes, all others no
  1708.         POP    AX            ;Restore exit code
  1709.         RET
  1710. CONFIRM_EXIT    ENDP
  1711.  
  1712. ;----------------------------------------------------------------------
  1713. ;  Switch ES and DS
  1714. ;  Input - Nothing
  1715. ;  Output - ES is in DS and DS is in ES
  1716. ;  Changes - ES, DS
  1717. ;----------------------------------------------------------------------
  1718. SWITCH_DS_ES    PROC    NEAR
  1719.         PUSH    ES
  1720.         PUSH    DS
  1721.         POP    ES
  1722.         POP    DS
  1723.         RET
  1724. SWITCH_DS_ES    ENDP
  1725.  
  1726. ;----------------------------------------------------------------------
  1727. ;  Put the keystroke data into the output buffer to be sent to unattended
  1728. ;  system
  1729. ;  Input - AX - keystroke data
  1730. ;  Output - Nothing
  1731. ;  Changes - Nothing
  1732. ;----------------------------------------------------------------------
  1733. SEND_KEYSTROKE    PROC    NEAR
  1734.     ASSUME    CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
  1735.         PUSH    AX            ;Save it
  1736.         MOV    AH,1            ;Use the output buffer
  1737.         MOV    AL,0FEH         ;Sync byte, to expect key data
  1738.         CALL    PUT_BUFF_DATA        ;Put AL into the output buffer
  1739.         POP    AX            ;Get AL back
  1740.         PUSH    AX            ;Save AH
  1741.         MOV    AH,1            ;Use the output buffer
  1742.         CALL    PUT_BUFF_DATA        ;Put ASCII code in out buffer
  1743.         POP    AX            ;Get AH back
  1744.         PUSH    AX            ;Save keystroke
  1745.         MOV    AL,AH            ;Move it to AL
  1746.         MOV    AH,1            ;Use the output buffer
  1747.         CALL    PUT_BUFF_DATA        ;Put scan code in out buffer
  1748.         POP    AX            ;Restore keystroke
  1749.         RET
  1750. SEND_KEYSTROKE    ENDP
  1751.  
  1752. ;======================================================================
  1753. LAST_BYTE    EQU    $
  1754. CSEG        ENDS
  1755.         END    START
  1756.