www.pudn.com > commutil.zip > BBPLUS.ASM


            page    55,132 
            title   "BBPLUS - Compuserve B+ Protocol Module" 
 
; --------------------------------------------------------------------- 
; 
; Maintenance Log: 
; 
; Version    Date   Description                        Who 
; -------  -------  ---------------------------------- ---------------- 
;   1.0    08Feb91  Initial version complete           Flanders/Holmes 
; 
; --------------------------------------------------------------------- 
 
protocol    segment para public 'code' 
            assume  cs:protocol 
 
start:      jmp     bpmbplus                ; jump to start 
            db      "BD"                    ; backdown protocol ID 
 
            db      1                       ; nbr of protocols 
 
            db      "B"                     ; invocation letter 
            db      "CIS B+ V1.0     ", 0   ; name to display 
            db      1                       ; protocol number 
 
; -------------------------------------------------------------------- 
;  Macro(s) 
; -------------------------------------------------------------------- 
 
FARRET      macro                           ; far return macro 
            db      0cbh 
            endm 
 
NSTATE      macro   nxtstate                ; go to next state 
            ifnb                  ; if next state given 
            mov     state, nxtstate         ; move in next state 
            endif 
            stc                             ; tell state_exec to do it 
            ret                             ; .. continue 
            endm 
 
XSTATE      macro   nxtstate                ; exit the state machine 
            ifnb                  ; if next state given 
            mov     state, nxtstate         ; move in next state 
            endif 
            clc                             ; tell state_exec to do it 
            ret                             ; .. continue 
            endm 
 
; --------------------------------------------------------------------- 
;  Protocol characters equates 
; --------------------------------------------------------------------- 
 
$ETX        =       03h                     ; Trailer byte 
$ENQ        =       05h                     ; Enquiry code 
$CR         =       0Dh                     ; Carriage return 
$DLE        =       10h                     ; Lead in byte 
$NAK        =       15h                     ; Negative acknowledgement 
 
; --------------------------------------------------------------------- 
;  Local stack 
; --------------------------------------------------------------------- 
 
            even 
bpmstack    db      32 dup ("St")           ; local stack area 
bpmstackend db      "Es"                    ; End of local stack 
 
stackoffset dw      offset bpmstackend      ; New stack pointer 
 
; --------------------------------------------------------------------- 
;  State definitions 
; --------------------------------------------------------------------- 
 
$ST_INIT    =       -1                      ; Awaiting initialization 
$ST_DLE     =       0                       ; DLE seen 
$ST_DLEB    =       2                       ; B seen 
$ST_GETDATA =       4                       ; Getting data in packet 
$ST_GETCKS  =       6                       ; Getting checksum 
$ST_GETCRC  =       8                       ; Getting crc 
$ST_VERCRC  =       10                      ; Verifying CRC 
$ST_VERCKS  =       12                      ; Verifying Checksum 
$ST_VERPKT  =       14                      ; Verifying Packet 
$ST_SNDNAK  =       16                      ; Sending a NAK 
$ST_SNDACK  =       18                      ; Sending an ACK 
$ST_GETDLE  =       20                      ; Wait for a DLE 
 
state       dw      $ST_INIT                ; current state 
 
state_jmp   dw      bpdle                   ;  0: DLE seen 
            dw      bpdleb                  ;  2: B seen 
            dw      bpgetdata               ;  4: Getting data in packet 
            dw      bpgetcks                ;  6: Getting checksum 
            dw      bpgetcrc                ;  8: Getting crc 
            dw      bpvercrc                ; 10: Verifying CRC 
            dw      bpvercks                ; 12: Verifying Checksum 
            dw      bpverpkt                ; 14: Verifying Packet 
            dw      bpsndnak                ; 16: Sending a NAK 
            dw      bpsndack                ; 18: Sending an ACK 
            dw      bpgetdle                ; 20: Wait for a DLE 
 
 
; --------------------------------------------------------------------- 
;  Transport Parameter Packet 
; 
;  This protocol supports the following: 
; 
;        Send window:   1 packet    Receive window:   2 packets 
;         Block size: 512 bytes       Check method: CRC 
;    Transport Layer:  No          Download resume:  No 
;      Upload Resume:  No         File information:  No 
; 
;       Data Quoting:      and  
; --------------------------------------------------------------------- 
 
tp_seq      db      ?                       ; sequence number 
tp_msg      db      "+", 0, 1, 4, 1, 1, 0   ; Transport parmameter pkt 
tp_msgq     db           14h, 0, 0d4h, 0    ; quoting level 
            db      $ETX 
tp_msg_len  =       $-tp_seq                ; Length of message 
 
; --------------------------------------------------------------------- 
;  Data areas 
; --------------------------------------------------------------------- 
 
flgs        db      0                       ; various flags 
flgfnc      =       10000000b               ; 1... .... callback active 
flgrcv      =       01000000b               ; .1.. .... character rcv'd 
flgcan      =       00100000b               ; ..1. .... cancel req'd 
flgtmo      =       00010000b               ; ...1 .... timeout 
flgopen     =       00001000b               ; .... 1... file is open 
flgrec      =       00000100b               ; .... .1.. record available 
 
bparea      label   byte                    ; internal BPAREA 
bpflg       db      0                       ; BPLUS flags 
bpfcrc      =       10000000b               ; 1... .... Use CRC checking 
bpfqut      =       01000000b               ; .1.. .... Next is quoted char 
bpseq       db      '0'                     ; current sequence number 
bpq         db      8 dup (0ffh)            ; default quoting set 
 
ubp_area    dd      ?                       ; users' save area 
ubp_areao   equ     word ptr ubp_area       ; offset 
ubp_areas   equ     word ptr ubp_area+2     ; segment 
 
bpqc00      db      32 dup (0)              ; 00h-1fh quoting 
bpqc80      db      32 dup (0)              ; 80h-9fh quoting 
 
ticks       dw      ?                       ; entry nbr ticks 
 
jmptab      dw      init                    ; 0: initialization call 
            dw      fncok                   ; 2: last function ok 
            dw      fncfail                 ; 4: last function failed 
            dw      commchar                ; 6: character received 
            dw      kbdchar                 ; 8: keystroke encountered 
 
MAXCODE     =       8                       ; maximum entry code 
 
CHRTMOUT    =       ((10*182)/10)           ; 10 second char timeout 
PKTTMOUT    =       ((25*182)/10)           ; 25 second char timeout 
MAXERRS     =       10                      ; maximum errors in row 
 
errors      db      0                       ; error counter 
 
filename    db      65 dup (0)              ; space for filename 
 
packet      db      520 dup (?)             ; packet buffer 
 
rcvaddr     dw      offset packet           ; address for next receive 
 
ckbyte2     db      ?                       ; byte 2 of chk val (crc) 
ckbyte1     db      ?                       ; byte 1 (crc or cksum) 
crcval      equ     word ptr ckbyte2        ; .. to access it as a word 
chksumval   equ     byte ptr ckbyte1        ; .. to access it as a byte 
 
oldds       dw      ?                       ; caller's ds 
 
oldsp       dw      ?                       ; caller's sp 
oldss       dw      ?                       ; caller's ss 
 
init2x      db      13, 'B+: Init called 2x', 13, 0 
badfnc      db      13, 'B+: Bad fnc code', 13, 0 
openerr     db      13, 'B+: Unable to open requested file', 13, 0 
timedout    db      13, 'B+: Timeout, protocol ended', 13, 0 
toomany     db      13, 'B+: Too many errors', 13, 0 
notinited   db      13, "B+: Not init'd first", 13, 0 
sendercan   db      13, 'B+: Download cancelled', 13, 0 
success     db      13, 'B+: Download completed OK', 13, 0 
writerr     db      13, 'B+: Aborted: write error', 13, 0 
openok      db      13, 'B+: Receiving ', 0 
alrdyopen   db      13, 'B+: File opened twice', 13, 0 
unknownpkt  db      13, 'B+: Unknown packet type', 13, 0 
noupload    db      13, "B+: Can't upload", 13, 0 
clsb4open   db      13, 'B+: Close before open', 13, 0 
staterr0    db      13, 'B+: Staterr 0', 13, 0 
staterr1    db      13, 'B+: Staterr 1', 13, 0 
 
panicmsg    dw      7 
            db      10h, 10h, 10h, 10h, 10h, "++" 
; --------------------------------------------------------------------- 
;  Protocol Mainline 
; --------------------------------------------------------------------- 
 
bpmbplus    proc                            ; entry point 
            push    es                      ; save caller's regs 
            push    ds 
 
            mov     cs:oldds, ds            ; keep copy of caller's ds 
 
            mov     cs:oldss, ss            ; save caller's stack 
            mov     cs:oldsp, sp 
 
            mov     cs:ticks, ax            ; save entry ticks 
 
            mov     ax, cs                  ; ax -> our segment 
            mov     ds, ax                  ; ds -> our segment 
            mov     es, ax                  ; es -> our segment 
 
            cli                             ; no interrupts .. 
            mov     ss, ax                  ; ss -> our segment 
            mov     sp, stackoffset         ; sp -> end of stack 
            sti                             ; .. allow ints again 
 
            cmp     di, MAXCODE             ; q. is code ok? 
            ja      bpmbplus90              ; a. no .. return "done" 
 
            test    di, 1                   ; q. is code even? 
            jnz     bpmbplus90              ; a. no .. return "done" 
 
            jmp     jmptab[di]              ; .. call requested routine 
 
bpmbplus90: lea     bx, badfnc              ; bx -> bad function code 
            jmp     proto_err               ; issue error and leave 
 
bpmbplus    endp 
 
 
; --------------------------------------------------------------------- 
;   Initialization call;                 ds:bx -> operands (filename) 
; --------------------------------------------------------------------- 
 
init        proc 
 
            cmp     state, $ST_INIT         ; q. already init'd? 
            je      init00                  ; a. no .. continue 
 
            lea     bx, init2x              ; bx -> error message 
            jmp     proto_err               ; .. kill the protocol 
 
init00:     mov     ubp_areao, si           ; save user's offset 
            push    oldds                   ; push user's ds 
            pop     ubp_areas               ; .. set bparea segment 
 
            push    ds                      ; save our ds 
            lds     si, ubp_area            ; ds:si -> user's area 
            lea     di, bparea              ; di -> our bp area 
            mov     cx, 10                  ; cx = bytes to move 
            cld                             ; .. in upward direction 
      rep   movsb                           ; .. move it in. 
            pop     ds                      ; restore our ds 
 
            lea     si, bpq                 ; si -> quote parameters 
            lea     di, bpqc00              ; di -> quote array 
            call    bd_setq                 ; setup quote array 
 
            mov     state, $ST_DLE          ; set state to DLE SEEN 
            mov     bx, CHRTMOUT            ; bx = ticks to wait 
            call    setimer                 ; .. set the timer 
            jmp     proto_ok                ; .. return to caller 
 
init        endp 
 
 
; --------------------------------------------------------------------- 
;  Last function executed ok -or- simple dispatch 
;                                           flgfnc = 0: simple dispatch 
;                                           fncfnc = 1: state return 
;                                               -- Carry is cleared 
; --------------------------------------------------------------------- 
 
fncok       proc 
 
            test    flgs, flgfnc            ; q. callback return? 
            jz      fncok05                 ; a. no .. dispatch 
 
            clc                             ; show function succeeded 
            ret                             ; .. rtn to callback caller 
 
fncok05:    cmp     state, $ST_INIT         ; q. init'd yet? 
            jne     fncok10                 ; a. yes .. continue 
 
            lea     bx, notinited           ; bx -> not init'd msg 
            jmp     proto_err               ; .. kill the protocol 
 
fncok10:    jmp     short check_rec         ; see if record received 
 
fncok       endp 
 
 
; --------------------------------------------------------------------- 
;  Previous function failed                 Carry set to show failure 
; --------------------------------------------------------------------- 
 
fncfail     proc                            ; last function failed 
 
            test    flgs, flgfnc            ; q. callback return? 
            jnz     fncfail10               ; a. yes .. continue 
 
            lea     bx, staterr1            ; bx -> state error msg 
            jmp     proto_err               ; .. tell user & die 
 
fncfail10:  stc                             ; set carry to show fail 
            ret                             ; return to callback caller 
 
fncfail     endp 
 
; --------------------------------------------------------------------- 
;  Process Communications Character         dl = character 
; --------------------------------------------------------------------- 
 
commchar    proc 
 
            cmp     state, $ST_INIT         ; q. init'd yet? 
            jne     commchar05              ; a. yes .. continue 
 
            lea     bx, notinited           ; bx -> not init'd msg 
            jmp     proto_err               ; .. kill the protocol 
 
commchar05: test    flgs, flgfnc            ; q. callback return? 
            jz      commchar10              ; a. no .. continue 
 
            lea     bx, staterr0            ; bx -> state error msg 
            jmp     proto_err               ; .. tell user & die 
 
commchar10: mov     bx, rcvaddr             ; bx -> receive address 
            mov     [bx], dl                ; save received character 
 
            or      flgs, flgrcv            ; show a char was received 
 
            jmp     short check_rec         ; see if record received 
 
commchar    endp 
 
 
; --------------------------------------------------------------------- 
;  Process keyboard character               dl = character 
; --------------------------------------------------------------------- 
 
kbdchar     proc 
 
            cmp     state, $ST_INIT         ; q. init'd yet? 
            jne     kbdchar05               ; a. yes .. continue 
 
            lea     bx, notinited           ; bx -> not init'd msg 
            jmp     proto_err               ; .. kill the protocol 
 
kbdchar05:  test    flgs, flgfnc            ; q. callback return? 
            jz      kbdchar10               ; a. no .. continue 
 
            lea     bx, staterr0            ; bx -> state error msg 
            jmp     proto_err               ; .. tell user & die 
 
kbdchar10:  cmp     dx, 4F00H               ; q. END key? 
            jnz     kbdchar20               ; a. no .. skip it 
 
            or      flgs, flgcan            ; show cancel requested. 
 
kbdchar20:  jmp     short check_rec         ; see if record received 
 
kbdchar     endp 
 
 
; --------------------------------------------------------------------- 
;  See if record received 
; --------------------------------------------------------------------- 
 
check_rec   proc 
 
            call    state_exec              ; exec the state machine 
 
            test    flgs, flgrec            ; q. record received? 
            jz      chk_rec90               ; a. no .. exit 
 
            and     flgs, not flgrec        ; shut off indicator 
 
            cmp     packet+1, '+'           ; q. transport parms? 
            jne     chk_rec10               ; a. no .. check next 
 
            call    proc_tport              ; process transport rec 
            jmp     proto_ok                ; .. continue 
 
chk_rec10:  cmp     packet+1, 'T'           ; q. transfer packet? 
            jne     chk_rec20               ; a. no .. check next 
 
            call    proc_trec               ; process T record 
            jmp     proto_ok                ; .. continue 
 
chk_rec20:  cmp     packet+1, 'N'           ; q. data packet? 
            jne     chk_rec30               ; a. no .. check next 
 
            call    proc_nrec               ; process N record 
            jmp     proto_ok                ; .. continue 
 
chk_rec30:  lea     bx, sendercan           ; else .. sender cancelled it 
 
            cmp     packet+1, 'F'           ; q. failure packet? 
            je      chk_rec40               ; a. yes .. kill protocol 
 
            lea     bx, unknownpkt          ; unknown packet type 
 
chk_rec40:  call    panic                   ; panic abort! 
            jmp     proto_err               ; .. the the users 
 
chk_rec90:  jmp     proto_ok                ; .. continue later 
 
check_rec   endp 
 
 
; --------------------------------------------------------------------- 
;  Process transport (+) record 
; --------------------------------------------------------------------- 
 
proc_tport  proc 
 
 
 
            lea     si, packet+8            ; point at quoting set 
            lea     di, bpq                 ; di -> quoting set 
            mov     cx, 4                   ; words to move 
            cld                             ; .. in upward direction 
       rep  movsw                           ; .. move in the quote set 
 
            mov     al, packet+5            ; al = tp's crc flag 
            push    ax                      ; .. save on stack 
 
            mov     al, packet              ; get his packet # 
            mov     bpseq, al               ; .. save it in ours 
 
            call    nxtseq                  ; set next sequence nbr 
 
            mov     al, bpseq               ; al =  next sequence no 
            mov     tp_seq, al              ; .. save in seq record 
 
            lea     si, tp_seq              ; si -> our tport record 
            lea     di, packet              ; di -> send packet area 
            mov     cx, tp_msg_len          ; cx =  length o'packet 
            call    bd_setout               ; .. set up output 
 
            pop     ax                      ; restore crc flag 
 
            and     bpflg, not bpfcrc       ; assume checksum 
 
            or      al, al                  ; q. use CRC? 
            jz      tport10                 ; a. no .. continue 
 
            or      bpflg, bpfcrc           ; .. set on CRC 
 
tport10:    mov     bx, di                  ; bx -> string to send 
            mov     di, 18                  ; di =  send 2cnt string 
            call    callback                ; .. send it out 
 
            lea     si, bpq                 ; si -> quote parameters 
            lea     di, bpqc00              ; di -> quote array 
            call    bd_setq                 ; setup new quote array 
 
            and     flgs, not flgtmo        ; reset timout 
            mov     bx, PKTTMOUT            ; .. use packet timout 
            call    setimer                 ; .. reset timer 
            mov     state, $ST_GETDLE       ; .. set next state 
 
            ret                             ; .. and return to caller 
 
proc_tport  endp 
 
 
; --------------------------------------------------------------------- 
;  Process T record 
; --------------------------------------------------------------------- 
 
proc_trec   proc 
 
            cmp     packet+2, 'D'           ; q. send to us (download)? 
            jne     trec10                  ; a. no .. check next 
 
            lea     bx, alrdyopen           ; file already open 
 
            test    flgs, flgopen           ; q. file open? 
            jnz     trec06                  ; a. yes.. error 
 
            lea     si, packet+4            ; si -> file name 
            lea     di, filename            ; di -> output area 
            cld                             ; .. address ascending 
 
trec03:     lodsb                           ; al = filename char 
 
            cmp     al, ' '                 ; q. above blank? 
            ja      trec05                  ; a. yes .. 
 
            xor     al, al                  ; else .. clear al 
 
trec05:     stosb                           ; .. put char in filename 
 
            or      al, al                  ; q. end of filename? 
            jnz     trec03                  ; a. no .. continue 
 
            lea     bx, filename            ; bx -> filename to open 
            mov     di, 2                   ; di = open a file 
            call    callback                ; ask for open 
            jnc     trec07                  ; .. continue protocol 
 
            call    panic                   ; kill the protocol 
            lea     bx, openerr             ; bx -> open error msg 
trec06:     jmp     proto_err               ; .. die now 
 
trec07:     lea     bx, openok              ; bx -> opened ok 
            mov     di, 12                  ; di = display ASCIIZ 
            call    callback                ; .. display the message 
 
            lea     bx, filename            ; bx -> filename opened 
            mov     di, 12                  ; di = display ASCIIZ 
            call    callback                ; .. display the message 
 
            mov     bl, $CR                 ; bx -> carriage return 
            mov     di, 14                  ; di = display character 
            call    callback                ; .. display the message 
 
            call    nxtseq                  ; set next sequence number 
            call    bpsndack                ; .. ack the pack 
            or      flgs, flgopen           ; .. show file open 
            ret                             ; .. continue 
 
trec10:     cmp     packet+2, 'C'           ; q. closing file? 
            jne     trec20                  ; a. no .. check next 
 
            call    nxtseq                  ; get next sequence number 
            call    bpsndack                ; send an ack 
 
            lea     bx, clsb4open           ; close before open 
 
            test    flgs, flgopen           ; q. file open? 
            jz      trec90                  ; a. no .. error 
 
            and     flgs, not flgopen       ; reset open flag 
            lea     bx, success             ; bx -> success 
            jmp     proto_err               ; .. return to caller 
 
trec20:     lea     bx, noupload            ; bx -> no upload msg 
 
            cmp     packet+3, 'U'           ; q. upload from us? 
            je      trec30                  ; a. no .. uh oh. 
 
            lea     bx, unknownpkt          ; bx -> unknown packet type 
 
trec30:     call    panic                   ; panic abort! 
trec90:     jmp     proto_err               ; .. tell the user 
 
proc_trec   endp 
 
 
; --------------------------------------------------------------------- 
;  Process data packet 
; --------------------------------------------------------------------- 
 
proc_nrec   proc 
 
            mov     cx, rcvaddr             ; cx = next rcv addr 
            sub     cx, offset packet       ; cx = len of packet 
            sub     cx, 3                   ; cx = len of data 
            jz      nrec10                  ; .. skip if no data 
            mov     word ptr packet, cx     ; .. save in packet 
 
            lea     bx, packet              ; bx -> packet 
            mov     di, 4                   ; di =  write data 
            call    callback                ; q. write that data ok? 
            jc      nrec20                  ; a. yes .. continue 
 
nrec10:     call    nxtseq                  ; .. set for next sequence 
            call    bpsndack                ; else .. send an ack 
            ret                             ; .. let it keep running 
 
nrec20:     call    panic                   ; abort the protocol 
            lea     bx, writerr             ; bx -> write error message 
            jmp     proto_err               ; .. kill the protocol 
 
proc_nrec   endp 
 
 
; --------------------------------------------------------------------- 
;  Run the state machine 
; --------------------------------------------------------------------- 
 
state_exec  proc 
 
            cmp     ticks, 0                ; q. timeout on ticks? 
            jg      state10                 ; a. no .. continue 
 
            or      flgs, flgtmo            ; timeout occurred 
 
state10:    mov     bx, state               ; bx = state offset 
            call    state_jmp[bx]           ; .. go to appropriate state 
            jc      state10                 ; .. next state 
 
            ret                             ; return to caller 
 
state_exec  endp 
 
 
 
; --------------------------------------------------------------------- 
;  State: Wait for DLE 
; --------------------------------------------------------------------- 
 
bpgetdle    proc 
 
            test    flgs, flgcan            ; q. user cancel? 
            jz      bpgdle00                ; a. no .. continue 
 
            call    panic                   ; panic abort 
            and     flgs, not flgcan        ; .. and shut off flag 
 
bpgdle00:   test    flgs, flgrcv            ; q. character received? 
            jnz     bpgdle10                ; a. yes .. check it out 
 
            mov     bx, PKTTMOUT            ; bx = packet timeout 
            call    chktimer                ; q. timeout? 
            jz      bpgdle05                ; a. no .. continue 
 
            lea     bx, timedout            ; bx -> timeout message 
            jmp     chk_err                 ; see if too many errors 
 
bpgdle05:   XSTATE                          ; .. exit the state machine 
 
bpgdle10:   mov     bx, rcvaddr             ; bx -> received char 
            mov     al, [bx]                ; al = received char 
 
            and     flgs, not flgrcv        ; reset receive flag 
 
            cmp     al, $DLE                ; q.  seen? 
            je      bpgdle50                ; a. yes .. process it 
 
            cmp     al, $ENQ                ; q.  seen? 
            jne     bpgdle15                ; a. no .. continue 
 
            NSTATE  $ST_SNDACK              ; else .. send an ACK 
 
bpgdle15:   cmp     al, $NAK                ; q.  received? 
            jne     bpgdle20                ; a. no .. continue 
 
            and     flgs, not flgtmo        ; bx -> protocol error msg 
            XSTATE                          ; .. stay in state 
 
bpgdle20:   cmp     al, $ETX                ; q. ETX? 
            jne     bpgdle05                ; a. no .. continue 
 
            NSTATE  $ST_SNDNAK              ; else .. send a NAK 
 
bpgdle50:   mov     bx, CHRTMOUT            ; set character timout 
            call    setimer                 ; .. reset timer 
            mov     errors, 0               ; .. reset errors 
            and     flgs, not flgtmo        ; .. reset timout 
            XSTATE  $ST_DLE                 ; .. state = DLE seen 
 
bpgetdle    endp 
 
 
; --------------------------------------------------------------------- 
;  State: DLE Seen 
; --------------------------------------------------------------------- 
 
bpdle       proc 
 
            test    flgs, flgrcv            ; q. character received? 
            jnz     bpdle10                 ; a. yes .. check it out 
 
            mov     bx, CHRTMOUT            ; bx = character timeout 
            call    chktimer                ; q. timeout? 
            jz      bpdle05                 ; a. no .. continue 
 
            lea     bx, timedout            ; bx -> timeout message 
            jmp     chk_err                 ; see if too many errors 
 
bpdle05:    XSTATE                          ; exit the state machine 
 
bpdle10:    mov     bx, rcvaddr             ; bx -> received char 
            mov     al, [bx]                ; al = received char 
 
            and     flgs, not flgrcv        ; .. shut off char rcvd 
 
            cmp     al, 'B'                 ; q.  B seen? 
            je      bpdle50                 ; a. yes .. process it 
 
            cmp     al, '0'                 ; q. possible ack? 
            jb      bpdle12                 ; a. no .. continue 
 
            cmp     al, '9'                 ; q. is it an ACK? 
            ja      bpdle12                 ; a. no .. continue 
 
            cmp     al, bpseq               ; q. it it THE ACK? 
            jne     bpdle15                 ; a. no .. continue 
 
            jmp     short bpdle15           ; .. continue 
 
bpdle12:    cmp     al, $ENQ                ; q. Enquiry? 
            jne     bpdle15                 ; a. no .. continue 
 
            NSTATE  $ST_SNDACK              ; .. resend an ack 
 
bpdle15:    mov     bx, PKTTMOUT            ; bx = packet timout 
            call    setimer                 ; .. set the timer 
            XSTATE  $ST_GETDLE              ; else .. get a DLE 
 
bpdle50:    mov     bx, CHRTMOUT            ; bx = character timeout 
            call    setimer                 ; set timer to 10 sec 
            mov     errors, 0               ; reset errors 
            and     flgs, not flgtmo        ; reset timout 
            mov     rcvaddr, offset packet  ; address of sequence 
            XSTATE  $ST_DLEB                ; set next state 
 
bpdle       endp 
 
 
; --------------------------------------------------------------------- 
;  State:  B seen 
; --------------------------------------------------------------------- 
 
bpdleb      proc 
 
            test    flgs, flgrcv            ; q. character received? 
            jnz     bpdleb10                ; a. yes .. check it out 
 
            mov     bx, CHRTMOUT            ; bx = character timeout 
            call    chktimer                ; q. timeout? 
            jz      bpdleb90                ; a. no .. continue 
 
            NSTATE  $ST_SNDNAK              ; send a NAK 
 
bpdleb10:   mov     bx, rcvaddr             ; bx -> received char 
            mov     al, [bx]                ; al = char received 
 
            cmp     al, $ENQ                ; q. ENQ received? 
            jne     bpdleb20                ; a. no .. save character 
 
            XSTATE  $ST_SNDACK              ; send an ACK 
 
bpdleb20:   call    charcvd                 ; receive the char 
 
            and     flgs, not flgtmo        ; reset any timeout 
            mov     bx, CHRTMOUT            ; .. set for char timeout 
            call    setimer                 ; .. reset the timer 
            mov     errors, 0               ; .. reset error counter 
            XSTATE  $ST_GETDATA             ; .. state = get data 
 
bpdleb90:   XSTATE                          ; .. continue 
 
bpdleb      endp 
 
 
; --------------------------------------------------------------------- 
;  State: Get data 
; --------------------------------------------------------------------- 
 
bpgetdata   proc 
 
            test    flgs, flgrcv            ; q. character received? 
            jnz     bpgdat10                ; a. yes .. check it out 
 
            mov     bx, CHRTMOUT            ; bx = character timeout 
            call    chktimer                ; q. timeout? 
            jz      bpdleb90                ; a. no .. continue 
 
            NSTATE  $ST_SNDNAK              ; send a NAK 
 
bpgdat10:   mov     bx, rcvaddr             ; bx -> received char 
            mov     al, [bx]                ; al = char received 
 
            test    bpflg, bpfqut           ; q. awaiting quoted? 
            jz      bpgdat20                ; a. no .. continue 
 
            cmp     al, 60h                 ; q. upper set? 
            pushf                           ; .. save results 
 
            and     al, 1fh                 ; set off upper bits 
 
            popf                            ; q. add 80 hex? 
            jb      bpgdat15                ; a. no .. leave as is. 
 
            add     al, 80h                 ; else .. 80h-9fh 
 
bpgdat15:   mov     [bx], al                ; save unquoted char 
            and     bpflg, not bpfqut       ; .. shut off quoting 
            jmp     short bpgdat85          ; .. and continue protocol 
 
bpgdat20:   cmp     al, $DLE                ; q. quoted char? 
            jne     bpgdat25                ; a. no .. continue 
 
            and     flgs, not flgrcv        ; set off received flag 
            or      bpflg, bpfqut           ; .. and set on quoted flag 
            jmp     short bpgdat90          ; .. and continue 
 
bpgdat25:   cmp     al, $ETX                ; q. ETX received? 
            jne     bpgdat30                ; a. no .. check next 
 
            call    charcvd                 ; save the ETX 
            mov     state, $ST_GETCKS       ; get first byte of check 
            jmp     short bpgdat90          ; .. continue processing 
 
bpgdat30:   cmp     al, $ENQ                ; q. ENQ received? 
            jne     bpgdat85                ; a. no .. received char 
 
            mov     state, $ST_SNDACK       ; .. send out an ack 
            jmp     short bpgdat90          ; .. and continue 
 
bpgdat85:   call    charcvd                 ; .. and process it 
 
bpgdat90:   and     flgs, not flgtmo        ; reset timeout 
            mov     bx, CHRTMOUT            ; .. set to CHAR timout 
            call    setimer                 ; .. reset the timer 
            XSTATE                          ; .. and continue 
 
bpgetdata   endp 
 
 
 
; --------------------------------------------------------------------- 
;  Wait for checksum char 
; --------------------------------------------------------------------- 
 
bpgetcks    proc 
 
            test    flgs, flgrcv            ; q. character received? 
            jnz     bpgcks10                ; a. yes .. check it out 
 
            mov     bx, CHRTMOUT            ; bx = character timeout 
            call    chktimer                ; q. timeout? 
            jz      bpgcks90                ; a. no .. continue 
 
            XSTATE  $ST_SNDNAK              ; send a NAK 
 
bpgcks10:   mov     bx, rcvaddr             ; bx -> received char 
            mov     al, [bx]                ; al = char received 
 
            test    bpflg, bpfqut           ; q. quoting active? 
            jz      bpgcks50                ; a. no .. check/save char 
 
            and     bpflg, not bpfqut       ; .. reset quoting flag 
 
            cmp     al, 60h                 ; q. 80-9f range? 
            pushf                           ; .. save the answer 
 
            and     al, 1fh                 ; .. upper bits off 
 
            popf                            ; .. restore answer .. 
            jb      bpgcks70                ; a. no .. store as is 
 
            add     al, 80h                 ; else.. reconstitute 80-9f 
            jmp     short bpgcks70          ; .. and save it 
 
bpgcks50:   cmp     al, $DLE                ; q. quoted char? 
            jne     bpgcks70                ; a. no .. continue 
 
            and     flgs, not flgrcv        ; "receive" the quote 
            or      bpflg, bpfqut           ; show quoted char expected 
            XSTATE                          ; .. and say in state 
 
bpgcks70:   and     flgs, not flgrcv        ; show byte processed 
            mov     ckbyte1, al             ; save as checksum 
 
            mov     state, $ST_GETCRC       ; .. assume CRC checking 
 
            test    bpflg, bpfcrc           ; q. using CRC? 
            jnz     bpgcks90                ; a. yes .. continue 
 
            NSTATE  $ST_VERCKS              ; else .. verify checksum 
 
bpgcks90:   XSTATE                          ; .. continue 
 
bpgetcks    endp 
 
; --------------------------------------------------------------------- 
;  Wait for CRC character 
; --------------------------------------------------------------------- 
 
bpgetcrc    proc 
 
            test    flgs, flgrcv            ; q. character received? 
            jnz     bpgcrc10                ; a. yes .. check it out 
 
            mov     bx, CHRTMOUT            ; bx = character timeout 
            call    chktimer                ; q. timeout? 
            jz      bpgcrc90                ; a. no .. continue 
 
            XSTATE  $ST_SNDNAK              ; send a NAK 
 
bpgcrc10:   mov     bx, rcvaddr             ; bx -> received char 
            mov     al, [bx]                ; al = char received 
 
            test    bpflg, bpfqut           ; q. quoting active? 
            jz      bpgcrc50                ; a. no .. check/save char 
 
            and     bpflg, not bpfqut       ; .. reset quoting flag 
 
            cmp     al, 60h                 ; q. 80-9f range? 
            pushf                           ; .. save the answer 
 
            and     al, 1fh                 ; .. upper bits off 
 
            popf                            ; .. restore answer .. 
            jb      bpgcrc70                ; a. no .. store as is 
 
            add     al, 80h                 ; else.. reconstitute 80-9f 
            jmp     short bpgcrc70          ; .. and save it 
 
bpgcrc50:   cmp     al, $DLE                ; q. quoted char? 
            jne     bpgcrc70                ; a. no .. continue 
 
            and     flgs, not flgrcv        ; "receive" the quote 
            or      bpflg, bpfqut           ; show quoted char expected 
            XSTATE                          ; .. and say in state 
 
bpgcrc70:   and     flgs, not flgrcv        ; show byte processed 
            mov     ckbyte2, al             ; save as CRC byte 2 
            NSTATE  $ST_VERCRC              ; .. assume CRC checking 
 
bpgcrc90:   XSTATE                          ; .. continue 
 
bpgetcrc    endp 
 
 
; --------------------------------------------------------------------- 
;  Verify Checksum 
; --------------------------------------------------------------------- 
 
bpvercks    proc 
 
            lea     si, packet              ; si -> packet 
            mov     cx, rcvaddr             ; cx -> next to receive 
            sub     cx, si                  ; cx =  length to check 
 
            call    bpcksum                 ; dx = calc'd chksum 
 
            cmp     dl, chksumval           ; q. does it match? 
            je      bpvercks90              ; a. yes .. exit AOK! 
 
            XSTATE  $ST_SNDNAK              ; else .. send a NAK 
 
bpvercks90: NSTATE  $ST_VERPKT              ; .. continue 
 
bpvercks    endp 
 
 
 
; --------------------------------------------------------------------- 
;  Verify CRC 
; --------------------------------------------------------------------- 
 
bpvercrc    proc 
 
            lea     si, packet              ; si -> packet 
            mov     cx, rcvaddr             ; cx -> next to receive 
            sub     cx, si                  ; cx =  length to check 
 
            call    bpcrc                   ; dl = calc'd crc 
 
            cmp     dx, crcval              ; q. does it match? 
            je      bpvercrc90              ; a. yes .. exit AOK! 
 
            XSTATE  $ST_SNDNAK              ; else .. send a NAK 
 
bpvercrc90: NSTATE  $ST_VERPKT              ; .. continue 
 
bpvercrc    endp 
 
 
; --------------------------------------------------------------------- 
;  Verify packet 
; --------------------------------------------------------------------- 
 
bpverpkt    proc 
 
            mov     al, packet              ; al = sequence number 
 
            mov     ah, bpseq               ; ah = last good sequence 
            inc     ah                      ; ah = next seq number 
 
            cmp     ah, '9'                 ; q. did seq wrap? 
            jna     bpverpkt05              ; a. no .. continue 
 
            mov     ah, '0'                 ; ah = next packet number 
 
bpverpkt05: cmp     al, ah                  ; q. expected number? 
            jne     bpverpkt10              ; a. no .. check it out 
 
            mov     errors, 0               ; reset error count 
            or      flgs, flgrec            ; show record received 
            XSTATE  $ST_SNDACK              ; else .. exit the state 
 
bpverpkt10: cmp     packet+1, 'F'           ; q. Fail packet? 
            jne     bpverpkt20              ; a. no .. continue 
 
            or      flgs, flgrec            ; show record received 
            XSTATE                          ; else .. exit the state 
 
bpverpkt20: cmp     al, bpseq               ; q. previous packet? 
            jne     bpverpkt40              ; a. no .. NAK it 
 
            NSTATE  $ST_SNDACK              ; .. ack the pak 
 
bpverpkt40: NSTATE  $ST_SNDNAK              ; .. nak that pak! 
 
bpverpkt    endp 
 
 
; --------------------------------------------------------------------- 
;  Send an ACK 
; --------------------------------------------------------------------- 
 
bpsndack    proc 
 
            mov     bl, $DLE                ; bl = DLE 
            mov     di, 20                  ; di = send one char 
            call    callback                ; .. ask BD to do it 
 
            mov     bl, bpseq               ; bl = sequence number 
            mov     di, 20                  ; di = send one char 
            call    callback                ; .. ask BD to do it 
 
            mov     bl, '.'                 ; bl = I'm alive char 
            mov     di, 14                  ; di = display one char 
            call    callback                ; .. ask BD to do it 
 
            mov     bx, PKTTMOUT            ; set packet timeout 
            call    setimer                 ; set the timer 
            and     flgs, not flgtmo        ; .. reset timeout 
            mov     rcvaddr, offset packet  ; .. reset the receive addr 
            XSTATE  $ST_GETDLE              ; get a DLE 
 
bpsndack    endp 
 
 
; --------------------------------------------------------------------- 
;  Send a NAK 
; --------------------------------------------------------------------- 
 
bpsndnak    proc 
 
            cmp     errors, MAXERRS         ; q. too many errors? 
            jb      bpsndnak10              ; a. no .. continue 
 
            lea     bx, toomany             ; bx -> too many errors msg 
            jmp     proto_err               ; .. exit the protocol 
 
bpsndnak10: mov     bl, $NAK                ; bl = NAK 
            mov     di, 20                  ; di = send one char 
            call    callback                ; .. ask BD to do it 
 
            mov     bl, 'X'                 ; bl = I'm nakking char 
            mov     di, 14                  ; di = display one char 
            call    callback                ; .. ask BD to do it 
 
            mov     bx, PKTTMOUT            ; set packet timeout 
            call    setimer                 ; set the timer 
            and     flgs, not flgtmo        ; .. reset timeout 
            mov     rcvaddr, offset packet  ; .. reset the receive addr 
            XSTATE  $ST_GETDLE              ; get a DLE 
 
bpsndnak    endp 
 
 
; --------------------------------------------------------------------- 
;  Send a panic abort 
; --------------------------------------------------------------------- 
 
panic       proc 
 
            push    bx                      ; save caller's bx 
 
            lea     bx, panicmsg            ; bx -> panic stop msg 
            mov     di, 18                  ; di = send one char 
            call    callback                ; .. ask BD to do it 
 
            pop     bx                      ; restore caller's bx 
            ret                             ; return to caller 
 
panic       endp 
 
 
; --------------------------------------------------------------------- 
;  Check for timeout                        non-zero = timeout 
; --------------------------------------------------------------------- 
 
chktimer    proc 
 
            test    flgs, flgtmo            ; set zf if no timeout 
            pushf                           ; save flags 
            jz      chktimer10              ; .. jump if no timeout 
 
            call    setimer                 ; set 10 second value 
 
chktimer10: popf                            ; restore test results 
            ret                             ; .. return to caller 
 
chktimer    endp 
 
 
; --------------------------------------------------------------------- 
;  Set timer to 10 second timeout           bx = ticks to wait 
; --------------------------------------------------------------------- 
 
setimer     proc 
 
            mov     di, 22                  ; di = set tick downcounter 
            call    callback                ; .. have BD do it 
 
            ret                             ; .. return to caller 
 
setimer    endp 
 
 
; --------------------------------------------------------------------- 
;  Check errors                             bx -> error message 
; --------------------------------------------------------------------- 
 
chk_err     proc 
 
            inc     errors                  ; add one to errors 
 
            cmp     errors, MAXERRS         ; q. too many errors? 
            jb      chk_err10               ; a. no .. continue 
 
            jmp     proto_err               ; .. kill the protocol 
 
chk_err10:  XSTATE                          ; .. continue the protocol 
 
chk_err     endp 
 
 
; --------------------------------------------------------------------- 
;  Show received character processed 
; --------------------------------------------------------------------- 
 
charcvd     proc 
 
            and     flgs, not flgrcv        ; shut off receive bit 
            inc     rcvaddr                 ; point to next address 
 
            ret                             ; return to caller 
 
charcvd     endp 
 
 
; ---------------------------------------------------------------------- 
;   Calculate standard B protocol checksum 
; 
;   entry: si -> block to check 
;          cx =  length 
;    exit: dl =  checksum 
; ---------------------------------------------------------------------- 
 
bpcksum     proc 
 
            push    cx                      ; save register 
 
            xor     ah, ah                  ; ah = zero for additions 
            xor     dx, dx                  ; dx = zero for accumulator 
 
bpcksum10:  shl     dx, 1                   ; dx = shifted left by 1 
 
            cmp     dx, 0ffh                ; q. over 255? 
            jle     bpcksum20               ; a. no .. continue 
 
            and     dx, 0ffh                ; dx = less than 255 
            inc     dx                      ; ..plus one 
 
bpcksum20:  lodsb                           ; al = char from buffer 
            add     dx, ax                  ; dx = acculation of chars 
 
            cmp     dx, 0ffh                ; q. over 255? 
            jle     bpcksum30               ; a. no .. continue 
 
            and     dx, 0ffh                ; dx = less than 255 
            inc     dx                      ; ..plus one 
 
bpcksum30:  loop    bpcksum10               ; loop back till done 
            pop     cx                      ; ..restore register 
            ret                             ; ..then return to caller 
 
bpcksum     endp 
 
 
; ---------------------------------------------------------------------- 
;   Calculate CRC           entry: si -> message block 
;                                  cx =  length of message 
;                            exit: dx =  returned CRC 
; ---------------------------------------------------------------------- 
 
bpcrc       proc 
 
            push    bx                      ; save registers 
            push    cx 
            push    di 
 
            mov     dx, -1                  ; dx = initialize crc 
            mov     bx, 1021h               ; bx = working constant 
            mov     di, 8000h               ; di = constant, too 
 
bpcrc10:    lodsb                           ; al = char from message 
            xor     ah, ah                  ; ax = cast char as integer 
            xchg    al, ah                  ; shift left char by 8 
            xor     dx, ax                  ; crc ^= (int)*ptr++ << 8 
 
            push    cx                      ; save register 
            mov     cx, 8                   ; cx = bit loop count 
 
bpcrc20:    mov     ax, dx                  ; ax = temp copy of crc 
 
            and     ax, di                  ; q. bit on? 
            jz      bpcrc30                 ; a. no .. continue 
 
            shl     dx, 1                   ; shift left by one bit 
            xor     dx, bx                  ; crc = crc << 1 ^ 0x1021 
            jmp     short bpcrc40           ; ..continue with common code 
 
bpcrc30:    shl     dx, 1                   ; crc <<= 1 
 
bpcrc40:    loop    bpcrc20                 ; ..just loop thru this byte 
 
            pop     cx                      ; restore register 
            loop    bpcrc10                 ; ..and loop thru whole message 
 
            pop     di                      ; restore registers 
            pop     cx 
            pop     bx 
 
            ret                             ; return to caller 
 
bpcrc       endp 
 
 
; ---------------------------------------------------------------------- 
;   Setup output field 
;       - with count 
;       - DLE + "B" 
;       - move in data, applying quouting rules 
;       - call CRC/cksum routines 
; 
;   entry: si -> user data w/terminating ETX 
;          di -> destination area 
;          cx =  length 
;    exit: di -> 2byte length + data + CRC/cksum 
; ---------------------------------------------------------------------- 
 
bd_setout   proc 
 
            push    di                      ; save registers 
            xor     bx, bx                  ; bx = extra DLE bytes added 
            mov     ax, cx                  ; get copy of length 
            stosw                           ; store in output record 
 
            push    si                      ; save registers 
            test    bpflg, bpfcrc           ; q. using CRC? 
            jz      bd_seto20               ; a. no .. calculate chksum 
 
            call    bpcrc                   ; dx = CRC of the data 
            add     bx, 2                   ; bx = 2 extra bytes 
            jmp     short bd_seto30         ; ..continue w/common code 
 
bd_seto20:  call    bpcksum                 ; dl = checksum of data 
            inc     bx                      ; bx = 1 extra byte 
 
bd_seto30:  pop     si                      ; restore register 
            push    dx                      ; save CRC/checksum 
            mov     ax, 4210h               ; ax = DLE + "B" 
            stosw                           ; save in output record 
            add     bx, 2                   ; bx = 2 more bytes 
            mov     dx, bx                  ; dx = extra length, now 
            dec     cx                      ; cx = len - 1, for ETX's sake 
 
bd_seto40:  lodsb                           ; al = source byte 
 
            cmp     al, 1fh                 ; q. in the 1st range? 
            ja      bd_seto50               ; a. no .. continue 
 
            xor     ah, ah                  ; ax = (int) source byte 
            mov     bx, ax                  ; bx = index into quote array 
 
            cmp     bpqc00[bx], 0           ; q. need to quote char? 
            je      bd_seto70               ; a. no .. continue 
 
            add     al, 40h                 ; al = quoted character 
            jmp     short bd_seto60         ; ..do rest of quoting stuff 
 
bd_seto50:  cmp     al, 80h                 ; q. maybe in 2nd range? 
            jb      bd_seto70               ; a. no .. normal character 
 
            cmp     al, 9fh                 ; q. really in 2nd range? 
            ja      bd_seto70               ; a. no .. must be normal 
 
            and     al, 1fh                 ; al = 00 - 1fh 
            xor     ah, ah                  ; ax = (int) source byte 
            mov     bx, ax                  ; bx = index into quote array 
 
            cmp     bpqc80[bx], 0           ; q. need to quote char? 
            je      bd_seto70               ; a. no .. continue 
 
            add     al, 60h                 ; al = quoted character 
bd_seto60:  mov     ah, 10h                 ; ah = DLE 
            xchg    al, ah                  ; swap around for store 
            stosw                           ; ..save in output record 
            inc     dx                      ; dx = one more extra char 
            jmp     short bd_seto80         ; ..continue w/common code 
 
bd_seto70:  stosb                           ; save char in output area 
bd_seto80:  loop    bd_seto40               ; ..then loop till done 
 
            movsb                           ; copy ETX to output area 
            pop     ax                      ; ax = CRC/checksum 
            stosw                           ; save one or the other 
 
            pop     di                      ; di -> output count 
            add     [di], dx                ; add in "extra" bytes cnt 
            ret                             ; ..finally, return to caller 
 
bd_setout   endp 
 
 
; ---------------------------------------------------------------------- 
;   Unroll set quote mode fields 
; 
;   entry: si -> source field of 8 bytes 
;          di -> destination field of 64 bytes 
; ---------------------------------------------------------------------- 
 
bd_setq     proc 
 
            mov     cx, 8                   ; cx = big loop size 
 
bd_setq10:  push    cx                      ; save outer loop size 
            mov     cx, 8                   ; cx = bits per byte 
            lodsb                           ; al = source byte 
            mov     ah, al                  ; ah = work value 
 
bd_setq20:  test    ah, 80h                 ; q. bit set? 
            jz      bd_setq30               ; a. no .. clear dest byte 
 
            mov     al, 0ffh                ; al = true value 
            jmp     short bd_setq40         ; ..continue w/common code 
 
bd_setq30:  xor     al, al                  ; al = false value 
 
bd_setq40:  stosb                           ; save in destination array 
            shl     ah, 1                   ; ah = next bit to test 
            loop    bd_setq20               ; ..loop till byte done 
 
            pop     cx                      ; restore outer loop count 
            loop    bd_setq10               ; ..loop till array finished 
 
            ret                             ; ..finally, return to caller 
 
bd_setq     endp 
 
; --------------------------------------------------------------------- 
;  Set bpseq to next sequence number 
; --------------------------------------------------------------------- 
 
nxtseq      proc 
 
            inc     bpseq                   ; increment seq number 
 
            cmp     bpseq, '9'              ; q. rollover? 
            jna     nxtseq90                ; a. no .. exit 
 
            mov     bpseq, '0'              ; .. else return to '0' 
 
nxtseq90:   ret                             ; .. return to caller 
 
nxtseq      endp 
 
; --------------------------------------------------------------------- 
;  Setup to "call" backdown                 di = return code 
; --------------------------------------------------------------------- 
 
callback    proc 
 
            or      flgs, flgfnc            ; show were in callback mode 
 
            jmp     short proto_exit        ; return to caller 
 
callback    endp 
 
 
; --------------------------------------------------------------------- 
;  Display error, return done               bx -> string 
; --------------------------------------------------------------------- 
 
proto_err   proc 
 
            mov     di, 12                  ; di = display string 
            call    callback                ; .. display it 
 
            jmp     short proto_done        ; tell bd we are done 
 
proto_err   endp 
 
 
; --------------------------------------------------------------------- 
;  Protocol done - leave forever 
; --------------------------------------------------------------------- 
 
proto_done  proc 
 
            push    ds                      ; save our ds 
            les     di, ubp_area            ; es:di -> caller' area 
            lea     si, bparea              ; ds:di -> our area 
            mov     cx, 5                   ; words to move 
            cld                             ; ascending 
      rep   movsw                           ; .. return 'em to user 
            pop     ds                      ; restore our DS 
 
            mov     di, 10                  ; di = done code 
 
            jmp     short proto_exit        ; leave the protocol 
 
proto_done  endp 
 
 
; --------------------------------------------------------------------- 
;  Exit with the OK code 
; --------------------------------------------------------------------- 
 
proto_ok    proc 
 
            and     flgs, not flgfnc        ; zero out the function flag 
 
            mov     di, 0                   ; di = ok return code 
 
            jmp     short proto_exit        ; restore regs & exit 
 
proto_ok    endp 
 
 
; --------------------------------------------------------------------- 
;  Protcol exit routine 
; --------------------------------------------------------------------- 
 
proto_exit  proc 
 
            mov     stackoffset, sp         ; save our stack offset 
 
            cli                             ; no interrupts 
            mov     ss, oldss               ; ..restore callers ss 
            mov     sp, oldsp               ; ..and sp 
            sti                             ; ints ok again 
 
            pop     ds                      ; restore caller's regs 
            pop     es 
 
            FARRET                          ; return to caller 
 
proto_exit  endp 
 
protocol    ends 
            end     start