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


            page    55,132 
            title   "BXMODM - XMODEM Protocol Module" 
 
; --------------------------------------------------------------------- 
; 
; Maintenance Log 
; 
; Version    Date   Description                        Who 
; -------  -------  ---------------------------------- ---------------- 
;   1.0    08Feb91  Initial version complete           Flanders/Holmes 
; 
; --------------------------------------------------------------------- 
 
protocol    segment para public 'code'      ; Ascii module 
            assume  cs:protocol 
 
start:      jmp     bpmxmodem               ; jump to start 
            db      "BD"                    ; backdown protocol ID 
 
            db      2                       ; number of protcols 
 
            db      "X"                     ; invocation letter 
            db      "Xmodem V1.0     ", 0   ; name to display 
            db      1                       ; protocol number 
 
            db      "C"                     ; invocation letter 
            db      "Xmodem/CRC V1.0 ", 0   ; name to display 
            db      2                       ; protocol number 
 
 
; -------------------------------------------------------------------- 
;  Macro(s) 
; -------------------------------------------------------------------- 
 
FARRET      macro                           ; far return macro 
            db      0cbh 
            endm 
 
; --------------------------------------------------------------------- 
;  Protocol characters equates 
; --------------------------------------------------------------------- 
 
$SOH        =       1                       ; First byte of packets 
$EOT        =       4                       ; Last byte of packet 
$ACK        =       6                       ; Positive acknowledgement 
$NAK        =       21                      ; Negative acknowledgement 
$CAN        =       24                      ; Cancel transmission 
 
; --------------------------------------------------------------------- 
;  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_SOH     =       0                       ; Awaiting - between pkts 
$ST_EOP     =       2                       ; Awaiting end of packet 
$ST_CAN     =       4                       ; Cancelling protocol 
$ST_UCAN    =       6                       ; User cancelled protocol 
 
state       dw      $ST_INIT                ; current state 
 
state_jmp   dw      xmsoh                   ;  0: Awaiting SOH 
            dw      xmeop                   ;  2: Awaiting end of pkt 
            dw      xmcan                   ;  4: cancel 
            dw      xmucan                  ;  6: user cancel 
 
 
; --------------------------------------------------------------------- 
;  Data areas 
; --------------------------------------------------------------------- 
 
flgs        db      0                       ; various flags 
flgfnc      =       80h                     ; 1... .... callback active 
flgrcv      =       40h                     ; .1.. .... character rcv'd 
flgcan      =       20h                     ; ..1. .... cancel req'd 
flgnrm      =       10h                     ; ...1 .... normal XMODEM 
flgsoh      =       08h                     ; .... 1... first SOH rcvd 
 
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 
 
ONESEC      =       19                      ; A solid 1 sec in ticks 
 
CHRTMOUT    =       12                      ; 12 second char timeout 
CANTMOUT    =       2                       ; 2 seconds for char timout 
MAXERRS     =       10                      ; maximum errors in row 
SOHTMOUT    =       22                      ; Timeout for inter-packet NAK's 
                                            ; Initial NAK to first SOH 
 
timer       db      SOHTMOUT                ; Timeout after first NAK 
 
nseq        db      1                       ; next sequence number 
nakch       db      'C'                     ; NAK Character 
errors      db      0                       ; error counter 
 
cancnt      db      0                       ; count of cancels 
 
filename    db      65 dup (0)              ; space for filename 
 
packet      db      133 dup (?)             ; XMODEM packet buffer 
 
rcvaddr     dw      offset packet           ; address for next receive 
pktsz       db      133                     ; size of expected packet 
 
PKTSOH      equ     byte ptr packet         ; SOH 
PKTSEQ      equ     byte ptr packet+1       ; sequence number 
PKTCSEQ     equ     byte ptr packet+2       ; complementary seq nbr 
PKTDATA     equ     byte ptr packet+3       ; start of data 
PKTCSUM     equ     byte ptr packet+131     ; checksum 
PKTCRC      equ     word ptr packet+131     ; crc if XMODEM/CRC 
PKTBUFLEN   equ     word ptr packet+1       ; length for write 
 
oldds       dw      ?                       ; caller's ds 
 
oldsp       dw      ?                       ; caller's sp 
oldss       dw      ?                       ; caller's ss 
 
init2x      db      13, 'XMODEM: Init called twice', 13, 0 
badfnc      db      13, 'XMODEM: Bad function code', 13, 0 
openerr     db      13, 'XMODEM: Unable to open that file..' 
fileprompt  db      13, 'XMODEM: Enter filename,  to exit: ', 0 
nofile      db      13, 'XMODEM: No filename, protocol aborted', 13, 0 
fileopened  db      13, 'XMODEM: File opened.. starting download', 13, 0 
timedout    db      13, 'XMODEM: Timeout, protocol ended', 13, 0 
toomany     db      13, 'XMODEM: Too many error, download cancelled', 13, 0 
notinited   db      13, 'XMODEM: BD did not call init first', 13, 0 
usercan     db      13, 'XMODEM: User cancelled download', 13, 0 
sendercan   db      13, 'XMODEM: Sender cancelled download', 13,0 
success     db      13, 'XMODEM: Download completed OK', 13, 0 
writerr     db      13, 'XMODEM: Write error.. protocol aborted', 13, 0 
seqerr      db      13, 'XMODEM: Packet sequence error', 13, 0 
staterr0    db      13, 'XMODEM: State error 0', 13, 0 
staterr1    db      13, 'XMODEM: State error 1', 13, 0 
 
; --------------------------------------------------------------------- 
;  Protocol Mainline 
; --------------------------------------------------------------------- 
 
bpmxmodem   proc 
            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      bpmxmodm90              ; a. no .. return "done" 
 
            test    di, 1                   ; q. is code even? 
            jnz     bpmxmodm90              ; a. no .. return "done" 
 
            jmp     jmptab[di]              ; .. call requested routine 
 
bpmxmodm90: lea     bx, badfnc              ; bx -> bad function code 
            jmp     proto_err               ; issue error and leave 
 
bpmxmodem   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:     cmp     dl, 1                   ; q. normal xmodem? 
            jne     init02                  ; a. no .. assume CRC 
 
            or      flgs, flgnrm            ; show normal wanted 
            mov     pktsz, 132              ; .. size of packet 
            mov     nakch, $NAK             ; .. reset nak char 
 
init02:     mov     ds, oldds               ; ds -> callers segment 
 
            cmp     byte ptr [bx], 0        ; q. any filename given? 
            je      init10                  ; a. no .. get the file name 
 
            lea     di, filename            ; di -> area for filename 
            mov     si, bx                  ; si -> input filename 
            cld                             ; .. move upward 
 
init05:     movsb                           ; move in a byte 
 
            cmp     di, offset filename+64  ; q. end of area? 
            je      init20                  ; a. yes .. continue 
 
            cmp     byte ptr [si-1],0       ; q. end of string? 
            jne     init05                  ; a. no .. continue 
 
            push    cs                      ; save our segment 
            pop     ds                      ; .. ds -> our segment 
            jmp     short init20            ; .. open the file 
 
init10:     lea     bx, fileprompt          ; bx -> filename prompt 
 
init15:     mov     di, 12                  ; di =  display ASCIIZ 
            call    callback                ; .. ask bd to display 
 
            lea     bx, filename            ; bx -> filename 
            mov     di, 16                  ; di =  get a line 
            call    callback                ; .. ask bd to get it 
 
            cmp     filename, ' '           ; q. first char non-blank? 
            ja      init20                  ; a. yes .. continue 
 
            lea     bx, nofile              ; bx = no file given 
            jmp     proto_err               ; .. kill the protocol 
 
init20:     lea     bx, filename            ; bx -> filename 
            mov     di, 2                   ; di = open file 
            call    callback                ; q. file open ok? 
            jnc     init25                  ; a. yes .. continue 
 
            lea     bx, openerr             ; bx -> open error 
            jmp     init15                  ; Tell user .. ask for next 
 
init25:     lea     bx, fileopened          ; bx -> file opened msg 
            mov     di, 12                  ; di = display string 
            call    callback                ; .. ask bd to do it 
 
            mov     timer, SOHTMOUT         ; set timer to packet timeout 
 
            call    nak                     ; send a NAK 
 
            mov     bx, ONESEC              ; bx = ticks for 1 second 
            mov     di, 22                  ; di = set tick downcounter 
            call    callback                ; .. set the down counter 
 
            jmp     proto_ok                ; .. and init is done 
 
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 state_exec        ; run the state machine 
 
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 state_exec        ; run the state machine 
 
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 state_exec        ; run the state machine 
 
kbdchar     endp 
 
 
; --------------------------------------------------------------------- 
;  Run the state machine 
; --------------------------------------------------------------------- 
 
state_exec  proc 
 
            cmp     ticks, 0                ; q. timeout on ticks? 
            jg      state10                 ; a. no .. continue 
 
            dec     timer                   ; countdown the timer 
 
            mov     bx, ONESEC              ; bx = ticks for 1 second 
            mov     di, 22                  ; di = set tick downcounter 
            call    callback                ; reset the down counter 
 
state10:    mov     bx, state               ; bx = state offset 
            jmp     state_jmp[bx]           ; .. go to appropriate state 
 
state_exec  endp 
 
; --------------------------------------------------------------------- 
;  Awaiting SOH 
; --------------------------------------------------------------------- 
 
xmsoh       proc 
 
            test    flgs, flgrcv            ; q. character received? 
            jz      xmsoh50                 ; a. no .. check timeouts 
 
            test    flgs, flgcan            ; q. cancel requested? 
            jz      xmsoh05                 ; a. no .. continue 
 
            mov     bl, $CAN                ; bl = CAN 
            mov     di, 20                  ; di = send one character 
            call    callback                ; .. send the cancel 
 
            mov     state, $ST_UCAN         ; set up for user cancel 
            jmp     proto_ok                ; .. and say we're ok 
 
xmsoh05:    cmp     packet, $SOH            ; q. packet received? 
            jne     xmsoh10                 ; a. no .. check next 
 
            call    charcvd                 ; show char processed 
 
            or      flgs, flgsoh            ; show 1st SOH found 
            mov     nakch, $NAK             ; reset the NAK char 
 
            mov     state, $ST_EOP          ; show awaiting end pkt 
            jmp     proto_ok                ; .. show we are ok 
 
xmsoh10:    cmp     packet, $CAN            ; q. cancel by sender? 
            jne     xmsoh15                 ; a. no .. check next 
 
            mov     state, $ST_CAN          ; start the cancel 
            mov     timer, SOHTMOUT         ; .. restart the timer 
            jmp     short xmsoh20           ; .. kill the character 
 
xmsoh15:    cmp     packet, $EOT            ; q. end of transmission? 
            jne     xmsoh20                 ; a. no .. continue 
 
            mov     di, 6                   ; close the file 
            call    callback                ; .. ask bd to do it 
 
            call    ack                     ; send an ack 
 
            lea     bx, success             ; bx -> success message 
            call    proto_err               ; .. and we are done. 
 
xmsoh20:    and     flgs, not flgrcv        ; shut off receive bit 
            jmp     proto_ok                ; .. no change of state 
 
xmsoh50:    cmp     timer, 0                ; q. timeout? 
            jng     xmsoh55                 ; a. yes .. process it 
 
            jmp     proto_ok                ; else .. continue 
 
xmsoh55:    inc     errors                  ; add one to errors 
 
            cmp     errors, 2               ; q. time to chg NAK char? 
            jb      xmsoh90                 ; a. no .. get out ok 
 
            test    flgs, flgsoh            ; q. first SOH found? 
            jnz     xmsoh60                 ; a. yes .. don't change 
 
            mov     nakch, $NAK             ; reset nak char 
            mov     pktsz, 132              ; .. not CRC 
            or      flgs, flgnrm            ; .. normal XMODEM 
 
xmsoh60:    cmp     errors, MAXERRS         ; q. enough errors? 
            jb      xmsoh90                 ; a. no .. continue ok 
 
xmsoh80:    mov     bl, $CAN                ; bl = CAN 
            mov     di, 20                  ; di = send one character 
            call    callback                ; .. send the cancel 
 
            lea     bx, timedout            ; bx -> timeout message 
            jmp     proto_err               ; .. and kill the protocol 
 
xmsoh90:    call    nak                     ; NAK 'em again 
            mov     timer, SOHTMOUT         ; reset timeout 
            jmp     proto_ok                ; .. and continue 
 
xmsoh       endp 
 
 
; --------------------------------------------------------------------- 
;  Awaiting end of packet 
; --------------------------------------------------------------------- 
 
xmeop       proc 
 
            test    flgs, flgrcv            ; q. character received? 
            jnz     xmeop50                 ; a. yes .. process it 
 
            cmp     timer,0                 ; q. Timeout? 
            jng     xmeop05                 ; a. yes .. process it 
            jmp     proto_ok                ; else .. continue 
 
xmeop05:    inc     errors                  ; add one to errors 
 
            cmp     errors, MAXERRS         ; q. enough errors to die? 
            jb      xmeop10                 ; a. no .. continue 
 
            mov     bl, $CAN                ; bl = CAN 
            mov     di, 20                  ; di = send one character 
            call    callback                ; .. send the cancel 
 
            lea     bx, timedout            ; bx -> timeout message 
            jmp     proto_err               ; .. and kill the protocol 
 
xmeop10:    mov     timer, SOHTMOUT         ; reset tmout 
 
            call    nak                     ; send a nak 
            jmp     proto_ok                ; and continue .. 
 
xmeop50:    call    charcvd                 ; process the char 
            mov     ax, rcvaddr             ; get current rcv address 
            sub     ax, offset packet       ; ax = chars received 
 
            cmp     al, pktsz               ; q. packet received? 
            jb      xmeop58                 ; a. no .. continue recieve 
 
            call    chkpkt                  ; q. packet ok? 
            jnc     xmeop60                 ; a. yes .. write & continue 
 
            inc     errors                  ; .. add an error 
 
            cmp     errors, MAXERRS         ; q. too many errors? 
            jb      xmeop55                 ; a. no .. continue 
 
            mov     bl, $CAN                ; bl = CAN 
            mov     di, 20                  ; di = send one character 
            call    callback                ; .. send the cancel 
 
            lea     bx, toomany             ; bx -> too many error msg 
            jmp     proto_err               ; .. and kill the protocol 
 
xmeop55:    call    nak                     ; nak the packet 
            mov     timer, SOHTMOUT         ; .. start the timer 
xmeop58:    jmp     proto_ok                ; .. and continue 
 
xmeop60:    mov     al, nseq                ; get the next seq nbr 
 
            cmp     al, PKTSEQ              ; q. same sequence? 
            jne     xmeop90                 ; a. no .. skip write 
 
            inc     nseq                    ; nseq = next sequence nbr 
 
            mov     PKTBUFLEN, 128          ; set the buffersize 
            lea     bx, PKTBUFLEN           ; bx -> buffer to write 
            mov     di, 4                   ; di = write to file 
            call    callback                ; q. BD write it ok? 
            jnc     xmeop90                 ; a. yes .. continue 
 
            mov     bl, $CAN                ; bl = CAN 
            mov     di, 20                  ; di = send one character 
            call    callback                ; .. send the cancel 
 
            lea     bx, writerr             ; bx -> write error 
            jmp     proto_err               ; .. and kill the protocol 
 
xmeop90:    call    ack                     ; show it went well 
            mov     timer, SOHTMOUT         ; reset the timer 
xmeop95:    jmp     proto_ok                ; .. and continue 
 
xmeop       endp 
 
 
; --------------------------------------------------------------------- 
;  Process cancel request 
; --------------------------------------------------------------------- 
 
xmcan       proc 
 
            test    flgs, flgrcv            ; q. character received? 
            jz      xmcan90                 ; a. no .. continue 
 
            and     flgs, not flgrcv        ; cancel the character 
 
            cmp     packet, $CAN            ; q. cancel? 
            jne     xmcan50                 ; a. no .. wait 
 
xmcan40:    lea     bx, sendercan           ; bx -> sender cancelled 
            call    proto_err               ; .. cancel the protocol 
 
xmcan50:    call    nak                     ; don't accept packet 
            mov     timer, SOHTMOUT         ; reset timer 
            jmp     proto_ok                ; .. continue 
 
xmcan90:    cmp     timer, 0                ; q. timeout? 
            jng     xmcan40                 ; a. yes .. just die. 
            jmp     proto_ok                ; else .. continue 
 
xmcan       endp 
 
 
; --------------------------------------------------------------------- 
;  Process user cancel request 
; --------------------------------------------------------------------- 
 
xmucan      proc 
 
            test    flgs, flgrcv            ; q. character received? 
            jz      xmucan50                ; a. no .. test for timeout 
 
            mov     timer, CANTMOUT         ; else .. renew timeout 
            and     flgs, not flgrcv        ; .. kill received char 
            mov     rcvaddr, offset packet  ; .. and next char addr 
            jmp     proto_ok                ; .. continue 
 
xmucan50:   cmp     timer, 0                ; q. timeout yet? 
            jng     xmucan60                ; a. yes .. die 
            jmp     proto_ok                ; else .. let it continue 
 
xmucan60:   lea     bx, usercan             ; bx -> user cancelled 
            jmp     proto_err               ; .. and kill the protocol 
 
xmucan      endp 
 
 
; --------------------------------------------------------------------- 
;  Show received character processed 
; --------------------------------------------------------------------- 
 
charcvd     proc 
 
            and     flgs, not flgrcv        ; shut off receive bit 
            inc     rcvaddr                 ; point to next address 
 
            mov     timer, CHRTMOUT         ; set new character timeout 
            ret                             ; return to caller 
 
charcvd     endp 
 
 
; --------------------------------------------------------------------- 
;  Check the received packet                carry = error in packet 
; --------------------------------------------------------------------- 
 
chkpkt      proc 
 
            lea     si, PKTDATA             ; si -> packet data 
            mov     cx, 128                 ; cl =  len of data 
 
            test    flgs, flgnrm            ; q. CRC? 
            jnz     chkpkt05                ; a. no .. do CHKSUM 
 
            call    calc_crc                ; calculate the CRC 
            xchg    dh, dl                  ; .. make it little-endian 
 
            cmp     dx, PKTCRC              ; q. same CRC? 
            jmp     short chkpkt10          ; .. test it later 
 
chkpkt05:   call    calc_cksum              ; calculate the chksum 
 
            cmp     dl, PKTCSUM             ; q. same chksum? 
chkpkt10:   jne     chkpkt90                ; a. no .. kill it now 
 
                                            ; Check the sequence number 
 
            mov     al, PKTSEQ              ; ah = sequence number 
            not     al                      ; al = 1's complement 
 
            cmp     al, PKTCSEQ             ; q. same seq/Cseq? 
            jne     chkpkt90                ; a. no .. bad packet 
 
            mov     al, PKTSEQ              ; al = packet's seq 
            mov     ah, nseq                ; .. and expected seq 
 
            cmp     al, ah                  ; q. sequence ok? 
            je      chkpkt80                ; a. yes .. continue 
 
            dec     ah                      ; ah = previous sequence 
 
            cmp     al, ah                  ; q. previous packet? 
            je      chkpkt80                ; a. yes .. continue .. 
 
            lea     bx, seqerr              ; bx = sequence error 
            jmp     short proto_err         ; .. kill the protocol 
 
chkpkt80:   clc                             ; show it succeeded 
            ret                             ; return to caller 
 
chkpkt90:   stc                             ; show it failed 
            ret                             ; .. return to caller 
 
chkpkt      endp 
 
 
; ---------------------------------------------------------------------- 
;   Calculate chksum        entry: si -> message block 
;                                  cx =  length of message 
;                            exit: dl =  returned checksum 
; ---------------------------------------------------------------------- 
 
calc_cksum  proc 
 
            xor     dl, dl                  ; dl = 0 
 
calc_cks10: lodsb                           ; al = data char 
            add     dl, al                  ; dl = checksum .. so far 
            loop    calc_cks10              ; .. loop 'til done 
 
            ret 
 
calc_cksum  endp 
 
; ---------------------------------------------------------------------- 
;   Calculate CRC           entry: si -> message block 
;                                  cx =  length of message 
;                            exit: dx =  returned CRC 
; ---------------------------------------------------------------------- 
 
calc_crc    proc 
 
            xor     dx, dx                  ; dx = initialize crc 
            mov     bx, 1021h               ; bx = working constant 
            mov     di, 8000h               ; di = constant, too 
 
calc_c10:   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 
 
calc_c20:   mov     ax, dx                  ; ax = temp copy of crc 
 
            and     ax, di                  ; q. bit on? 
            jz      calc_c30                ; a. no .. continue 
 
            shl     dx, 1                   ; shift left by one bit 
            xor     dx, bx                  ; crc = crc << 1 ^ 0x1021 
            jmp     short calc_c40          ; ..continue with common code 
 
calc_c30:   shl     dx, 1                   ; crc <<= 1 
 
calc_c40:   loop    calc_c20                ; ..just loop thru this byte 
 
            pop     cx                      ; restore register 
            loop    calc_c10                ; ..and loop thru whole message 
 
            ret 
calc_crc    endp 
 
 
; --------------------------------------------------------------------- 
;  Send a NAK 
; --------------------------------------------------------------------- 
 
nak         proc 
 
            mov     bl, nakch               ; bl = current NAK char 
            mov     di, 20                  ; di = send one char 
            call    callback                ; .. ask BD to do it 
 
            mov     state, $ST_SOH          ; Awaiting new pkt 
            mov     rcvaddr, offset packet  ; .. reset address 
 
            ret                             ; .. return to caller 
 
nak         endp 
 
 
; --------------------------------------------------------------------- 
;  Send an ACK 
; --------------------------------------------------------------------- 
 
ack         proc 
 
            mov     bl, $ACK                ; bl = ACK char 
            mov     di, 20                  ; di = send one char 
            call    callback                ; .. ask BD to do it 
 
            mov     bl, '.'                 ; show we're processing 
            mov     di, 14                  ; di = display one char 
            call    callback                ; .. ask BD to do it 
 
            mov     state, $ST_SOH          ; Awaiting new pkt 
            mov     rcvaddr, offset packet  ; .. reset address 
            mov     errors, 0               ; .. and reset error cnt 
 
            ret                             ; .. return to caller 
 
ack         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 
 
            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