;;========================================================================
;;
;; Program:         TCP/IP stack and HTTP-server in a chip
;; Idea:            Shrikumar H. <shri@cs.umass.edu>
;; Author:          Denis Petrov <zhengxi@operamail.com>
;; Platform:        Microchip PIC16F84
;; Date:            17.09.99
;; LastDate:        25.09.99
;;
;;========================================================================

;; todo: watching tcp_online
;;       use WDT
;;       more than 1 socket

include masmpic.inc
.386

;;========================================================================
;; General settings
;;========================================================================
QUARTZ_FREQ             =  6000000
RS_BAUD                 =    19200
RS_DATA                 =        8
RS_TICKS                =  (QUARTZ_FREQ/4)/RS_BAUD   ; [non-volatile]


ADDR_MYSELF_0           =      219      ; 219.192.55.208 ( ~my phone# :)
ADDR_MYSELF_1           =      192
ADDR_MYSELF_2           =       55
ADDR_MYSELF_3           =      208

TCP_PORT_HTTP           =       80      ; 1..255

TCP_RCV_WINDOW          =      128;!sic!; [non-volatile]
TCP_SND_WINDOW          =      128      ; [non-volatile]

RS_MONITOR              =        1      ; monitor works over raw RS232

FS_UNIT_SIZE            =      128      ; [non-volatile]
FS_ROOT_DIR_ENTRIES     =        8      ; min 2: INDEX and ERROR.

FS_USE_INTERNAL_ROM     =        1
FS_INTERNAL_ROM_UNITS   =        4      ; number of 128-byte pages
FS_USE_INTERNAL_EEPROM  =        0      ;

FS_USE_EXTERNAL_ROM     =        0


;;========================================================================
;; DATA RAM mapping
;;========================================================================
TCPR_RPORT_H            =   SRAM0           ; remote TCP port
TCPR_RPORT_L            =   SRAM1
TCPR_LPORT_H            =   SRAM2           ; local TCP port, TCPR_LPORT_H==0
TCPR_LPORT_L            =   SRAM3
TCPR_SEQ_L3             =   SRAM4
TCPR_SEQ_L2             =   SRAM5
TCPR_SEQ_L1             =   SRAM6
TCPR_SEQ_L0             =   SRAM7
TCPR_ACK_L3             =   SRAM8
TCPR_ACK_L2             =   SRAM9
TCPR_ACK_L1             =   SRAM10
TCPR_ACK_L0             =   SRAM11
TCPR_HLEN               =   SRAM12          ; Is not used when sending не используется при посылке

TCPR_FLAG               =   SRAM13          ; ÎÅ ÉÓÐÏÌØÚÕÅÔÓÑ ÐÒÉ ÐÏÓÙÌËÅ

TEMP_0                  =   SRAM2
TEMP_1                  =   SRAM12
TEMP_2                  =   SRAM13

HTTP_UNITIDX            =   SRAM14 ;***
HTTP_FILESIZE_H         =   SRAM15 ;***
HTTP_FILESIZE_L         =   SRAM16 ;***
HTTP_NAME_0             =   SRAM14
HTTP_NAME_1             =   SRAM15
HTTP_NAME_2             =   SRAM16

if RS_MONITOR
MON_ADDR_H              =   SRAM14
MON_ADDR_L              =   SRAM15
MON_TAG                 =   SRAM16          ; like (as) 'R', 'W', 'A' ×ÒÏÄÅ 'R','W','A'
endif

; socket data, it's valid if tcp_online==1
TCPR_POS                =   SRAM17          ; iterator 0 -->] 80..FF
                                            ; bytes received from the time communication opened 
                                            ; ÐÒÉÎÑÔÏ ÂÁÊÔ Ó ÏÔËÒÙÔÉÑ ÓÏÅÄÉÎÅÎÉÑ
TCPS_ACK                =   SRAM18
TCPS_SEQ                =   SRAM19
TCPS_LEN                =   SRAM20          ; for retransmit
TCPS_FLAG               =   SRAM21          ; for retransmit

RX_BYTE                 =   SRAM22          ; [soft uart]
TX_BYTE                 =   RX_BYTE         ; [soft uart]

IP_POS                  =   SRAM23          ; iterator
IP_HLEN                 =   SRAM24          ; IP header len (incoming only)
IP_LEN                  =   SRAM25          ; IP packet len
IP_SUM_0                =   SRAM26          ; TCP/IP chksum
IP_SUM_1                =   SRAM27          ; --//-----//-- low octet
IP_ADR_0                =   SRAM28          ; remote IP address
IP_ADR_1                =   SRAM29          ; --//--
IP_ADR_2                =   SRAM30          ; --//--
IP_ADR_3                =   SRAM31          ; --//--

DefBit      B_HTTP_STATE_0, TCPS_FLAG, 5
DefBit      B_HTTP_STATE_1, TCPS_FLAG, 6
DefBit      B_TCP_ONLINE,   TCPS_FLAG, 7
;DefBit     B_LED_1,        PORTA,     3
;DefBit     B_LED_2,        PORTA,     2
DefBit      B_RS232_RxD,    PORTB,     0
DefBit      B_RS232_TxD,    PORTA,     3
DefBit      B_RS232_CTS,    PORTA,     2
DefBit      B_SLIP_OUTPKT,  IP_HLEN,   7
DefBit      B_SLIP_ESCAPE,  IP_HLEN,   6


;;========================================================================
;; Useful macros
;;========================================================================
TXLW macro k
  movlw       (k)
  call        _tx
endm

SLITXLW macro k
  movlw       (k)
  call        _slitx
endm

SUM0 MACRO x:req
__TMPSUM=(((x)+((x) shr 16)) shr 8)
    movlw __TMPSUM
ENDM

SUM1 MACRO x:req
__TMPSUM=(((x)+((x) shr 16)) shr 0)
    movlw __TMPSUM
ENDM


;;========================================================================
;; Code
;;========================================================================
_start:
        clrf        INTCON                  ; Disable Interrupts ÚÁÐÒÅÔÉÔØ ×ÓÅ ÐÒÅÒÙ×ÁÎÉÑ ?
        movlw       01001111b               ; "_-", WDT/128
        option
        jump        _init

_interrupt:
;
; Soft UART ( simplex :( )
;
;         S01234567T
;        ƒ‚ˆˆˆˆˆˆˆˆˆ
; 115.2  „‰‰‰‰‰‰‰‰…„
;        ƒ ‚€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ
;  57.6  „€‰€‰€‰€‰€‰€‰€‰€‰€… „
;        ƒ  ‚€€ˆ€€ˆ€€ˆ€€ˆ€€ˆ€€ˆ€€ˆ€€ˆ€€ˆ
;  38.4  „€€‰€€‰€€‰€€‰€€‰€€‰€€‰€€‰€€…  „
;        ƒ     ‚€€€€€ˆ€€€€€ˆ€€€€€ˆ€€€€€ˆ€€€€€ˆ€€€€€ˆ€€€€€ˆ€€€€€ˆ€€€€€ˆ€€
;  19.2  „€€€€€‰€€€€€‰€€€€€‰€€€€€‰€€€€€‰€€€€€‰€€€€€‰€€€€€‰€€€€€…     „€€
;                                        _________
;
;       _^_"þ"
;
_interrupt_b0:                              ; 5 ; Interrupt ÏÂÒÁÂÏÔÞÉÔ ÐÒÅÒÙ×ÁÎÉÑ INT
        call        _delay4                 ; 4 ; Delay 4 (ÍÏÍÅÎÔ "þ")
        movlw       8                       ; 1 ; 8Nx
_rx_next:
        bcf         B_RS232_CTS             ; 1 ; fall CTS
        call        _delay_x_9              ; x-9 ;
        bcf         C                       ; 1 ;
        skip1       B_RS232_RxD             ; 1 ;
        bsf         C                       ; 1 ; C:=RS232_RxD
        rrf         RX_BYTE,F               ; 1 ;
        addlw       -1                      ; 1 ;
        jnz         _rx_next                ; 3 ;

        movf        RX_BYTE,w               ;
        xorlw       0C0h                    ;
        jnz         _no_C0                  ; Starting to recieve ÎÁÞÉÎÁÅÍ ÐÒÉÅÍ
        bcf         B_SLIP_OUTPKT           ; New package (SLIP END) ÎÏ×ÏÇÏ ÐÁËÅÔÁ (SLIP END)
        clrf        IP_POS                  ;
        clrf        IP_SUM_0                ;
        clrf        IP_SUM_1                ;
        jump        _rx                     ;
_no_C0:
        j0          B_SLIP_OUTPKT,_mode_slip; if the symbol being revieved is not in the package 
                                            ; ÅÓÌÉ ÐÒÉÎÉÍÁÅÍÙÊ ÓÉÍ×ÏÌ ×ÎÅ ÐÁËÅÔÁ
_mode_terminal:
        xorlw       <00Dh xor 0C0h>         ;
        jnz         _rx                     ; Modem emulation ÜÍÕÌÑÃÉÑ ÍÏÄÅÍÁ:
        TXLW        'O'                     ; Respond to AT command ÏÔ×ÅÔ ÎÁ AT-ËÏÍÁÎÄÙ
        TXLW        'K'                     ;
        TXLW        0Dh                     ;
        jump        _rx                     ;
_mode_slip:
        j0          B_SLIP_ESCAPE,_no_slip_escape
        xorlw       <0DCh xor 0C0h>         ; Treatment of the 2nd byte
                                            ; ÏÔÒÁÂÏÔËÁ ×ÔÏÒÏÇÏ ÂÁÊÔÁ
        movlw       0DBh                    ; Special order SLIP ÓÐÅÃ.ÐÏÓÌÅÄÏ×ÁÔÅÌØÎÏÓÔÅÊ SLIP:
        skipnz                              ; 0xDB,0xDC --> 0xC0
        movlw       0C0h                    ; 0xDB,0xDD --> 0xDB
        movwf       RX_BYTE                 ; RX_BYTE=(RX_BYTE==0xDC?0xC0:0xDB)
;       jump        _end_slip_escape        ;
_no_slip_escape:                            ;
        bsf         B_SLIP_ESCAPE           ; if OxDB is recieved, then ÅÓÌÉ ÐÒÉÎÑÔ 0xDB, ÚÎÁÞÉÔ
        xorlw       <0DBh xor 0C0h>         ; this is the first byte ÜÔÏ ÐÅÒ×ÙÊ ÂÁÊÔ
        jz          _rx                     ; special order SLIP ÓÐÅÃ.ÐÏÓÌÅÄÏ×ÁÔÅÌØÎÏÓÔÉ SLIP:

_end_slip_escape:
        bcf         B_SLIP_ESCAPE           ;

        movf        RX_BYTE,W
        call        _checksum_byte          ; control sum refreshement (renewal?) 
                                            ; ÏÂÎÏ×ÌÅÎÉÅ ËÏÎÔÒÏÌØÎÏÊ ÓÕÍÍÙ
                                            ; of the package being recieved 
                                            ; ÐÒÉÎÉÍÁÅÍÏÇÏ ÐÁËÅÔÁ

        movf        IP_POS,W                ; treatment of the first 0x13 bytes 
                                            ; ÏÂÒÁÂÏÔËÁ ÐÅÒ×ÙÈ 0x13 ÂÁÊÔ
        addlw       -20                     ; after SLIP END as a header
                                            ; ÐÏÓÌÅ SLIP.END ËÁË ÚÁÇÏÌÏ×ÏË
        jc          _xxxx                   ; of the IP package IP ÐÁËÅÔÁ
        rlf         IP_POS,W                ;
        clrf        PCLATH                  ; usefull but not required
                                            ; ÜÔÏ ÐÏÌÅÚÎÏ, ÎÏ ÎÅ ÎÅÏÂÈÏÄÉÍÏ
        addwf       PCL,F                   ;

        movf        RX_BYTE,W               ; IPhdr+ 0  Version & IHL
        movwf       IP_HLEN                 ;
        rlf         IP_HLEN,F               ; IPhdr+ 1  Type of Service
        jump        _01_                    ;
        movlw       0                       ; IPhdr+ 2  Total Length (hi)
        jump        _rx_byte_must_equal_w   ;
        movf        RX_BYTE,W               ; IPhdr+ 3  Total Length (lo)
        movwf       IP_LEN                  ;
        jump        _finish                 ; IPhdr+ 4  Identification (hi)
_01_:   bcf         IP_HLEN,7               ;
        jump        _finish                 ; IPhdr+ 5  Identification (lo)
        nop                                 ;
        jump        _finish                 ; IPhdr+ 6  Flags & Fragment Offset (hi)
        nop                                 ;
        movlw       0                       ; IPhdr+ 7  Fragment Offset (lo)
        jump        _rx_byte_must_equal_w   ;
        jump        _finish                 ; IPhdr+ 8  Time to Live
        nop                                 ;
        movlw       6                       ; IPhdr+ 9  Protocol
        jump        _rx_byte_must_equal_w   ;
        jump        _finish                 ; IPhdr+10  Header Checksum (hi)
        nop                                 ;
        jump        _finish                 ; IPhdr+11  Header Checksum (lo)
        nop                                 ;
        movlw       IP_ADR_0                ; IPhdr+12  Source Address
        jump        _save_rx_byte           ;
        movlw       IP_ADR_1                ; IPhdr+13
        jump        _save_rx_byte           ;
        movlw       IP_ADR_2                ; IPhdr+14
        jump        _save_rx_byte           ;
        movlw       IP_ADR_3                ; IPhdr+15
        jump        _save_rx_byte           ;
        movlw       ADDR_MYSELF_0           ; IPhdr+16  Destination Address
        jump        _rx_byte_must_equal_w   ;
        movlw       ADDR_MYSELF_1           ; IPhdr+17
        jump        _rx_byte_must_equal_w   ;
        movlw       ADDR_MYSELF_2           ; IPhdr+18
        jump        _rx_byte_must_equal_w   ;
        movlw       ADDR_MYSELF_3           ; IPhdr+19
_rx_byte_must_equal_w:
        xorwf       RX_BYTE,W               ;
        jnz         _error                  ;

_xxxx:
        movf        IP_HLEN,W               ; IP_POS-IP_HLEN - on which position ÎÁ ËÁËÏÍ ÍÅÓÔÅ
        subwf       IP_POS,W                ; after the IP header, the recieved byte can be found
                                            ; ÐÒÉÎÑÔÙÊ ÂÁÊÔ ÎÁÈÏÄÉÔÓÑ ÐÏÓÌÅ IP ÚÁÇÏÌÏ×ËÁ
        jc          _post_ip                ; ... or is this still an IP header? 
                                            ; ... ÉÌÉ ÜÔÏ ×ÓÅ ÅÝÅ IP ÚÁÇÏÌÏ×ÏË?

_no_post_ip:
        xorlw       0FFh                    ; and if this is the last byte of the IP header
                                            ; Á ÅÓÌÉ ÜÔÏ ÐÏÓÌÅÄÎÉÊ ÂÁÊÔ IP ÚÁÇÏÌÏ×ËÁ
        jnz         _finish                 ; IP_SUM should be 0 IP_SUM ÄÏÌÖÎÁ ÂÙÔØ ÒÁ×ÎÁ 0
        movf        IP_SUM_0,W              ;
        iorwf       IP_SUM_1,W              ;
        jnz         _error                  ; wrong sum for monitoring
                                            ; ÎÅÐÒÁ×ÉÌØÎÁÑ ËÏÎÔÒÏÌØÎÁÑ ÓÕÍÍÁ...
_finish:
        incf        IP_POS,F                ; Next! ÓÌÅÄÕÀÝÉÊ!
        jump        _rx                     ;

_post_ip:
        addlw       -14                     ; saving the first 14 bytes of the TCP header
                                            ; ÓÏÈÒÁÎÑÅÍ ÐÅÒ×ÙÅ 14 ÂÁÊÔ TCP ÚÁÇÏÌÏ×ËÁ
        jnc         _save_as_tcp_header     ;
        jnz         _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             ; saving bytes 5, 6 and 7 of the TCP _connection_
                                            ; ÓÏÈÒÁÎÑÅÍ 5,6É7 ÂÁÊÔÙ TCP _ÓÏÅÄÉÎÅÎÉÑ_.
        addlw       -15                     ; if now (W<14) - than the name of the file
                                            ; ÅÓÌÉ ÓÅÊÞÁÓ (W<14) - ÚÎÁÞÉÔ ÉÍÑ ÆÁÊÌÁ
        jc          _no_save_rx_byte        ;  came in multiple packages, for example, 
                                            ; ÐÒÉÛÌÏ × ÎÅÓËÏÌØËÉÈ ÐÁËÅÔÁÈ, ÎÁÐÒÉÍÅÒ,
                                            ; GET /xxx was typed in the telnet-client
                                            ; GET /xxx ÂÙÌÏ ÎÁÂÒÁÎÏ × telnet-ËÌÉÅÎÔÅ
                                            ; so this check is not necessary
                                            ;  ÔÁË ÞÔÏ ÜÔÁ ÐÒÏ×ÅÒËÁ ÎÅ Ñ×Ì. ÎÅÏÂÈÏÄÉÍÏÊ,
                                            ;  if only www-browser will be used
                                            ; ÅÓÌÉ ÂÕÄÅÔ ÐÏÌØÚÏ×ÁÔØÓÑ ÔÏÌØËÏ www-browser.
        subwf       TCPR_POS,W              ; like first symbols of the file name in "GET /"
                                            ; ËÁË ÐÅÒ×ÙÅ ÓÉÍ×ÏÌÙ ÉÍÅÎÉ ÆÁÊÌÁ × "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)
        jnc         _no_save_rx_byte
if (HTTP_NAME_0-(TCPR_RPORT_H+14)) ne 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 - is often used ÞÁÓÔÏ ÉÓÐÏÌØÚÕÅÔÓÑ
        movf        RX_BYTE,W               ;
        movwf       INDR                    ;

_no_save_rx_byte:
        incf        IP_POS,W                ; ÅÓÌÉ ÐÒÉÎÑÔ ÐÏÓÌÅÄÎÉÊ ÂÁÊÔ
        subwf       IP_LEN,W                ; if the last byte of the IP package is recieved... 
                                            ; IP ÐÁËÅÔÁ...
        jnz         _finish                 ;

        movf        IP_HLEN,W               ; IP_LEN-=IP_HLEN;
        subwf       IP_LEN,F                ;
        call        _chksum_pseudoheader    ; control check sum of the TCP package's header/body 
                                            ; ÐÒÏ×ÅÒËÁ ËÏÎÔÒÏÌØÎÏÊ ÓÕÍÍÙ TCP ÚÁÇÏÌÏ×ËÁ/ÔÅÌÁ ÐÁËÅÔÁ
        movf        IP_SUM_0,W              ; 
        iorwf       IP_SUM_1,W              ;
        skipnz                              ;
        call        _process_tcp            ;
        jump        _error                  ;



;===========================================================================
; TX routines
;===========================================================================
;_txhex: movwf       FSR
;        swapf       FSR,W
;        call        _txhex0
;        movf        FSR,W
;_txhex0:andlw       00001111b
;        addlw       -10
;        skipnc
;        addlw       7
;        addlw       58
;        jump        _tx
;;------------------------------------------------
_slitx_csum:
        movf        IP_SUM_0,W              ; pass (or deliver) the control sum 
                                            ; ÐÅÒÅÄÁÔØ ËÏÎÔÒÏÌØÎÕÀ ÓÕÍÍÕ
        call        _slitx                  ; (2 bytes) (Ä×Á ÂÁÊÔÁ)
        movf        IP_SUM_1,W              ;
        jump        _slitx
;;------------------------------------------------
_slitx4:
        movwf       FSR                     ; pass (or deliver) 4 bytes (W[0]...W[3])
                                            ; ÐÅÒÅÄÁÔØ 4 ÂÁÊÔÁ (W[0]..W[3])
        call        _slitx2                 ; with the control sum correction
                                            ; Ó ËÏÒÒÅËÃÉÅÊ ËÏÎÔÒÏÌØÎÏÊ ÓÕÍÍÙ
_slitx2:
        movf        INDR,W                  ; pass (or deliver) 2 bytes (FSR[0]...FSR[1]) 
                                            ; ÐÅÒÅÄÁÔØ 2 ÂÁÊÔÁ (FSR[0]..FSR[1])
        call        _checksum_hi
        call        _slitx1
        movf        INDR,W
        call        _checksum_lo
_slitx1:
        movf        INDR,W                  ; pass (or deliver) 1 byte (*FSR++) 
                                            ; ÐÅÒÅÄÁÔØ 1 ÂÁÊÔ (*FSR++)
        incf        FSR,F                   ;
        jump        _slitx
;;------------------------------------------------
_tx_0_0:
        call        _tx_0                   ; pass (or deliver) 2 zeros
                                            ; ÐÅÒÅÄÁÔØ Ä×Á ÎÕÌÑ
_tx_0:
        movlw       000h                    ; pass (or deliver) a zero
                                            ; ÐÅÒÅÄÁÔØ ÎÕÌØ
_slitx:
        xorlw       0C0h                    ; pass (deliver) a byte by (using) SLIP protocol
                                            ; ÐÅÒÅÄÁÔØ ÂÁÊÔ ÐÏ ÐÒÏÔÏËÏÌÕ SLIP
        jnz         _ne_C0                  ; i.e. ( = that is) with substitutions
                                            ; Ô.Å. Ó ÚÁÍÅÎÁÍÉ
        TXLW        0DBh                    ;   0xC0 --> 0xDB,0xDC
        movlw       0DCh                    ;   0xDB --> 0xDB,0xDD
        jump        _tx                     ;
_ne_C0:
        xorlw       <0DBh xor 0C0h>         ;
        jnz         _tx11                   ;
        call        _tx11                   ;
        movlw       <0DDh xor 0DBh>         ;
_tx11:                                      ;
        xorlw       0DBh                    ;
_tx:
        bsf         B_RS232_TxD             ; just pass (deliver) one byte
                                            ; ÐÒÏÓÔÏ ÐÅÒÅÄÁÔØ ÏÄÉÎ ÂÁÊÔ
        movwf       TX_BYTE                 ; IN:  W
        movlw       <(-(RS_DATA+1))shl 4>   ; OUT: TX_BYTE:=W
_tx_loop_c:
        bsf         C                       ; 1
_tx_loop:
        call        _delay_x_9
        rrf         TX_BYTE,F               ; 1 ; 1
        jnc         _c_is_clear             ; 2 ; 3
        addlw       10h                     ; 1
        bcf         B_RS232_TxD             ; 1
        jnz         _tx_loop_c              ; 3
_delay_x_9:
; upon technical-delay it is not allowed:   ; ÐÒÉ TX-ÚÁÄÅÒÖËÅ ÎÅÌØÚÑ:
; 1. to change flag STATUS.C                ; 1. ÉÚÍÅÎÑÔØ ÆÌÁÇ STATUS.C
; 2. to overload the stream of returns      ; 2. ÓÉÌØÎÏ ÐÅÒÅÇÒÕÖÁÔØ ÓÔÅË ×ÏÚ×ÒÁÔÏ×
if ((RS_TICKS)-11) eq 28                    ; 38400 and 6MHz
        call        _x2 ;28=2+2*13
_x2:    nop
        call        _x1 ;12=2+2*5
_x1:    nop
        brake
elseif ((RS_TICKS)-11) eq 67                ; 19200 and 6MHz
if 0
        nop
        call        _x1 ;66=2*3+4*15
        call        _x1 ;
        call        _x1 ;66=2*5+10+10+10+10+10+6
        call        _x1 ;
        call        _x2 ;
_x1:    brake
        brake
_x2:    brake
        brake
else
TEMP_DELAY = TEMP_0
        clrf        TEMP_DELAY
        bsf         TEMP_DELAY,4
_tx_delay:
        nop
        decfsz      TEMP_DELAY,F
        jump        _tx_delay
endif
else
error
endif
_delay4:
        return
_c_is_clear:
        bsf         B_RS232_TxD             ; 1
        addlw       10h                     ; 1
        bcf         C                       ; 1  =nop
        jump        _tx_loop                ; 2



;========================================================================
;
;========================================================================
_init:
        ;movlw       00000000b              ; RS232_TxD:=0, RS232_CTS:=0
        clrf        PORTB                   ;
        clrf        PORTA
        movlw       00000000b               ; porta, ___ooooo
        tris        5
        movlw       00000001b               ; portb, oooooooi
        tris        6

        bcf         B_TCP_ONLINE            ;     tcp_online=0
_error:
        clrf        IP_HLEN                 ;
        bsf         B_SLIP_OUTPKT           ; at first outside of the package
                                            ; ÓÎÁÞÁÌÁ ÓÎÁÒÕÖÉ ÐÁËÅÔÁ
_rx:
        bsf         B_RS232_CTS             ; raise CTS ÐÏÄÎÑÔØ CTS
        movlw       10010000b               ; GIE+INTE
        movwf       INTCON
_rxl:
;       clrwdt                              ;????
        jump        _rxl

;========================================================================
; Sending of the TCP/IP package ÐÅÒÅÄÁÞÁ TCP/IP ÐÁËÅÔÁ
;========================================================================
_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)>  ; calculation of the IP header control sum
                                            ; ÒÁÓÞÅÔ ËÏÎÔÒÏÌØÎÏÊ ÓÕÍÍÙ IP ÚÁÇÏÌÏ×ËÁ
        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           ; SEQ formatting for the TCP package which is
                                            ;  being sent
                                            ; ÆÏÒÍÉÒÏ×ÁÎÉÅ SEQ ÄÌÑ
        subwf       TCPS_ACK,W              ; ÏÔÐÒÁ×ÌÑÅÍÏÇÏ TCP ÐÁËÅÔÁ
        jc          _no_correct_hi_seq      ;
        incf        TCPR_SEQ_L1,F           ;
        skipnz                              ;
        incf        TCPR_SEQ_L2,F
        skipnz
        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                ; calculation of the TCP headers control sum
                                            ; ÒÁÓÞÅÔ ËÏÎÔÒÏÌØÎÏÊ ÓÕÍÍÙ TCP ÚÁÇÏÌÏ×ËÁ
        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       00010011b               ; 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              ; calculation of the TCP package's body
                                            ; ÒÁÓÞÅÔ ËÏÎÔÒÏÌØÎÏÊ ÓÕÍÍÙ
        xorwf       IP_POS,W                ; ÔÅÌÁ TCP ÐÁËÅÔÁ
        jz          _loop_break0
        call        _file_read
        call        _checksum_byte
        incf        IP_POS,F
        jump        _loop_top0
_loop_break0:
        call        _slitx_csum
        call        _tx_0_0

        clrf        IP_POS                  ; delivery of the TCP package's body
                                            ; ÐÅÒÅÄÁÞÁ ÔÅÌÁ TCP ÐÁËÅÔÁ
_loop_top1:
        movf        TCPS_LEN,W
        xorwf       IP_POS,W
        jz          _loop_break1
        call        _file_read
        call        _slitx
        incf        IP_POS,F
        jump        _loop_top1
_loop_break1:

_tx_slip_end:
        movlw       0C0h                    ; deliver SLIP.END ÐÅÒÅÄÁÔØ SLIP.END
        jump        _tx


;========================================================================
; calculation/check of control sums of TCP/IP headers/packages
; ÒÁÓÞÅÔ/ÐÒÏ×ÅÒËÁ ËÏÎÔÒÏÌØÎÙÈ ÓÕÍÍ TCP/IP ÚÁÇÏÌÏ×ËÏ×/ÐÁËÅÔÏ×
;========================================================================
_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)shl 8)+(ADDR_MYSELF_1+ADDR_MYSELF_3)>
        call        _checksum_hi
        SUM1        <6+((ADDR_MYSELF_0+ADDR_MYSELF_2)shl 8)+(ADDR_MYSELF_1+ADDR_MYSELF_3)>
        jump        _checksum_lo
;------------------------------------------
_checksum_byte:
        j1          <IP_POS,0>,_checksum_lo
_checksum_hi:
        subwf       IP_SUM_0,F              ; correct high byte of the control sum
                                            ; ËÏÒÒÅËÔÉÒÏ×ÁÔØ ÓÔ.ÂÁÊÔ ËÏÎÔÒ.ÓÕÍÍÙ
        movlw       1
        skipc
_checksum_lo:
        subwf       IP_SUM_1,F              ; correct low byte of the control sum
                                            ; ËÏÒÒÅËÔÉÒÏ×ÁÔØ ÍÌ.ÂÁÊÔ ËÏÎÔÒ.ÓÕÍÍÙ
        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          ; testing the number of the local port
                                            ; ÐÒÏ×ÅÒËÁ ÎÏÍÅÒÁ ÌÏËÁÌØÎÏÇÏ ÐÏÒÔÁ
        xorlw       TCP_PORT_HTTP
        iorwf       TCPR_LPORT_H,W
        skipz
        return

        skip0       <TCPR_FLAG,2>           ; RST
        bcf         B_TCP_ONLINE
        j1          <TCPR_FLAG,0>,_tcp_fin  ; FIN
        j1          <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
        jz          _my_transmit_is_acked
        subwf       TCPS_LEN,W              ; -TCPR_ACK_L0+TCPS_SEQ
        jz          _tcp_send               ; if client did not confirm recieve... RETRANSMIT!!
                                            ; ÅÓÌÉ ËÌÉÅÎÔ ÎÅ ÐÏÄÔ×ÅÒÄÉÌ ÐÒÉÅÍ... RETRANSMIT !!!!
        return                              ; completely wrong TCPR_ACK_L0 = we're not responding
                                            ; ÓÏ×ÓÅÍ ÎÅÐÒÁ×ÉÌØÎÙÊ TCPR_ACK_L0 = ÎÅ ÏÔ×ÅÞÁÅÍ
_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              ;
        jnz         _tcp_send               ; if we havn't RX'd what we expected... RETRANSMIT!
                                            ; ÅÓÌÉ ÍÙ ÐÏÌÕÞÉÌÉ ÎÅ ÔÏ, ÞÔÏ ÖÄÁÌÉ... 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 ËÁË ËÏÎÅÞÎÙÊ Á×ÔÏÍÁÔ *******************
        movlw       00010001b               ; http_state    = *
                                            ; b_tcp_online  = 0
                                            ; tcps_flag     = FIN+ACK
        j1          B_HTTP_STATE_1,_set_flag_and_send
        j1          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
        jnc         _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'                     ;
        jz          _cgi_a                  ; HTTP_NAME_0 == 'a'
        sublw       <'a'-'0'>               ;
        addlw       -10                     ;
        jnc         _cgi_digit              ; HTTP_NAME_0 in ['0'..'9']
        movlw       3                       ;
        movwf       HTTP_UNITIDX            ; HTTP_UNITIDX = 3
        clrf        HTTP_FILESIZE_H         ;
        movlw       068h                    ; HTTP_FILESIZE = 0x6E
        jump        _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         B_HTTP_STATE_0          ; http_state=1
        jump        _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
        jnz         _transmit_80
        movf        HTTP_FILESIZE_L,W
        addlw       7Fh
        jc          _transmit_80
        bsf         B_HTTP_STATE_1          ; http_state=3
        movf        HTTP_FILESIZE_L,W       ; <== TRANSMIT less than TCP_SND_WINDOW bytes
        jump        _transmit_not_80
_transmit_80:
        movlw       TCP_SND_WINDOW          ; <== TRANSMIT TCP_SND_WINDOW bytes
_transmit_not_80:
        movwf       TCPS_LEN
        jump        _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       00010000b               ; tcps_flag = 0x11; // SYN+ACK
                                            ; tcp_online=0;
                                            ; http_state=*;
_set_flag_and_send:
        movwf       TCPS_FLAG
        jump        _tcp_send_empty         ; tcp_send_empty(); // 0 byte ÐÅÒÅÄÁÅÍ 0 ÂÁÊÔ


_tcp_syn:
    ;;  j1      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       10010010b               ; http_state=0; // just connected
        movwf       TCPS_FLAG               ; tcps_flag = 0x12; // SYN+ACK
        call        _tcp_send_empty         ; tcp_send_empty(); // ÐÅÒÅÄÁÅÍ 0 ÂÁÊÔ
        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 ge 2
        skip0       <HTTP_UNITIDX,1>
        bsf         PCLATH,0
endif
        movf        IP_POS,W
if FS_INTERNAL_ROM_UNITS ge 1
        skip0       <HTTP_UNITIDX,0>
        iorlw       80h
endif
        movwf       PCL


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

.org 800h
;========================================================================
; JavaScript program for PortB control
;========================================================================
        .db 'H','T','T','P','/','1','.','0',' ','2','0','0', 13, 10, 13, 10
        ; "Content-Type: %s", "blah-blah-blah"
        ; "Content-Length: %d", blah_blah_blah
        ; "Refresh: %d", blah_blah_blah
        .db '<','t','i','t','l','e','>','P','o','r','t',' ','B','<','/','t'
        .db 'i','t','l','e','>','<','b','o','d','y',' ','o','n','L','o','a'
        .db 'd','=','"','f','o','r','(','v','a','r',' ','i','=','0',';','i'
        .db '<','7',';','i','+','+',')','d','o','c','u','m','e','n','t','.'
        .db 'f','o','r','m','s','[','0',']','.','e','l','e','m','e','n','t'
        .db 's','[','i',']','.','c','h','e','c','k','e','d','=','0','x'
        jump        _cgi_portb_hi           ; SIC!
        jump        _cgi_portb_lo
        .db     '&','(','2','<','<','i',')','"','>','<','f','o','r','m',' '

        .db 'a','c','t','i','o','n','=','a','>','<','s','c','r','i','p','t'
        .db '>','f','o','r','(','v','a','r',' ','i','=','1',';','i','<','8'
        .db ';','i','+','+',')','d','o','c','u','m','e','n','t','.','w','r'
        .db 'i','t','e','(','"','B','.','"','+','i','+','"','<','I','N','P'
        .db 'U','T',' ','T','Y','P','E','=','c','h','e','c','k','b','o','x'
        .db '>','<','B','R','>','"',')','<','/','s','c','r','i','p','t','>'
        .db '<','i','n','p','u','t',' ','t','y','p','e','=','s','u','b','m'
        .db 'i','t',' ','v','a','l','u','e','=','R','e','a','d','>','<','i'

        .db 'n','p','u','t',' ','t','y','p','e','=','b','u','t','t','o','n'
        .db ' ','v','a','l','u','e','=','W','r','i','t','e',' ','o','n','C'
        .db 'l','i','c','k','=','"','f','o','r','(','v','a','r',' ','v','='
        .db '4','0','0',',','i','=','0',';','i','<','7',';','v','+','=','d'
        .db 'o','c','u','m','e','n','t','.','f','o','r','m','s','[','0',']'
        .db '.','e','l','e','m','e','n','t','s','[','i',']','.','c','h','e'
        .db 'c','k','e','d','<','<','+','+','i',')',';','t','o','p','.','l'
        .db 'o','c','a','t','i','o','n','.','h','r','e','f','=','v','"','>'

;       .db 'H','T','T','P','/','1','.','0',' ','4','0','4', 13, 10, 13, 10
;       .db 'N','o','t',' ','f','o','u','n','d','<','h','r','>','<','a',' '
;       .db 'h','r','e','f','=','i','>','M','a','i','n',' ','P','a','g','e'
;       .db   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0
;       .db   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0
;       .db   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0
;       .db   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0
;       .db   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0
        .db 'H','T','T','P','/','1','.','0',' ','2','0','0', 13, 10, 13, 10
        .db '<','a',' ','h','r','e','f','=','a','>','P','o','r','t','B',' '
        .db 'c','o','n','t','r','o','l','<','/','a','>','<','h','r','>','<'
        .db 'a',' ','h','r','e','f','=','h','t','t','p',':','/','/','z','h'
        .db 'e','n','g','x','i','.','d','a','.','r','u','>','D','e','n','i'
        .db 's',' ','P','e','t','r','o','v',27h,'s',' ','h','o','m','e',' '
        .db 'p','a','g','e','<','/','a','>',  0,  0,  0,  0,  0,  0,  0,  0
        .db   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0

endif

if FS_USE_EXTERNAL_ROM

_file_read:
        retlw       0

endif

end