;; wwwpic2 is a tcp/ip stack and www server in a PIC 16F84
;;
;; This program is free software;  you can redistribute it and/or
;; modify it under the terms of the GNU General Public License
;; as published by the Free Software Foundation;  either version 2
;; of the License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY;  without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program;  if not, write to the Free Software
;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

;; To contact V Sanders email
;; vince@kyllikki.fluff.org

;; The main web site for this program is
;; http://www.kyllikki.fluff.org/hardware/wwwpic2/
;;
;; This program is based upon wwwpic by Denis Petrov <zhengxi@operamail.com>
;; From and original idea by Shrikumar H. <shri@cs.umass.edu>
;;
;; See the website and acompanying README for more details

;; Version 0.20

;
	Title		"WWWPic 2"

	Processor	16F84 ; PIC device type 16F84 or 16F84A

;
; include PIC register definitions and define config fuses
; depends upon processor selected
;
	IFDEF	__16F84
		__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_OFF & _HS_OSC
		INCLUDE	<p16f84.inc>
	ENDIF

	IFDEF	__16F84A
		__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_OFF & _HS_OSC
		INCLUDE	<p16f84a.inc>
	ENDIF

; set radix to decimal
	Radix	DEC
        EXPAND

; settings and extra macros
 	include	"wwwpic2.inc"

;; Two vector locations
_ResetVector	set	0x00
_IntVector	set	0x04

;;========================================================================
;; DATA RAM mapping
;;========================================================================
	CBLOCK 0x0c

		RX_BYTE			; [soft uart]
		TX_BYTE			; [soft uart]

		TCPR_RPORT_H		; remote TCP port
		TCPR_RPORT_L		;
		TCPR_LPORT_H		; local TCP port, TCPR_LPORT_H==0
		TCPR_LPORT_L		;
		TCPR_SEQ_L3		;
		TCPR_SEQ_L2		;
		TCPR_SEQ_L1		;
		TCPR_SEQ_L0		;
		TCPR_ACK_L3		;
		TCPR_ACK_L2		;
		TCPR_ACK_L1		;
		TCPR_ACK_L0		;
		TCPR_HLEN		;
		TCPR_FLAG		;

		TEMP_0			;
		TEMP_1			;
		TEMP_2			;

		HTTP_UNITIDX		;
		HTTP_FILESIZE_H		;
		HTTP_FILESIZE_L		;
		HTTP_NAME_0		;
		HTTP_NAME_1		;
		HTTP_NAME_2		;

					; socket data, it's valid if tcp_online==1
		TCPR_POS		; iterator 0 -->] 80..FF

		TCPS_ACK		;
		TCPS_SEQ		;
		TCPS_LEN		; for retransmit
		TCPS_FLAG		; for retransmit

		IP_POS			; iterator
		IP_HLEN			; IP header len (incoming only)
		IP_LEN			; IP packet len
		IP_SUM_0		; TCP/IP chksum
		IP_SUM_1		; --//-----//-- low octet
		IP_ADR_0		; remote IP address
		IP_ADR_1		; --//--
		IP_ADR_2		; --//--
		IP_ADR_3		; --//--

	ENDC

;;========================================================================
;; Reset Vector
;;========================================================================
	ORG	_ResetVector
;	;	;			;
        clrf	INTCON			; Disables all interups clears GIE
;	;	;			;   and all pending interupts
	movlw	B'01001111'             ; Sets options
        movwf	OPTION_REG		;   PORTB pulups on
;	;	;			;   Rising edge trigger on RB0
;	;	;			;   TMR0 clock source internal
;	;	;			;   TMR0 low to high edge
;	;	;			;   prescaler asigned to WDT
;	;	;			;   prescaler set to 1:	128
        goto	_init			; Goto start routine
;	;	;			;


;;========================================================================
;; Interrupt Code
;;========================================================================
	ORG	_IntVector
; Called from main interupt vector as RBO edge is only active interupt source
;   it came from there!
; Soft UART - simplex :(
; Recive a byte at the pre-set baud rate
; 'RS_DATA'(8) Data No Parity X stop
_rx_byte:				; (5) Well 3-4 (interupt latency)
        call	_delay4			; (4) Delays 4 cycles total
        movlw	RS_DATA			; (1) 8 data No parity x stop
_rx_bit:
        bcf	PORTA,B_RS232_CTS	; (1) Drop CTS to stop any more bytes
;	;	;			;       being sent while dealing with
;	;	;			;       this one
        call	_delay_x_9		; (2) RS_TICKS-9
        bcf	STATUS,C		; (1) Clear carry bit
        btfss	PORTB,B_RS232_RxD       ; (1) Set carry if rxd pin reads 0
        bsf	STATUS,C                ; (1)
        rrf	RX_BYTE,F               ; (1) Rotate recived byte which shifts
;	;	;			;       in the carry bit
        addlw	-1                      ; (1) Subtract one from the bit count
        bnz	_rx_bit                 ; (3) Round for next bit
;	;	;			;
; RX SLIP code
	;; RX_BYTE register contains recived byte
        movf	RX_BYTE,W               ; get recived byte into w
        xorlw	0C0h                    ;
        bnz	_not_slip_end_char      ; check for SLIP END char
; recived SLIP END
        bcf	IP_HLEN,B_SLIP_OUTPKT   ; clear discard data flag
        clrf	IP_POS                  ; clear IP_POS
        clrf	IP_SUM_0                ; clear ip checksup low byte
        clrf	IP_SUM_1                ; clear ip checksup high byte
        goto	_rx                     ; return to busy loop
;	;	;			;
_not_slip_end_char:
        brclr	IP_HLEN,B_SLIP_OUTPKT,_mode_slip ; is discard data flg set
;	;	;			;
_mode_terminal:
; terminal mode - discarding data any 0xD char codes reply with ok
        xorlw	(00Dh ^ 0C0h)           ; Check for a 0xD char
        bnz	_rx                     ; Not a 0xD return to busy loop
        TXLW	'O'                     ; This is for slip
        TXLW	'K'                     ;   server sw that trys to issue
        TXLW	0Dh                     ;   AT commands at startup
        goto	_rx                     ; return to busy loop
;	;	;			;
_mode_slip:
; slip mode - not discarding data
        brclr	IP_HLEN,B_SLIP_ESCAPE,_no_slip_escape; check escape flag
; previous char was slip escape char
; PROTOCOL BUG - assumes its 0xDC or 0xDD - should pass thru if neither
;   see RFC 1055
	xorlw	(0DCh ^ 0C0h)           ; check for 0xDC
        movlw	0DBh                    ; Escaping in SLIP:
        skpnz                           ; 0xDB,0xDC --> 0xC0
        movlw	0C0h                    ; 0xDB,0xDD --> 0xDB
        movwf	RX_BYTE                 ; RX_BYTE=(RX_BYTE==0xDC?0xC0:0xDB)
;       goto	_end_slip_escape        ; ok ,w either 0xdc or 0xdd so
;	;	;		        ;   later xor fails
;	;	;			;
_no_slip_escape:
; previous char was not an escape character - check this one
        bsf	IP_HLEN,B_SLIP_ESCAPE   ; set escape flag to true
        xorlw	(0DBh ^ 0C0h)           ; check for SLIP_escape
        bz	_rx                     ; ret to busy loop with esc flg set
;	;	;			;
_end_slip_escape:
        bcf	IP_HLEN,B_SLIP_ESCAPE   ; clear escape flag
;	;	;			;
;	;	;			;
; byte recived and slip de-escaped and framed
        movf	RX_BYTE,W	        ; retrieve our original byte
        call	_checksum_byte          ; calculates the ip checksum
	                                ;   as we go
;	;	;			;
        movf	IP_POS,W                ;(rus)
        addlw	-20                     ;(rus) SLIP.END (rus com)
        bc	_xxxx                   ; IP (rus com)
        rlf	IP_POS,W                ;
        clrf	PCLATH                  ; (rus)
        addwf	PCL,F                   ;
;	;	;			;
        movf	RX_BYTE,W               ; IPhdr+ 0 Version & IHL
        movwf	IP_HLEN                 ;
        rlf	IP_HLEN,F               ; IPhdr+ 1 Type of Service
        goto	_01_                    ;
        movlw	0			; IPhdr+ 2 Total Length (hi)
        goto	_rx_byte_must_equal_w   ;
        movf	RX_BYTE,W               ; IPhdr+ 3 Total Length (lo)
        movwf	IP_LEN                  ;
        goto	_finish                 ; IPhdr+ 4 Identification (hi)
;	;	;			;
_01_:
	bcf	IP_HLEN,7               ;
        goto	_finish                 ; IPhdr+ 5 Identification (lo)
        nop				;
        goto	_finish                 ; IPhdr+ 6 Flags & Fragment Offset (hi)
        nop				;
        movlw	0                       ; IPhdr+ 7 Fragment Offset (lo)
        goto	_rx_byte_must_equal_w   ;
        goto	_finish                 ; IPhdr+ 8 Time to Live
        nop                             ;
        movlw	6                       ; IPhdr+ 9 Protocol
        goto	_rx_byte_must_equal_w   ;
        goto	_finish                 ; IPhdr+10 Header Checksum (hi)
        nop                             ;
        goto	_finish                 ; IPhdr+11 Header Checksum (lo)
        nop                             ;
        movlw	IP_ADR_0                ; IPhdr+12 Source Address
        goto	_save_rx_byte           ;
        movlw	IP_ADR_1                ; IPhdr+13
        goto	_save_rx_byte           ;
        movlw	IP_ADR_2                ; IPhdr+14
        goto	_save_rx_byte           ;
        movlw	IP_ADR_3                ; IPhdr+15
        goto	_save_rx_byte           ;
        movlw	ADDR_MYSELF_0           ; IPhdr+16 Destination Address
        goto	_rx_byte_must_equal_w   ;
        movlw	ADDR_MYSELF_1           ; IPhdr+17
        goto	_rx_byte_must_equal_w   ;
        movlw	ADDR_MYSELF_2           ; IPhdr+18
        goto	_rx_byte_must_equal_w   ;
        movlw	ADDR_MYSELF_3           ; IPhdr+19
_rx_byte_must_equal_w:
        xorwf	RX_BYTE,W               ;
        bnz	_error                  ; recived byte wasnt correct
;	;	;			;   discard the rest of the packet
;	;	;			;
_xxxx:
        movf	IP_HLEN,W               ; IP_POS-IP_HLEN - (rus)
        subwf	IP_POS,W                ; (rus) IP (rus)
        bc	_post_ip                ; ... (rus)?
;	;	;			;
_no_post_ip:
        xorlw	0FFh                    ; (rus) IP (rus)
        bnz	_finish                 ; IP_SUM (rus)
        movf	IP_SUM_0,W              ;
        iorwf	IP_SUM_1,W              ;
        bnz	_error                  ; (rus)
;	;	;			;
_finish:
        incf	IP_POS,F                ; (rus)
        goto	_rx                     ;
;	;	;			;
_post_ip:
        addlw	-14                     ; (rus) TCP (rus)
        bnc	_save_as_tcp_header     ;
        bnz	_no_correct_tcp_hlen    ;
        rrf	TCPR_HLEN,F             ; if(IP_POS-IP_HLEN==14)
        rrf	TCPR_HLEN,F             ; {
        bcf	TCPR_HLEN,7             ;    TCPR_HLEN=(TCPR_HLEN<<2)&0x3F;
        bcf	TCPR_HLEN,6             ; }
;	;	;			;
_no_correct_tcp_hlen:
        subwf	TCPR_HLEN,W             ; (rus) TCP (rus)
        addlw	-15                     ; (rus) (W<14) - (rus)
        bc	_no_save_rx_byte        ; (rus)
                                        ;  GET /xxx (rus) ­ (rus) telnet-(rus)
                                        ; (rus)
                                        ; (rus) www-browser.
        subwf	TCPR_POS,W              ; (rus) "GET /.."
        addlw	(-1-(5+3))              ; W=TCPR_POS-(TCPR_HLEN-(IP_POS-IP_HLEN-14))
        addlw	3                       ; (5.7)->(FD.FF) (5.7)->(0.2)
        bnc	_no_save_rx_byte        ;
	if ((HTTP_NAME_0 - (TCPR_RPORT_H + 14)) != 0); {
	addlw	(HTTP_NAME_0 - (TCPR_RPORT_H + 14))
	endif				; }
;	;	;			;
_save_as_tcp_header:
        addlw	TCPR_RPORT_H+14		;
;	;	;			;
_save_rx_byte:
        movwf	FSR                     ; [W]:=RX_BYTE - (rus)
        movf	RX_BYTE,W               ;
        movwf	INDF                    ;
;	;	;			;
_no_save_rx_byte:
        incf	IP_POS,W                ; (rus)
        subwf	IP_LEN,W                ; IP ¯ (rus) ...
        bnz	_finish                 ;
;	;	;			;
        movf	IP_HLEN,W               ; IP_LEN-=IP_HLEN;
        subwf	IP_LEN,F                ;
        call	_chksum_pseudoheader    ; (rus)
        movf	IP_SUM_0,W              ; TCP (rus)
        iorwf	IP_SUM_1,W              ;
        skpnz                           ;
        call	_process_tcp            ;
        goto	_error                  ;
;	;	;			;


;===========================================================================
; TX routines
;===========================================================================
;_txhex: movwf	FSR
;        swapf	FSR,W
;        call	_txhex0
;        movf	FSR,W
;_txhex0:andlw	00001111b
;        addlw	-10
;        skipnc
;        addlw	7
;        addlw	58
;        goto	_tx
;------------------------------------------------
_slitx_csum:
        movf	IP_SUM_0,W              ; (rus)
        call	_slitx                  ; (rus)
        movf	IP_SUM_1,W              ;
        goto	_slitx
;;------------------------------------------------
;	;	;			;
_slitx4:
        movwf	FSR                     ; (rus)  (W[0]..W[3])
        call	_slitx2                 ; (rus)
;	;	;			;
_slitx2:
        movf	INDF,W                  ; (rus)  (FSR[0]..FSR[1])
        call	_checksum_hi
        call	_slitx1
        movf	INDF,W
        call	_checksum_lo
;	;	;			;
_slitx1:
        movf	INDF,W                  ; (rus) (*FSR++)
        incf	FSR,F                   ;
        goto	_slitx
;;------------------------------------------------
;	;	;			;
_tx_0_0:
        call	_tx_0                   ; (rus)
;	;	;			;
_tx_0:
        movlw	000h                    ; (rus)
;	;	;			;
_slitx:
        xorlw	0C0h                    ; (rus) SLIP
        bnz	_ne_C0                  ; (rus)
        TXLW	0DBh                    ;   0xC0 --> 0xDB,0xDC
        movlw	0DCh                    ;   0xDB --> 0xDB,0xDD
        goto	_tx                     ;
;	;	;			;
_ne_C0:
        xorlw	(0DBh ^ 0C0h)           ; <0DBh xor 0C0h>
        bnz	_tx11                   ;
        call	_tx11                   ;
        movlw	(0DDh ^ 0DBh)           ; <0DDh xor 0DBh>
;	;	;			;
_tx11:                                      ;
        xorlw	0DBh                    ;
;	;	;			;
_tx:
        bsf	PORTA,B_RS232_TxD       ; rus com
        movwf	TX_BYTE                 ; IN:  W
        movlw	((-(RS_DATA+1))<< 4) & 0xff ; <(-(RS_DATA+1))shl 4> ; OUT: TX_BYTE:=W
;	;	;			;
_tx_loop_c:
        bsf	STATUS,C                ; 1
;	;	;			;
_tx_loop:
        call	_delay_x_9
        rrf	TX_BYTE,F               ; 1 ; 1
        bnc	_c_is_clear             ; 2 ; 3
        addlw	10h                     ; 1
        bcf	PORTA,B_RS232_TxD       ; 1
        bnz	_tx_loop_c              ; 3
;	;	;			; Warning - falls thru to _delay_x_9
;	;	;			;   which returns also.
;	;	;			; saves a call and return

;; Delays for RS_TICKS less a fixed value (9 is the current value)
;; currently depends on 6Mhz clock! - possible bug in that it delays for
;; 70 cycles (total 79) where RS_TICKS is 78 (see next bit for reason)
;; For 10Mhz operation	:
;; RS_TICKS will be 130.2 hence we either creep back by 0.2 or add an extra
;;   cycle and creep forward 0.8.
;; Given how close Denis starts to the bits leading edge, I suspect that he
;;   delibarately added the extra cycle at 6Mhz to cause forward creep rather
;;   than back.
;; I shall do likewise and cause a delay for 122 cycles after 8 bits this only
;;   puts us 6/1/2 cycles futher along along (8%) anyway.
;; I wont do this here tho! i shall add it to RS_TICKS at the top

_delay_x_9:
;; Smallest delay possible with this routine is 19 cycles (38400 @ 4Mhz clock
;; is possible using 26 cycles so i dont think its an issue )
;; Uses TEMP_0 and TEMP_1 and 7 instrctions
;; Delay comprises of
;;   9 - static value
;;   2 - call to get here
;;   6 - routine overhead
;;   (n*3) - where n is number of loops required
;;  -1 - (-1 coz last time round  loop only executes 2 cycles not 3)
;;   r - where r is (n mod 3) to get number of extras leftover
;;
;; We need to calculate sumber of times round loop which is RS_TICKS less the
;;   static values (9+2+6-1)=16

;	;	;			;
WAIT_CYCLES set (RS_TICKS - 16)
WAIT_LOOPS set (WAIT_CYCLES / 3)
;	;	;			;
	if (WAIT_LOOPS < 1)		;{
		error "wait time too short"
	endif				; }
;	;	;			;
	movwf	TEMP_1			; (1) store w to temp_1
	movlw	WAIT_LOOPS		; (1) get number of loops to do
WAIT_CYCLES set (WAIT_CYCLES - (WAIT_LOOPS*3)); calc number of spare cycles
	movwf	TEMP_0			; (1) store literal in TEMP_0
	movf	TEMP_1,W		; (1) recover w from TEMP_1
_tx_delay:
        decfsz	TEMP_0,F		; (1) decrement and goto if zero
        goto	_tx_delay		; (2(1 if skipped)) go back round loop
;	;	;			;   one cycle down coz the goto got
;	;	;			;   missed have to account for it
;	;	;			;   with a nop
	if (WAIT_CYCLES == 1)		; {
	nop	;			; (1)
	endif	;			; }
	if (WAIT_CYCLES == 2)		; {
	goto	_delay_x_9_next2	; (2)
;	;	;			;
_delay_x_9_next2:
	endif	;			; }
;	;	;			;
_delay4:
        return	;			; (2)
;	;	;			;
_c_is_clear:
        bsf	PORTA,B_RS232_TxD       ; 1
        addlw	10h                     ; 1
        bcf	STATUS,C                ; 1  =nop
        goto	_tx_loop                ; 2
;	;	;			;


;;========================================================================
;; Primary initialisation - and main loop
;;========================================================================
;	;	;			; RS232_TxD:=0, RS232_CTS:=0
_init:
        clrf	PORTB                   ; Initialise PORTB to off
        clrf	PORTA			; Initialise PORTA to off
        movlw	B'00000000'             ; porta, ___ooooo
        tris	5			; (depreciated) set PORTA data
;	;	;			;   direction to all output
        movlw	B'00000001'             ; portb, oooooooi
        tris	6			; (depreciated) set PORTB to
;	;	;			; output except for RB0
;	;	;			;
        bcf	TCPS_FLAG,B_TCP_ONLINE  ; clear tcp_online flag
; return here upon recipt of error
;	;	;			;
_error:
        clrf	IP_HLEN                 ; clear IP_HLEN reg
        bsf	IP_HLEN,B_SLIP_OUTPKT   ; set discard data flag
;; return here to continue to wait for next byte
;	;	;			;
_rx:
        bsf	PORTA,B_RS232_CTS       ; turn on CTS
        movlw	B'10010000'             ; enable GIE and INTE
        movwf	INTCON	                ;
;	;	;			;
_busy_loop:
; The interupt routine doesnt use RETIE it simply gotos back to either of the
;   _rx or _error entry points
        goto	_busy_loop	        ; infinite busy loop
;	;	;			;


;========================================================================
; (rus)  TCP/IP (rus) 
;========================================================================
_just_ack:
_tcp_send_empty_10:
        bcf	TCPS_FLAG,0             ; TCPS_FLAG=xxxxxxx0
        bcf	TCPS_FLAG,1             ; TCPS_FLAG=xxxxxx0x
_tcp_send_empty:
        clrf	TCPS_LEN	        ;
_tcp_send:
        call	_tx_slip_end
        SUM0	(-(4500h+4000h+8000h))  ; (rus) IP (rus)
        movwf	IP_SUM_0		;
        SUM1	(-(4500h+4000h+8000h))	;
        movwf	IP_SUM_1		;
        TXLW	045h			;
        call	_tx_0_0			;
        movf	TCPS_LEN,W		;
        addlw	14h+14h			;
        movwf	IP_LEN                  ; IP_LEN = TCPS_LEN+14h+14h
        call	_slitx			;
        call	_chksum_pseudoheader
        call	_tx_0_0
        TXLW	040h
        call	_tx_0
        TXLW	080h
        TXLW	006h
        call	_slitx_csum
        SLITXLW	ADDR_MYSELF_0
        SLITXLW	ADDR_MYSELF_1
        SLITXLW ADDR_MYSELF_2
        SLITXLW ADDR_MYSELF_3
        movlw	IP_ADR_0
        call	_slitx4
;	;	;			;
        movf	TCPR_SEQ_L0,W           ; (rus) SEQ (rus)
        subwf	TCPS_ACK,W              ; (rus) TCP (rus)
        bc	_no_correct_hi_seq      ;
        incf	TCPR_SEQ_L1,F           ;
        skpnz                           ;
        incf	TCPR_SEQ_L2,F
        skpnz
        incf	TCPR_SEQ_L3,F
_no_correct_hi_seq:
        addwf	TCPR_SEQ_L0,F           ; TCPR_SEQ_L0+=TCPS_ACK-TCPR_SEQ_L0
        SUM0	(-(5000h+TCP_RCV_WINDOW-0014h))
        movwf	IP_SUM_0                ; (rus) TCP (rus) 
        SUM1	(-(5000h+TCP_RCV_WINDOW-0014h))
        movwf	IP_SUM_1
        call	_chksum_pseudoheader
        movlw	TCPR_LPORT_H
        movwf	FSR
        call	_slitx2
        movlw	TCPR_RPORT_H
        movwf	FSR
        call	_slitx2
        movlw	TCPR_ACK_L3
        call	_slitx4
        movlw	TCPR_SEQ_L3
        call	_slitx4
        TXLW	050h
        movf	TCPS_FLAG,W
        andlw	B'00010011'             ; 0x10,0x11,0x12
        call	_tx
        movf	TX_BYTE,W
        call	_checksum_lo
        call	_tx_0
        TXLW	TCP_RCV_WINDOW
;	;	;			;
        clrf	IP_POS
_loop_top0:
        movf	TCPS_LEN,W              ; (rus)
        xorwf	IP_POS,W                ; (rus) TCP (rus) 
        bz	_loop_break0
        call	_file_read
        call	_checksum_byte
        incf	IP_POS,F
        goto	_loop_top0
_loop_break0:
        call	_slitx_csum
        call	_tx_0_0
;	;	;			;
        clrf	IP_POS                  ; (rus) TCP (rus) 
_loop_top1:
        movf	TCPS_LEN,W
        xorwf	IP_POS,W
        bz	_loop_break1
        call	_file_read
        call	_slitx
        incf	IP_POS,F
        goto	_loop_top1
_loop_break1:
;	;	;			;
_tx_slip_end:
        movlw	0C0h                    ; (rus) SLIP.END
        goto	_tx
;	;	;			;



;========================================================================
; (rus) TCP/IP (rus)
;========================================================================
_chksum_pseudoheader:
        movf	IP_LEN,W
        call	_checksum_lo
        movf	IP_ADR_0,W
        call	_checksum_hi
        movf	IP_ADR_1,W
        call	_checksum_lo
        movf	IP_ADR_2,W
        call	_checksum_hi
        movf	IP_ADR_3,W
        call	_checksum_lo
        SUM0	(6+((ADDR_MYSELF_0+ADDR_MYSELF_2)<<8)+(ADDR_MYSELF_1+ADDR_MYSELF_3))
        call	_checksum_hi
        SUM1	(6+((ADDR_MYSELF_0+ADDR_MYSELF_2)<<8)+(ADDR_MYSELF_1+ADDR_MYSELF_3))
        goto	_checksum_lo
;------------------------------------------
_checksum_byte:
        brset	IP_POS,0,_checksum_lo
_checksum_hi:
        subwf	IP_SUM_0,F              ; (rus)
        movlw	1
        skipc
_checksum_lo:
        subwf	IP_SUM_1,F              ; (rus)
        movlw	1
        skipc
        subwf	IP_SUM_0,F
        skipc
        subwf	IP_SUM_1,F
        return


;========================================================================
; UDP handler
;========================================================================
_process_udp:
;	;	;			; ... to do ...


;========================================================================
; TCP handler
;========================================================================
_process_tcp:
        movf	TCPR_LPORT_L,W          ; (rus)
        xorlw	TCP_PORT_HTTP
        iorwf	TCPR_LPORT_H,W
        skipz
        return
;	;	;			;
        skip0	TCPR_FLAG,2             ; RST
        bcf	TCPS_FLAG,B_TCP_ONLINE
        brset	TCPR_FLAG,0,_tcp_fin    ; FIN
        brset	TCPR_FLAG,1,_tcp_syn    ; SYN
        skip1	TCPR_FLAG,4             ; ACK ????
        return
;_tcp_ack:
        movf	TCPS_SEQ,W
        subwf	TCPR_ACK_L0,W
        subwf	TCPS_LEN,W              ; TCPS_LEN-TCPR_ACK_L0+TCPS_SEQ
        bz	_my_transmit_is_acked
        subwf	TCPS_LEN,W              ; -TCPR_ACK_L0+TCPS_SEQ
        bz	_tcp_send               ; (rus)... RETRANSMIT !!!!
        return                              ; (rus) TCPR_ACK_L0 = (rus)
_my_transmit_is_acked:
        movf	TCPR_ACK_L0,W           ; tcps_seq=LO(tcpr.ack);
        movwf	TCPS_SEQ                ;
        movf	TCPR_SEQ_L0,W           ; if(tcpr.seq==tcps_ack1)
        xorwf	TCPS_ACK,W              ;
        bnz	_tcp_send               ; (rus)... RETRANSMIT !!!!
;_new_data_was_rvcd:
        movf	TCPR_HLEN,W
        subwf	IP_LEN,W
        addwf	TCPS_ACK,F              ; tcps_ack1 += ip_len-tcpr.hlen;
;	;	;			;
        addwf	TCPR_POS,F
        skipnc
        bsf	TCPR_POS,7              ; 0-->](128..255)
;	;	;			;
;	;	;			;
; ************* HTTP server (rus) *******************
        movlw	B'00010001'             ; http_state    = *
                                        ; b_tcp_online  = 0
                                        ; tcps_flag     = FIN+ACK
        brset	TCPS_FLAG,B_HTTP_STATE_1,_set_flag_and_send
        brset	TCPS_FLAG,B_HTTP_STATE_0,_http_state_1
_http_state_0:
;	;	;			;
        movf	TCPR_POS,W              ; if(tcpr_pos<*) goto _tcp_send_empty_10
        addlw	-8			; strlen("GET / HTTP/0.9\r\n\r\n")=18
        bnc	_tcp_send_empty_10
;	;	;			;
;	;	;			; ??? todo: file system functions
;	;	;			; =set http_unitidx
;	;	;			; =set http_filesize_h
;	;	;			; =set http_filesize_l
	if (FS_USE_INTERNAL_ROM)	; {
;	;	;			;------------------------
;	;	;			; CGI
;	;	;			;------------------------
        movf	HTTP_NAME_0,W           ;
        sublw	'a'                     ;
        bz	_cgi_a                  ; HTTP_NAME_0 == 'a'
        sublw	('a'-'0')               ;<'a'-'0'>               ;
        addlw	-10                     ;
        bnc	_cgi_digit              ; HTTP_NAME_0 in ['0'..'9']
        movlw	3                       ;
        movwf	HTTP_UNITIDX            ; HTTP_UNITIDX = 3
        clrf	HTTP_FILESIZE_H         ;
        movlw	06Fh                    ; HTTP_FILESIZE = 0x6F
        goto	_cgi_done               ;
_cgi_digit:
        rlf	HTTP_NAME_1,F           ; status.c=0
        movf	HTTP_NAME_1,W           ;
        rlf	HTTP_NAME_1,F           ;
        rlf	HTTP_NAME_1,F           ;
        addwf	HTTP_NAME_1,W           ;
        addwf	HTTP_NAME_2,W           ; W := 10*HTTP_NAME_0+HTTP_NAME_1
        addlw	-16                     ; W := 10*(HTTP_NAME_0-'0')+(HTTP_NAME_1-'0')
        skip0	HTTP_NAME_0,0		;
        addlw	100			;
        skip0	HTTP_NAME_0,1		;
        addlw	200			;
        movwf	PORTB                   ;
;	;	;			;
;       andlw	11110b			;
;       movwf	PORTB                   ;
_cgi_a:
        clrf	HTTP_UNITIDX            ; HTTP_UNITIDX = 0
        movlw	1                       ;
        movwf	HTTP_FILESIZE_H         ; HTTP_FILESIZE = 0x180
        movlw	080h                    ;
_cgi_done:
        movwf	HTTP_FILESIZE_L         ;
;	;	;			;
	endif				; }
	if (FS_USE_EXTERNAL_ROM)	; {
;	;	;			;...todo...
	endif				; }
;	;	;			;
        bsf	TCPS_FLAG,B_HTTP_STATE_0; http_state=1
        goto	_send_portion_of_file	;
;	;	;			;
_http_state_1:
        incf	HTTP_UNITIDX,F          ; http_unitidx++
        movf	TCPS_LEN,W              ; http_filesize -= tcps_len;
        subwf	HTTP_FILESIZE_L,F	;
        skipc   ;			;
        decf	HTTP_FILESIZE_H,F
_send_portion_of_file:
        movf	HTTP_FILESIZE_H,F
        bnz	_transmit_80
        movf	HTTP_FILESIZE_L,W
        addlw	7Fh
        bc	_transmit_80
        bsf	TCPS_FLAG,B_HTTP_STATE_1; http_state=3
        movf	HTTP_FILESIZE_L,W       ; <== TRANSMIT less than TCP_SND_WINDOW bytes
        goto	_transmit_not_80
_transmit_80:
        movlw	TCP_SND_WINDOW          ; <== TRANSMIT TCP_SND_WINDOW bytes
_transmit_not_80:
        movwf	TCPS_LEN
        goto	_tcp_send
;	;	;			;
;	;	;			;
_tcp_fin:
        incf	TCPR_SEQ_L0,W           ; tcps_ack1 = B3(tcpr.seq)+1;
        movwf	TCPS_ACK
        incf	TCPS_SEQ,F              ; tcps_seq1++;
        movlw	B'00010000'             ; tcps_flag = 0x11; // SYN+ACK
;	;	;			; tcp_online=0;
;	;	;			; http_state=*;
_set_flag_and_send:
        movwf	TCPS_FLAG
        goto	_tcp_send_empty         ; tcp_send_empty()
;	;	;			;
_tcp_syn:
;	brset	TCPS_FLAG,B_TCP_ONLINE,_return  ; if( 0==tcp_online ) {
        incf	TCPR_SEQ_L0,W           ; tcps_ack1 = B3(tcpr.seq)+1;
        movwf	TCPS_ACK
        clrf	TCPR_POS                ; tcpr_pos=0;
        clrf	TCPS_SEQ                ; tcps_seq1=ISS=0;
        movlw	B'10010010'               ; http_state=0; // just connected
        movwf	TCPS_FLAG               ; tcps_flag = 0x12; // SYN+ACK
        call	_tcp_send_empty         ; tcp_send_empty(); // (rus)
        incf	TCPS_SEQ,F              ; tcps_seq1++;
        return                          ; }

	if (FS_USE_INTERNAL_ROM)	; {
;========================================================================
; Internal ROM/EEPROM File (max 512/64 bytes)
;========================================================================
; UNIT0:        ROM             0x0200..0x027F
; UNIT1:        ROM             0x0280..0x02FF
; UNIT2:        ROM             0x0300..0x037F
; UNIT3:        ROM             0x0380..0x03FF
; UNIT4:        EEPROM          0x0000..0x003F
;========================================================================
_file_read:
	if (FS_USE_INTERNAL_EEPROM); {
;	j0	<HTTP_UNITIDX,2>,_ir_read
_ie_read:
        movf	IP_POS,W
        movwf	EEADR                   ; Address to read
        bsf	RP0			;
        bsf	EECON1,0                ; EE Read
        bcf	RP0			;
        movf	EEDATA,W                ; W = EEDATA
        return	;			;
	endif				; }
_ir_read:
        clrf	PCLATH
        bsf	PCLATH,1
	if (FS_INTERNAL_ROM_UNITS >= 2); {
        skip0	HTTP_UNITIDX,1
        bsf	PCLATH,0
	endif				; }
        movf	IP_POS,W
	if (FS_INTERNAL_ROM_UNITS >= 1)	; {
        skip0	HTTP_UNITIDX,0
        iorlw	80h
	endif				; }
        movwf	PCL


;========================================================================
; Simple CGI support
;========================================================================
_cgi_portb_hi:
        swapf	PORTB,W
        goto	_lo4bit_as_hexdigit
;	skip0	<PORTA,4>
;	retlw	'1'
;	retlw	'0'
_cgi_portb_lo:
        movf	PORTB,W
_lo4bit_as_hexdigit:
        andlw	B'00001111'
        addlw	-10
        skipnc
        addlw	7
        addlw	58
        return
;	;	;			;

	ORG	0x200
;========================================================================
; JavaScript program for PortB control
;========================================================================
        dt	"HTTP/1.0"
	dt	" 200\r\n\r\n"
        ; "Content-Type: %s", "blah-blah-blah"
        ; "Content-Length: %d", blah_blah_blah
        ; "Refresh: %d", blah_blah_blah
        dt	"<title>P"
	dt	"ort B</t"
        dt	"itle><bo"
	dt	"dy onLoa"
        dt	"d=\"for(v"
	dt	"ar i=0;i"
        dt	"<7;i++)d"
	dt	"ocument."
        dt	"forms[0]"
	dt	".element"
        dt	"s[i].che"
	dt	"cked=0x"
        goto	_cgi_portb_hi           ; SIC!
        goto	_cgi_portb_lo
        dt	"&(2<<i)"
	dt	"\"><form "

        dt	"action=a"
	dt	"><script"
        dt	">for(var"
	dt	" i=1;i<8"
        dt	";i++)doc"
	dt	"ument.wr"
        dt	"ite(\"B.\""
	dt	"+i+\"<INP"
        dt	"UT TYPE="
	dt	"checkbox"
        dt	"><BR>\")<"
	dt	"/script>"
        dt	"<input t"
	dt	"ype=subm"
        dt	"it value"
	dt	"=Read><i"

        dt	"nput typ"
	dt	"e=button"
        dt	" value=W"
	dt	"rite onC"
        dt	"lick=\"fo"
	dt	"r(var v="
        dt	"400,i=0;"
	dt	"i<7;v+=d"
        dt	"ocument."
	dt	"forms[0]"
        dt	".element"
	dt	"s[i].che"
        dt	"cked<<++"
	dt	"i);top.l"
        dt	"ocation."
	dt	"href=v\">"

;========================================================================
; Index Page
;========================================================================
        dt	"HTTP/1.0"
	dt	" 200\r\n\r\n"
        dt	"<a href="
	dt	"a>PortB "
        dt	"control<"
	dt	"/a><hr><"
        dt	"a href=h"
	dt	"ttp://ky"
        dt	"llikki.f"
	dt	"luff.org"
        dt	"/hardwar"
	dt	"e/>wwwpi"
        dt	"c2 homep"
        dt	"age</a> "
	dt	"        "
	dt	"        "

      	endif			; }

	if (FS_USE_EXTERNAL_ROM); {
_file_read:
        retlw	0
	endif			; }

end


syntax highlighted by Code2HTML, v. 0.9