sertcp.pwp


//
// PicoWeb Project File "sertcp"
//
// This project has no Web pages.  It instead uses a special user-defined
// TCP/IP port to send data to the serial port and/or receive data from
// the serial port.
// 
// Each time a packet is received for the special TCP port any data that it
// contains will be transmitted to the PicoWeb serial port.  Then any data
// waiting in the serial port input queue will be sent back.  The serial port
// queue will be read and any characters found there will be sent back in one
// or more outgoing TCP packets until either (1) the end-of-line character
// is detected (set by #define SER_PORT_EOL_CHAR), (2) an inter-character
// timeout is exceeded (set be #define SER_PORT_TIMEOUT_MSECS), or (3) the
// maximum number of character allowed in a response packet is exceeded (set
// by #define SER_MAX_CHARS 1024).  The #define SER_CLEAR_QUEUE determines
// whether the serial port queue is cleared each time a new packet is
// received.
// 
// Note that there is no "automatic" TCP/IP buffering/retry logic involved
// in these transactions.  Therefore, if the remote host decides it needs to
// retransmit a packet, duplicate packets will be sent to the PicoWeb and
// they will be sent out the serial port.  Likewise, serial data read from
// the serial port can be lost if the TCP/IP packets used to deliver this
// data back to the remote host are lost.  Therefore, to insure "proper"
// adherence to the TCP/IP standard we need to assume that what is being sent
// to the serial port is something like a "command", with length less than
// one Ethernet packet (i.e., <1400 bytes), and that each unique command
// results in a fixed-length response from a device on the serial port.
// The length of this response should be less than the TCP/IP window
// size (typically <8 Kbytes).  With these "rules", if the remote host's
// TCP/IP stack decides it needs retransmit an Ethernet packet, it will
// get more-or-less the same response back.  Note that if the serial
// port "response packet" is kept under one packet in length, then a
// variable-length response can be returned.
// 
// Testing:
// 
// The following can be used to send/read data from a PicoWeb loaded with
// this project:
// 
//    httpget -r -S "Hello world!\r\n" 10.1.2.3:1000
// 
// Note the PicoWeb is at IP address 10.1.2.3 in the above example.
// The ":1000" specified TCP port 1000 (defined in the project using
// define SEND_CMD_PORT).  You need the "-r and -S" switches before the
// "command" string.  Note the "\r" and "\n" in the command string which
// calls out a CR and LF.
//
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// NOTE!! Sending a zero-length packet to the PicoWeb causes the
//        PicoWeb to very quietly ignore the packet!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// 

#define EEPROM_IP         /* IP address stored in EEPROM */
#define NET_CONFIG_IP     /* allow IP address reconfiguration via net */
#define ENABLE_WATCHDOG
#undef DEBUGGER           /* no debugger...we're using serial port */

//#define CLOCK 8000000
#define CLOCK 7372000
#define BAUD_RATE 19200

#define BLINK_LED     /* will blink PicoWeb LED on TCP serial I/O */

#define UNKNOWN_TCP_PORT_HANDLER our_tcp_handler

#define SEND_CMD_PORT 1000     /* port to send pure binary data */
#define SEND_TCMD_PORT 999     /* port to send URL-style %XX quoted data */

#define SER_PORT_TIMEOUT_MSECS 1000  /* serial port input timeout */
#define SER_PORT_EOL_CHAR  0x0d  /* serial input end-of-line character */
                                 /* don't define for no EOL processing */

#define SER_MAX_CHARS 1024   /* max. characters allowed in response packet */

#define SER_CLEAR_QUEUE /* define to clear input queue before each burst out */

// HTML and images

// public CGI routines

// linker directives (search or add)

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

#define putchar_serial pmovbi putc_b,0
#define putchar_net    pmovbi putc_b,1
#define serial_binary  pser_mode 1
#define serial_normal  pser_mode 0

#ifdef BLINK_LED
#define LED_ON  cbi portd,LED_BIT     /* turn LED on */
#define LED_OFF sbi portd,LED_BIT     /* turn LED off */
#define PLED_ON  pledon               /* turn LED on with pcode */
#define PLED_OFF pledoff               /* turn LED off with pcode */
    sbi     DDRD,LED_BIT      ; make LED driver pin an output
    LED_OFF                   ; turn LED off
#else /* !BLINK_LED */
#define LED_ON
#define LED_OFF
#define PLED_ON
#define PLED_OFF
#endif /* !BLINK_LED */

.cseg
    serial_binary                      ; serial port to binary mode (clears queue)
.eseg

#avr_slow

.cseg
.eseg

#avr_fast

#avr_asm

#ifdef BLINK_LED
pledon:    pcode_routine   0
    LED_ON
    ret

pledoff:   pcode_routine   0
    LED_OFF
    ret
#endif /* BLINK_LED */

;
; serdev_copynet
;
; loop reading chars from the serial buffer and writing to ''net until
; CR encountered (or timeout)
;
.cseg
serdev_copynet:
    pmovwi buf+2,SER_MAX_CHARS         ; zero max. character counter
serdev_copynet_loop:
                                       ; get char from serial port with TO
    psgetcto buf,PSGETCTO_MSECS(SER_PORT_TIMEOUT_MSECS)
    pjumpeq serdev_copydone            ; no more chars!
#ifdef SER_PORT_EOL_CHAR 
    pcmpbi buf,SER_PORT_EOL_CHAR       ; check for EOL character (exit if found)
    pjumpeq serdev_copydone
#endif
    pputcb buf                         ; output character
    pdecw buf+2                        ; decrement character counter
    pjumpeq serdev_copydone            ; exit now if counter hit zero
    pjump serdev_copynet_loop          ; back for more
serdev_copydone:
    pret

;
; Our handler for unknown TCP ports
;
#define MY_TCP_OFFSET buf
#define MY_TCP_LEN    buf+2
#define MY_TCP_CHAR   buf+4

.cseg
our_tcp_handler:
    pcmpwi buf,BSWAP(SEND_CMD_PORT) ; check for our special TCP port
    pjumpeq tcp_send_cmd            ; process TCP packet if ours
#ifdef SEND_TCMD_PORT
    pcmpwi buf,BSWAP(SEND_TCMD_PORT); check for our special TCP port
    pjumpeq tcp_send_tcmd           ; process TCP packet if ours
#endif
    pret                            ; not for us...exit

#ifdef SEND_TCMD_PORT
tcp_send_tcmd:
    pcall tcp_enable_serial         ; enable serial port
    pmovwi MY_TCP_OFFSET,[data_addr]; get start of TCP packet data
    pprinturl MY_TCP_OFFSET,1       ; send URL-style "quoted" data
    pjump tcp_send_response         ; copy serial port input to net and exit
#endif

tcp_enable_serial:
    PLED_ON
    ppushn putcok,1                 ; enable output after saving state
    pmovbi putcok,1
    putchar_serial                  ; switch putchar to serial port
#ifdef SER_CLEAR_QUEUE
    serial_binary                   ; serial port to binary mode (clears queue)
#endif
    pret

tcp_send_cmd:
    pcall tcp_enable_serial         ; enable serial port
    pmovwi MY_TCP_OFFSET,[data_addr]; get start of TCP packet data
    pmovwi MY_TCP_LEN,[data_len]    ; get length of TCP packet data
    pcmpwi MY_TCP_LEN,0             ; zero?
  ;;;pprintv "MY_TCP_LEN=",[MY_TCP_LEN]
  ;;;pcrlf
    pjumpeq tcp_send_response       ; yes...early exit

tcp_send_raw:
    pr2s MY_TCP_CHAR,[MY_TCP_OFFSET],1; get next byte
    pputcb MY_TCP_CHAR              ; write character to serial port
    pincw MY_TCP_OFFSET             ; bump receive packet pointer
    pdecw MY_TCP_LEN                ; decrement count
    pjumpne tcp_send_raw            ; back for more if non-zero

tcp_send_response:
    putchar_net                     ; switch putchar back to ''net
    pcall serdev_copynet            ; copy serial port input to net
    ppopn putcok,1                  ; restore state
    PLED_OFF
    pret


Back