; ----------------------------------------------------------------------------
;
; tx_hex tx_nib tx_bcd tx_chr -- Transmit byte in W via RS232.
;
;   - Writes to GPIO,tx_pin using RS232 8N1 at CMOS/TTL levels.
;   - Polarity determined by GPIO,ttl_pin (0=rs232, 1=ttl).
;   - Note 19200 baud is 52.083 us per bit = 0.521 ms per byte.
;   - At 10 MHz, 130 instructions = 52.0 us = 19230.77 baud.
;   - Bit symmetric isochronous code.
;   - RS232 signal level terminology:
;
;   break | space | +12V | 5V true | 0V inverted TTL | start bit | data 0
;   idle  | mark  | -12V | 0V true | 5V inverted TTL | stop bit  | data 1
;
TX_Tcy      equ     d'130'      ; nominal bit width (Tcy units)

        ; tx_hex -- Send 8-bit byte as 2-character hex.

tx_hex: movwf   tx_swap         ;
        swapf   tx_swap,W       ; get upper nibble
        call    tx_nib          ;
        movf    tx_swap,W       ; get lower nibble
                                ; (fall into)

        ; tx_nib -- Send 4-bit nibble as 1-character hex.

tx_nib: andlw   0x0F            ; isolate nibble
        addlw   -0xA            ;
        skpnc                   ; if nibble >= 10
          addlw 'A'-0xA-'0'     ;   convert 10...15 into A...F
        addlw   0xA             ; undo
                                ; (fall into)

        ; tx_bcd -- Send one BCD digit.

tx_bcd: addlw   '0'             ; convert to ascii digit
                                ; (fall into)

        ; tx_chr -- Send single character.

tx_chr: movwf   tx_hold         ;
        bcf     STATUS,C        ; make start bit (data 0)
        call    _tx_out         ;
        movlw   TX_Tcy - d'14'  ; delay after start bit
        call    DelayW1         ;
        movlw   8               ; data bit count (8N1)
        movwf   tx_bits         ;

_tx1    rrf     tx_hold,F       ; shift next LSB into carry flag
        call    _tx_out         ;
        movlw   TX_Tcy - d'15'  ; delay after data bit
        call    DelayW1         ;
        decfsz  tx_bits,F       ; done?
          goto  _tx1            ;   no, do next bit

        nop                     ; (timing)
        bsf     STATUS,C        ; make stop bit (data 1)
        call    _tx_out         ;
        movlw   TX_Tcy - d'16'  ; delay after stop bit
        goto    DelayW1         ; (goto/return)

        ; tx_idle -- Set pin to RS232 idle state.

tx_idle:
        bsf     STATUS,C        ; set idle state (stop bit = data 1)
                                ; (fall into)

        ; Set GPIO output (data bit is in carry flag).

_tx_out movlw   0               ; assume transmit pin low
        skpc                    ; if carry flag is 0, then
          xorlw 1<<tx_pin       ;   invert
        btfsc   GPIO,ttl_pin    ; if polarity is 1, then
          xorlw 1<<tx_pin       ;   invert
        movwf   GPIO            ; set output pin(s)
        return                  ;

        cblock
            tx_swap, tx_hold, tx_bits
        endc
