;
;
;  MORSCOM1.ASM
;
;
;  Written by:      Bob Gallagher, Jr.
;  Last Revised:    15:37:39  1/4/1988
;
;

DSEG    SEGMENT PUBLIC 'DSEG'

;------------------------------------------------------------------
;-------------------- EQUATES BELOW -------------------------------
;------------------------------------------------------------------


EOL     EQU     0
EOM     EQU     255
CR      EQU     13
LF      EQU     10
DOS     EQU     21h
VIDEO   EQU     10h


; ---------------------------------------------------------------------
;----------------------- DATA BELOW -----------------------------------
;----------------------------------------------------------------------

MESG  db CR,LF,LF,"Morse Code from COM1",CR,LF
      db "Written by:   Bob Gallagher, Jr.",CR,LF
      db "  (Press ESC to quit)",LF,LF,'$'


BAUDMSB  DW  3F9H
BAUDLSB  DW  3F8H
MODSTS   DW  3FEH
MODCTL   DW  3FCH
LINCTL   DW  3FBH
LINSTS   DW  3FDH
DATAPORT DW  3F8H
INTENBL  DW  3F9H
INTID    DW  3FAH
IRQMASK  DB  11101111B
VECTOR   DB  0CH

TONESTATE DB 0        ; used by CHKPORT to see which way to flip




;------------------------------------------------------------------
DSEG    ENDS
CSEG SEGMENT PARA PUBLIC 'CODE'
        ASSUME CS:CSEG,DS:DSEG,SS:DSEG,ES:NOTHING
SHELL PROC NEAR
S_BEGIN:
        PUSH    ES
        CALL    RUN_MODULE
S_EXIT  PROC FAR
        XOR     AX,AX           ; zero register
        PUSH    AX              ; Put 0 return addr on stack
        RET
S_EXIT ENDP
RUN_MODULE:
        MOV     AX,DSEG
        MOV     DS,AX
        MOV     ES,AX
;---------------------------------------------------------------------
;--------------------- CODE  BELOW -----------------------------------
;----------------------------------------------------------------------

        call    CLS

        mov     DX,offset MESG
        call    PRINT_STR


;----------- init port, raise DTR  -------------
        mov     CX,60h
        mov     BL,03H
        call    INIT_PORT


;----------- check for escape ------------
CHKESC:
        call    CHECK_KEY
        jnz     CE01
        jmp     CHKPORT
CE01:
        call    GET_KEY
        cmp     AL,27
        jne     CHKPORT

        call    TONE_OFF  ; end program if ESC
        ret

;---------- check port ---------------
CHKPORT:
        mov     DX,MODSTS          ; check for carrier detect (CD)
        in      AL,DX
        and     AL,10000000b
        cmp     AL,0
        je      CP01

        cmp     TONESTATE,0        ; yes, CD active, check current state
        je      CP03
        jmp     CHKESC
CP03:   call    TONE_ON
        jmp     CHKESC

CP01:   cmp     TONESTATE,0        ; no CD, check current state
        jne     CP02
        jmp     CHKESC
CP02:   call    TONE_OFF
        jmp     CHKESC


;----------------------------------------------------------------------
;-------------------- SUBROUTINES  BELOW ------------------------------
;----------------------------------------------------------------------

TONE_ON PROC NEAR
        mov     TONESTATE,1

        MOV     AL,0B6H         ; Timer mode register signal
        OUT     67,AL

        MOV     AX,2711         ; Divisor for 440  (note A)
        OUT     66,AL
        MOV     AL,AH
        OUT     66,AL

        IN      AL,97           ; Activate speaker
        OR      AL,03
        OUT     97,AL
        ret
TONE_ON ENDP


TONE_OFF PROC NEAR
        mov     TONESTATE,0

        MOV     AL,0B6H         ; Now turn it off
        OUT     67,AL

        MOV     AX,2711
        OUT     66,AL
        MOV     AL,AH
        OUT     66,AL

        IN      AL,97
        AND     AL,11111100B
        OUT     97,AL
        ret
TONE_OFF ENDP



;----------------------------------------
CHECK_KEY PROC NEAR
;
;       Entry:  none
;
;       Returns:        AX = 0  - no key
;                            1  - yes, key now ready
;
;       Also:    Zero flag set...use JZ test for no key.
;-----------------------------------------
        MOV     AH,1
        INT     16H
        JZ      CK10

        MOV     AX,1
        RET

CK10:   MOV     AX,0
        RET
CHECK_KEY ENDP


;------------------------------------------------------------------
CLS PROC NEAR                            ; Clear Screen   (IBM Bios)
;
; Entries: None		; NEW routine, clears the current screen
; Returns: None		; regardless of the page
; Corrupts: None
;--------------------------------------------------------------------
        PUSH    AX
        PUSH    BX                       ; Preserve Registers
        PUSH    CX
        PUSH    DX
                                    ; clear the current screen
        SUB     CX,CX                    ; BH = Atribute (7)
        MOV     BH,7                     ; CX = Upper Left
        MOV     DX,184FH                 ; DX = Lower Right
        MOV     AX,600H                  ; AH = Service #  6=scroll
        INT     10H                      ; AL = # of lines (0=whole screen)

        MOV     AH,15       ; get cuurent page # into BH, read video status
        INT     10h

        XOR     DX,DX                   ; Locate Cursor to 0,0
        MOV     AH,2                    ; AH=Service #   2=move cursor
        INT     10H                     ; BH = page #

        POP     DX                      ; Restore Registers
        POP     CX
        POP     BX
        POP     AX
        RET
CLS ENDP


;-----------------------------------------------
GET_KEY PROC NEAR       ; (use CHECK_KEY first)
;
;       Entry:  none
;
;       Returns:        AL - ASCII result
;                       AH - scan code
;
;-----------------------------------------------
        MOV     AH,0
        INT     16H
        RET
GET_KEY ENDP





;------------------------------------------------------------
INIT_PORT PROC NEAR              ; (IBM XT)
;
; Set baud rate, parity and word length.
; Also puts up DTR & RTS
;
; Entries:
;          CX- Baud Rate:      300   180H
;                             1200    60H
;                             2400    30H
;                             4800    18H
;                             9600    0CH
;                            19200     6H
;
;    BL- Parity & Word Length: 8,N  03H
;                              7,E  1AH
;
; Returns:   NONE
;
; Corrupts:  AX
;
;-----------------------------------------------------------------

  MOV   AL,00000011b       ; Put up DTR & RTS
  MOV   DX,MODCTL
  OUT   DX,AL

  MOV   AL,80H             ; Set Divisor Latch
  MOV   DX,LINCTL
  OUT   DX,AL

  MOV   AL,CH              ; Set Baud Rate
  MOV   DX,BAUDMSB
  OUT   DX,AL
  MOV   AL,CL
  MOV   DX,BAUDLSB
  OUT   DX,AL

  MOV   AL,BL              ; Set Parity & Word Length
  MOV   DX,LINCTL
  OUT   DX,AL

  RET
INIT_PORT ENDP



;---------------------------------------------------------------------
PRINT_STR PROC NEAR     ; Print a string in the data area to the screen.
;
; Entries:   Data offset in DX before call.
; Returns:   None
; Corrupts:  AX DX
;
; The data string must end in '$' as an end of line mark.
;----------------------------------------------------------------------
                MOV     AX,0
                MOV     AH,9H           ; Print a string in the data area
                INT     21H             ; string must end in '$'
                RET                     ; Data offset in DX before call.
PRINT_STR ENDP


;--------------------------------------------------------
SHORT_BEEP PROC NEAR     ; Makes a shorter beep.
;
;       Entries :  None
;       Returns :  None
;       Corrupts:  AX
;
;
;--------------------------------------------------------
        MOV     AL,0B6H         ; Timer mode register signal
        OUT     67,AL

        MOV     AX,2711         ; Divisor for 440  (note A)
        OUT     66,AL
        MOV     AL,AH
        OUT     66,AL

        IN      AL,97           ; Activate speaker
        OR      AL,03
        OUT     97,AL

                MOV     AH,1    ;  .2 second delay
                SHL     AH,1
                SHL     AH,1
                MOV     AL,0
SD1:            MOV     CX,9000
SD2:            LOOP    SD2
                INC     AL
                CMP     AL,AH           ; Change for length of delay
                JNE     SD1

        MOV     AL,0B6H         ; Now turn it off
        OUT     67,AL

        MOV     AX,2711
        OUT     66,AL
        MOV     AL,AH
        OUT     66,AL

        IN      AL,97
        AND     AL,11111100B
        OUT     97,AL
        RET
SHORT_BEEP ENDP

;----------------------------------------------------------------------
SHELL ENDP
CSEG ENDS
     END
