serudp.pwp


// PicoWeb Project File

#undef BANNER
#define EEPROM_IP         /* use file "ip" for IP address */
//#define NET_CONFIG_IP     /* allow IP address reconfiguration via net */
#define ENABLE_WATCHDOG   /* use Atmel watchdog timer hardware */
#undef DEBUGGER           /* no debugger...we're using serial port */
//#define DEBUGGER
#define SERIAL_ALWAYS_BINARY

//#define CLOCK 8000000
#define CLOCK 7372000     /* processor clock rate (Hz) */
#define BAUD_RATE 19200   /* serial port baud rate */

#define SEEPROM_CLIENT_ADDR 0x3000
#define PKT_SIZE            256 /* one page */
#define UDP_SOURCE_PORT     99
#define UDP_DEST_PORT       99  /* port on remote host */
#define CLIENT_MAC_UNKNOWN  0xffff


// HTML and images
serudp.htm             // home page

// public CGI routines

//------------------ included AVR assembly language follows ---------------
#avr_reset

#include "udpsend.h"

    pbegin
    pcall reset_client
    pmovwi pkt_index,UDP_DATA+2 ; reset packet index
    pend

#avr_slow

    pbegin
    pcmpwi MEM_ETH_DEST,CLIENT_MAC_UNKNOWN
    pjumpne 99f                 ; we know the client MAC, waive on
    psee2s MEM_IP_DSTADDR,SEEPROM_CLIENT_ADDR,4
    pmemcpy buf,MEM_IP_DSTADDR,4        ; set IP to ARP for
    pcall arp_request           ; ARP for that baby...
99:
    pend

#avr_fast

    pbegin
    pcmpwi MEM_ETH_DEST,CLIENT_MAC_UNKNOWN
    pjumpeq 99f                 ; client mac unknown - bail out

    ppushn xmit_page,1          ; save current page
    pmovb xmit_page,my_enet     ; map my page
;
; drain chars from serial buffer into packet until newline or until
; packet fills, then send.
;
10:
    pser_getc buf               ; get next char
    pjumpeq 97f                 ; no more - bail
    ps2x [pkt_index],buf,1      ; store char to packet
    pincw pkt_index
    pandwi buf,0xff
    pcmpwi buf,'\n'             ; newline?
    pjumpeq 20f                 ; yep - send
    pcmpwi pkt_index,PKT_SIZE   ; did it fill
    pjumplo 10b                 ; no - go for more
20:
    pcall send_and_reset        ; send it and reset index
    pjump 10b                   ; go for more
97:
    ppopn xmit_page,1           ; restore transmit page
99:
    pend

#avr_asm

.pushsection .bss

pkt_hdr:    .skip   2           ; 2-byte header for every packet sent
pkt_index:  .skip   2           ; current packet index - UDP_DATA ... PKT_SIZE
packet_header:  .skip UDP_DATA  ; ether/ip/udp headers

.popsection

.pushsection .data
;
; this is a massive kludge.  this is the last page of the transmit buffer
; that is canonically reserved during initialization of the PicoWeb kernel.
;
; in a future update of the firmware, this buffer can be reserved properly
; so that it cannot be overwritten by a large (> 5*256 byte) transmit
; frame.  for now, as long as no web pages are too big, there is not a
; problem.
;
my_enet:    .byte   0x45        ; my ethernet page

.popsection

send_and_reset:
    pincw pkt_hdr
    ps2x UDP_DATA,pkt_hdr,2     ; store packet header
    pmovwi MEM_UDP_LEN,[pkt_index]  ; compute
    psubwi MEM_UDP_LEN,UDP_DATA     ;  the length
    pjumphis 10f
    pclrw MEM_UDP_LEN           ; < 0 bytes - send zero.
10:
    pcall udp_send              ; send the packet
xmit_reset:
    pmovwi pkt_index,UDP_DATA+2 ; reset packet index
    pret
;+
; **-udp-udp receive handler.
;
; return with ret.
;-

.global import_udp
import_udp:
    pbegin
    pr2s buf,UDP_DP,2           ; get destination port
    pcmpwi buf,BSWAP(UDP_SOURCE_PORT)   ; see if it is our source port
    pjumpne 99f                 ; nope - ignore it
;
; send the data to the serial port.
;

#define PKTP (buf)
#define PKTL (buf+2)
#define PKTC (buf+4)

    pr2s PKTL,UDP_LEN,2         ; get net order UDP length
    pmovwi PKTL,[swap PKTL]     ; swap it
    psubwi PKTL,UDP_HEADER_LEN  ; minus size of UDP header
    pjumplo 99f                 ; nothing there
    pmovwi PKTP,UDP_DATA        ; data pointer
10:
    pr2s PKTC,[PKTP],1          ; get next char
    pputcb PKTC
    pincw PKTP
    pdecw PKTL
    pjumpeq 99f                 ; we''re done
    pjumphis 10b                ; back for more
99:
    pasmret

#undef PKTP
#undef PKTL
#undef PKTC

;+
; **-reset_client-forget about our current client.
;-

reset_client:
    pclrw pkt_hdr
    pmovwi MEM_ETH_DEST,CLIENT_MAC_UNKNOWN
    pret
;+
; **-arp_test_reply-test arp reply.
;
; inputs:
;   MEM_ETH_DEST(word) == CLIENT_MAC_UNKNOWN if we are ARPing
;   arp packet in current receive buffer
;
; outputs:
;   client MAC potentially acquired
;-

arp_test_reply:
    pcmpwi MEM_ETH_DEST,CLIENT_MAC_UNKNOWN  ; were we arping?
    pjumpne 99f                 ; no - toss that baby
    pcmp4 buf,MEM_IP_DSTADDR    ; is it a reply for the right address?
    pjumpne 99f                 ; no - toss it

    pr2s MEM_ETH_DEST,AH_SRCETH,6 ; store the MAC
    pcall xmit_reset            ; flush the buffer
    pjump setup_header          ; set up static header fields
99:
    pret
;+
; **-setup_header-set up static header fields.
;-
setup_header:
    pmemcpy MEM_IP_SRCADDR,my_ip,4          ; source ip == me
    pmovwi MEM_UDP_SP,BSWAP(UDP_SOURCE_PORT)    ;  and source port
    pmovwi MEM_UDP_DP,BSWAP(UDP_DEST_PORT)      ;  and dest port
    pmemcpy MEM_ETH_SRC,my_ether,6      ;   and ether
    
    pmovwi MEM_ETH_PT,0x0008            ; set PT=IP
    pmovwi MEM_IP_HVTOS,0x0045          ; V=4, H=5(*4), TOS=00
    pmovwi MEM_IP_TTLP,0x1101           ; UDP proto and TTL=1
    pmovwi MEM_IP_FFO,0                 ; zero fragment stuff
    pret
;+
; **-icmp_test_destaddr-test if specified address is my client.
;
; pcode routine, exit with flags Z=1 if match
;-

icmp_test_destaddr:
    pcmp4 MEM_IP_DSTADDR,buf        ; compare it
    pret
;+
; **-udp_port_unreachable
;
; inputs:
;   buf = network order UDP port that is unreachable.
;-

udp_port_unreachable:
    pcmpwi buf,BSWAP(UDP_DEST_PORT) ; is it for my destination port?
    pjumpeq reset_client            ; yes - forget this dude!
    pret

#include "arp.asm"
#include "udpsend.asm"
#include "icmp.asm"

Back