;**************************************************
;* send_cmd
;* Sends a single command to the backend..no termination
;* Command in W
;**************************************************
send_cmd
	call	TX_ADD_BUFFER
	return

;**************************************************
;* send_badcmd
;* Send bad command command
;**************************************************
send_badcmd
	call	error_beep
	movlw	PIC_CMD_BADCMD
	call	TX_ADD_BUFFER
	return

;**************************************************
;* send_ok
;* Send successfull command command
;**************************************************
send_ok
	movlw	PIC_CMD_OK
	call	send_cmd
	return

;**************************************************
;* send_term
;* terminate the output string with ESC and END
;**************************************************
send_term
	movlw	CMD_ESC
	call	TX_ADD_BUFFER
	movlw	CMD_END
	call	TX_ADD_BUFFER
	return


;************************************************************************************
;+++++
;       INC_BUFFER advance buffer pointers wrap if necessary 
;
;       If buffer size is power of two, and buffer is aligned
;       on an multiple of twice it size, this macro generates
;       two instructions, Otherwise it generates six instructions.
;       Originator:  Eric Smith, eric@brouhaha.com for non-comercial use.

INC_BUFFER MACRO        Pointer, Base, Size     
        LOCAL   POWER_OF2, ALIGNED,BIT,VALUE

POWER_OF2       SET     !(Size&(Size-1))        ; calculate if power of 2
ALIGNED         SET     POWER_OF2&&((Base&(Size-1))==0) ; calculate if aligned

        IF      ALIGNED

VALUE   SET     Size
BIT     SET     0

        WHILE   VALUE>1
BIT     SET     BIT+1
VALUE   SET     VALUE>>1
        ENDW

        ENDIF

        INCF    Pointer,F       ; increase pointer

        IF      ALIGNED&&!(Base&(1<<BIT)) ; aligned ?
        BCF     Pointer,BIT     ; yep clear bit
        ELSE
        MOVF    Pointer,W       ; nope
        XORLW   Base+Size
        MOVLW   Base
        BTFSC   STATUS,Z
        MOVWF   Pointer
        ENDIF

        ENDM

INIT_BUFFERS

        ; setup receive buffer
        CLRF    RX_Buffer_Count ; clear counter
        MOVLW   RX_Buffer       ; get base adress for buffer
        MOVWF   RX_Buffer_InPtr ; save as in adress
        MOVWF   RX_Buffer_OutPtr; and out adress
        ; setup transmit buffer
        CLRF    TX_Buffer_Count ; clear counter
        MOVLW   TX_Buffer       ; get base adress for buffer
        MOVWF   TX_Buffer_InPtr ; save as in adress
        MOVWF   TX_Buffer_OutPtr; and out adress


        RETURN

; ***********************************************************************
;
;  RX_INT_HANDLER - handles the received commands on serial com 
;  called from inside int.
;

RX_INT_HANDLER
         BTFSS   RCSTA,OERR      ; test for overrun error
         GOTO    RX_CHECK_FRAMING
        ; when overrun, uart will stop receving the continous 
        ; recevive bit must then be reset
        BCF     RCSTA,CREN      ; clear continous receve bit
        BSF     RCSTA,CREN      ; and set it again
RX_CHECK_FRAMING
        BTFSS   RCSTA,FERR      ; check from framing errors
        GOTO    RX_CHECK_BUFFER 
        ; framing error do not store this byte
        ; read rx reg and discard byte
        GOTO    RX_DISCARD_BYTE 

RX_CHECK_BUFFER 
	bcf	LED_RX
;	call	write_leds

        MOVF    RX_Buffer_Count,W       ; test if empty
        XORLW   RX_BUFFER_SIZE
        BTFSC   STATUS,Z
        GOTO    RX_BUFFER_FULL

        MOVF    RX_Buffer_InPtr,W       ; get adress for indirect dressing
        MOVWF   FSR             ; setup fsr
        MOVF    RCREG,W         ; get received byte
        MOVWF   INDF            ; and store it in buffer
        INCF    RX_Buffer_Count,F ; inc buffer counter
        ; update pointers
        INC_BUFFER      RX_Buffer_InPtr,RX_Buffer,RX_BUFFER_SIZE

	bsf	LED_RX
	RETURN

RX_BUFFER_FULL
        ; no rom for more bytes, set overrun flag
        BSF     _BufferOverrun
        ; and clear the last byte ( no room to store it ! )

RX_DISCARD_BYTE
        ; optional an error flag could be set to indicate comm error.
        MOVF    RCREG,W         ; read byte and discard
        RETURN

; ***********************************************************************
;
;  TX_INT_HANDLER - handles the tramission of bytes on serial com 
;  called from inside int.
;

TX_INT_HANDLER
        MOVF    TX_Buffer_Count,W	; get number of bytes
        BTFSC   STATUS,Z		; buffer empty ?
        GOTO    TX_BUFFER_EMPTY

	bcf	LED_TX
;	call	write_leds

        MOVF    TX_Buffer_OutPtr,W	; get adress for indirect adressing
        MOVWF   FSR             	; setup fsr
        MOVF    INDF,W          	; get byte
        MOVWF   TXREG           	; and put it in tx reg
        DECF    TX_Buffer_Count,F	; decrement buffer counter
        
        ; update pointers
        INC_BUFFER      TX_Buffer_OutPtr,TX_Buffer,TX_BUFFER_SIZE
        
	bsf	LED_TX
        RETURN
TX_BUFFER_EMPTY
        ; no more bytes to send disable TX irq
        ; code is to avoid bank switching ( using FSR )
        MOVLW   PIE1    ; get adress for tx irq enable
        MOVWF   FSR     ; setup fsr
        BCF     INDF,TXIE ; and disable tx irq
	bsf	LED_TX
        RETURN

; ***********************************************************************
;
;  TX_ADD_BUFFER - Puts one byte in serial tx buffer,  blocks until room available
;  Make sure to be at bank0 ( buffer pointers in bank0, buffers in bank1 )
;

TX_ADD_BUFFER
	Bank0
        MOVWF   TX_Temp ; store byte temporarily
TX_ADD_TST      
        MOVF    TX_Buffer_Count,W ; get count
        XORLW   TX_BUFFER_SIZE  
        BTFSC   STATUS,Z        ; test if any room
        GOTO    TX_ADD_TST      ; nope no room, wait until there is
        
        MOVF    TX_Buffer_InPtr,W       ; get adress to store byte
        MOVWF   FSR             ; setup fsr
        MOVF    TX_Temp,W       ; get byte
        MOVWF   INDF            ; and store it

        ; update buffer pointers
        INC_BUFFER      TX_Buffer_InPtr,TX_Buffer,TX_BUFFER_SIZE

        INCF    TX_Buffer_Count,F ; increment byte count
                                ; MUST not be done until after byte is stored in buffer
                                ; and pointers updated
        
        MOVLW   PIE1    ; get adress for periphial irq
        MOVWF   FSR     ; setup fsr
        BSF     INDF,TXIE; and enable tx irq

        RETURN

; ***********************************************************************
;
;  RX_GET_BUFFER - Gets one byte from in serial rx buffer, if available
;  If no bytes in buffer zero flag is set else zero flag is cleared     
;  Make sure to be at bank0 ( buffer pointers in bank0, buffers in bank1 )
;  Byte will be in W and rx_data

; Same as above, but waits for a byte.
RX_GET_BUFFER_WAIT
	bcf	Led_Data, 2

	call	RX_GET_BUFFER
	btfss	SYS_OPTS, SOPT_BUFREDY
	goto	RX_GET_BUFFER_WAIT

	bsf	Led_Data, 2
	return

RX_GET_BUFFER
	Bank0
	BCF	SYS_OPTS, SOPT_BUFREDY

        MOVF    RX_Buffer_Count,F	; check if anything available ?
        BTFSC   STATUS,Z		;
        RETURN 				; nope, nothing there, NOTE zero flag set !
        
        ; get pointer
        MOVF    RX_Buffer_OutPtr,W
        MOVWF   FSR     ; setup FSR
	DISABLE_IRQ
        
        ; update buffer pointers
        INC_BUFFER      RX_Buffer_OutPtr,RX_Buffer,RX_BUFFER_SIZE

        ; get byte to W
        MOVF    INDF,W
        MOVWF	rx_data
        ; decrement counter
        DECF    RX_Buffer_Count,F 
	ENABLE_IRQ

        BCF     STATUS,Z        ; make sure zero flag is clear
	BSF	SYS_OPTS, SOPT_BUFREDY
        RETURN



;*********************************************************************************************************************
;*********************************************************************************************************************


