⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 picweb.c

📁 《嵌入式系统 Web 服务器:TCP/IP Lean》
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Miniature Web server for PIC 16c76 Copyright (c) Iosoft Ltd 2000
**
** This software is only licensed for distribution with the book 'TCP/IP Lean',
** and may only be used for personal experimentation by the purchaser
** of that book, on condition that this copyright notice is retained.
** For commercial licensing, contact license@iosoft.co.uk
**
** This is experimental software; use it entirely at your own risk */

/* Revisions:
** v0.01 JPB 28/2/00
** v0.02 - v0.27 deleted to save space
** v0.28 JPB 9/5/00  Added run-time variable substitution
** v0.29 JPB 11/5/00 Added temperature variable
** v0.30 JPB 11/5/00 Added time-setting capability
** v0.31 JPB 12/5/00 Added provision for analogue temperature sensor
**                   Added digital O/Ps
** v0.32 JPB 16/5/00 Changed from 100ms to 50ms ticks
** v0.33 JPB 18/5/00 Removed analogue temp sensor, added PORT A digital I/Ps 
** v0.34 JPB 4/6/00  Added PORT B invert capability
*/

#define TXDROP   0          // Set to 4 to drop 1-in-4 Tx frames for test
#define PORTBINV 0          // Set to 1 to invert port B O/Ps

#include <16c76.h>          // CPU definitions, must be followed by..
#device *=16                             // ..enable 16-bit (!) data pointers
#FUSES HS,NOWDT,NOPROTECT,PUT,BROWNOUT   // PIC fuse settings
#ID CHECKSUM                             // ID bytes are checksum
#ZERO_RAM                                // Wipe RAM for safety

#use DELAY(CLOCK=7372800)   // CPU clock frequency 7.3728 MHz
#use RS232 (BAUD=38400, XMIT=PIN_C6, RCV=PIN_C7, RESTART_WDT, ERRORS)
#bit TX_READY =      0x98.1 // Tx ready status bit

#define WORD unsigned long  // Data type definitions
#define BOOL short          // 'short' is very short (1 bit) in this compiler
typedef union               // Longword definition (not a native type)
{
    BYTE b[4];
    WORD w[2];
    BYTE l;
} LWORD;

#define PCOL_ICMP   1       // IP protocol values
#define PCOL_TCP    6
#define IPHDR_LEN   20      // IP, ICMP and TCP header lengths
#define TCPHDR_LEN  20
#define ICMPHDR_LEN 4       // Only include type, code & checksum in ICMP hdr

BYTE ipcol;                 // IP protocol byte
LWORD local, remote;        // Local & remote IP addresses
WORD locport, remport;      // ..and TCP port numbers
LWORD rseq, rack;           // TCP sequence & acknowledge values
WORD concount;              // Connection count (for high word of my seq num)
BYTE rflags, tflags;        // Rx and Tx flags
signed long iplen;          // Incoming IP length word
WORD rpdlen;                // Length of user data in incoming Rx packet
WORD tpdlen;                // Length of user data in outgoing Tx packet
BYTE portval;               // Value of port B O/Ps
BYTE hashmask, barmask;     // Mask values for EGI '#' and '|' variables
BOOL inv_byte;              // Flag to 'invert' the HTML O/P for EGI vars

#include <ctype.h>
#include "\picc\io\picslip.h"   // Include SLIP I/O functions (no linker!)
#include "\picc\io\pictcp.h"    // ..and TCP functions
#include "\picc\io\webrom.h"    // ..and ROM filesystem definitions

#use fast_io(A)             // I'll set the direction bits on I/O ports
#use fast_io(B)
#use fast_io(C)

#byte   PORTA=5             // Main I/O ports
#byte   PORTB=6
#byte   PORTC=7
#define ALL_OUT     0       // Direction (TRIS) values
#define ALL_IN      0xff

// Timer 1 trigger value; tick time = (1024 x DIV) / CPU_CLK
// 50 ms ticks with 7.3728 MHz clock requires divisor 45 prescale 8
#define TIMER1_DIV   45
#define TIMER1_SET   (T1_INTERNAL | T1_DIV_BY_8)

#use I2C (MASTER, SDA=PIN_C4, SCL=PIN_C3, RESTART_WDT, FAST)
#define SENSOR_ADDR  0x9e   // i2c addr for temperature sensor
#define EEROM_ADDR   0xa0   // i2c addr for eerom
#define RTC_ADDR     0xa2   // i2c addr for real-time clock

#define DIAG_LED     PIN_C2 // Diagnostic LED Pin ident

#define TFIN        0x01    // Option flags: no more data
#define TSYN        0x02    //           sync sequence nums
#define TRST        0x04    //           reset connection
#define TPUSH       0x08    //           push buffered data
#define TACK        0x10    //           acknowledgement
#define TURGE       0x20    //           urgent

#define DAYPORT     13      // TCP Port numbers: daytime & HHTP
#define HTTPORT     80

#define LEDONTIME   2       // Ticks for LED on
#define LEDOFFTIME  100     // Ticks for LED off
BOOL ledon;                 // Diagnostic LED state
int ledonticks, ledoffticks;// LED tick counts
int tickcount;              // Timer tick count

#define DAYTIME_LEN     10  // Format string for daytime response
#define DAYTIME_STR     "%02x:%02x:%02x\r\n"

#define HTTP_FAIL_LEN   34  // HTTP string for internal error
#define HTTP_FAIL       "HTTP/ 200 OK\r\n\r\nPICWEB ROM error\r\n"

#define HTML_OK_LEN     44  // HTTP header for HTML text
#define HTML_OK         "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n"

#define TEXT_OK_LEN     45  // HTTP header for plain text
#define TEXT_OK         "HTTP/1.0 200 OK\r\nContent-type: text/plain\r\n\r\n"

#define MAXFILES    100     // Limit on ROM file count (to stop runaway)
typedef union               // ROM file directory entry format
{
    ROM_FNAME f;                // Union of filename..
    BYTE b[sizeof(ROM_FNAME)];  // ..with byte values for i2c transfer
} ROM_DIR;

ROM_DIR romdir;             // Storage for one directory entry
int fileidx;                // Index of current file (1=first, 0=error)

typedef struct
{                           // Real-Time Clock (RTC) register format
    BYTE secs:4, sec10:4;       // BCD seconds
    BYTE mins:4, min10:4;       // BCD minutes
    BYTE hours:4, hour10:4;     // BCD hours
} RTC_DATA;
typedef union
{                           // Union of RTC registers..
    RTC_DATA d;
    BYTE b[3];              // ..with byte data for i2c transfer
} RTC_DATA_B;

RTC_DATA_B rtc;             // Storage for current time from RTC
BYTE templo, temphi;        // Storage for current temperature (hi/lo bytes)

/* Protoypes */
void daytime_rx(void);
BOOL http_rx(void);
void check_formargs(void);
BOOL http_tx(void);
#separate
void tcp_rx(void);
#separate
void tx_poll(void);
void rx_poll(void);
void get_rtc_time(void);
void set_rtc_time(void);
void get_temperature(void);
#separate
BOOL find_file(void);
BOOL open_file(void);
void close_file(void);
BOOL tx_file_byte(void);
void tx_byte_inv(BYTE b);
BOOL geticks(void);
BOOL timeout(int &var, int tout);
void setled(BOOL on);

void main(void)
{
    setup_port_a(NO_ANALOGS);           // No analogue I/Ps
    set_tris_a(ALL_IN);
#if PORTBINV
    PORTB = 0xff;                       // Initialise ports
#else
    PORTB = 0;
#endif        
    PORTC = 0xff;
    set_tris_b(ALL_OUT);                // Port B LEDs
    set_tris_c(0xf8);                   // Port C mostly I/Ps
    setup_timer_1(TIMER1_SET);          // Initialise timer
    geticks();
    setled(1);                          // Diagnostic LED flash on
    enable_interrupts(INT_RDA);         // Enable serial Rx interrupts
    enable_interrupts(GLOBAL);
    // ***** MAIN LOOP ***** //
    while (1)
    {
        restart_wdt();                  // Kick watchdog
        geticks();                      // Get timer ticks
        if (rxin || timeout(ledoffticks, LEDOFFTIME))
            setled(1);
        else if (ledon && timeout(ledonticks, LEDONTIME))
            setled(0);
        if (txflag)                     // If transmitting, send next char
            tx_poll();
        rx_poll();                      // Check for Rx modem commands
        if (rxflag)                     // If frame received..
        {
            rxflag = 0;                 // ..prepare for another
            rxout = 0;
            get_ip();                   // ..and process Rx frame
        }
    }
}

/* Get an IP message; if ping, send response */
BOOL get_ip(void)
{
    BYTE b, hi, lo;
    int n=0;
    BOOL ret=1;

    slipend = checkflag = 0;                        // Clear checksum
    checkhi = checklo = 0;
    if (match_byte(0x45) && skip_byte() &&          // Version, service
        get_word(iplen) && skip_word() &&           // Len, ID
        skip_word() &&  skip_byte() &&              // Frags, TTL
        get_byte(ipcol) && skip_word() &&           // Protocol, checksum
        get_lword(remote.l) && get_lword(local.l) &&// Addresses
        checkhi==0xff && checklo==0xff)             // Checksum OK?
    {
        if (ipcol==PCOL_ICMP && get_ping_req())     // Ping request?
        {
            tpdlen = rpdlen;                        // Tx length = Rx length
            if (!txflag)
            {
                put_ip(tpdlen+ICMPHDR_LEN);         // Send ping reply
                put_ping_rep();
            }
        }
        else if (ipcol==PCOL_TCP && get_tcp())      // TCP segment?
            tcp_rx();                               // Call TCP handler
        else
            discard_data();                         // Unknown; discard it
    }
    else
        discard_data();
    return(ret);
}

/* Handle an incoming TCP segment */
#separate
void tcp_rx(void)
{
    BYTE *p, *q;
    BOOL tx=1;

    tpdlen = 0;                         // Assume no Tx data
    tflags = TACK;                      // ..and just sending an ack
    if (txflag || (rflags & TRST))      // RESET received, or busy?
        tx = 0;                         //..do nothing
    else if (rflags & TSYN)             // SYN received?
    {
        inc_lword(rseq.l);              // Adjust Tx ack for SYN
        if (locport==DAYPORT || locport==HTTPORT)
        {                               // Recognised port?
            rack.w[0] = 0xffff;
            rack.w[1] = concount++;
            tflags = TSYN+TACK;         // Send SYN ACK
        }
        else                            // Unrecognised port?
            tflags = TRST+TACK;         // Send reset
    }
    else if (rflags & TFIN)             // Received FIN?
        add_lword(rseq.l, rpdlen+1);    // Ack all incoming data + FIN
    else if (rflags & TACK)             // ACK received?
    {
        if (rpdlen)                     // Adjust Tx ack for Rx data
            add_lword(rseq.l, rpdlen);
        else                            // If no data, don't send ack
            tx = 0;
        if (locport==DAYPORT && rack.w[0]==0)
        {                               // Daytime request?
            daytime_rx();               // Send daytime data
            tx = 0;
        }
        else if (locport==HTTPORT && rpdlen)
        {                               // HTTP 'get' method?
            if (http_rx())              // Send HTTP data & close
                tx = 0;
            else                        // ..or just close connection
                tflags = TFIN+TACK;
        }
    }
    if (tx)                             // If ack to send..
    {
        put_ip(TCPHDR_LEN);             // ..send IP header
        checkhi = checklo = 0;          // ..reset checksum
        put_tcp();                      // ..send TCP header
    }
}

/* Handle an incoming daytime request */
void daytime_rx()
{
    tpdlen = DAYTIME_LEN;               // Data length of response
    get_rtc_time();                     // Read clock
    put_ip(TCPHDR_LEN+tpdlen);          // Send IP header
    checkhi = checklo = 0;              // Reset checksum
    txin = IPHDR_LEN + TCPHDR_LEN;      // O/P data to buffer, calc checksum
    printf(put_byte, DAYTIME_STR, rtc.b[2], rtc.b[1], rtc.b[0]);
    txin = IPHDR_LEN;                   // Go back to end of IP header
    tflags = TFIN+TACK;                 // O/P TCP header
    put_tcp();
}

/* Receive an incoming HTTP request ('method'), return 0 if invalid */
BOOL http_rx(void)
{
    int len, i;
    BOOL ret=0;
    char c;

    tpdlen = 0;                         // Check for 'GET'
    if (match_byte('G') && match_byte('E') && match_byte('T'))
    {
        ret = 1;
        skip_space();
        match_byte('/');                // Start of filename
        if (rxbuff[rxout] == '$')       // If dummy file starting wth '$'
        {
                                        // ..put out simple text string
            tpdlen = TEXT_OK_LEN + DAYTIME_LEN;
            get_rtc_time();             // ..consisting of current time
            put_ip(TCPHDR_LEN+tpdlen);
            checkhi = checklo = 0;
            txin = IPHDR_LEN + TCPHDR_LEN;
            printf(put_byte, TEXT_OK);  // ..with HTTP header
            printf(put_byte, DAYTIME_STR, rtc.b[2], rtc.b[1], rtc.b[0]);
            txin = IPHDR_LEN;
            tflags = TFIN+TPUSH+TACK;
            put_tcp();
        }
        else
        {                               // Get filename into directory buffer
            for (i=0; i<ROM_FNAMELEN; i++)
            {
                c = rxbuff[rxout];
                if (c>' ' && c!='?')    // Name terminated by space or '?'
                    rxout++;
                else
                    c = 0;
                romdir.f.name[i] = c;
            }                           // If file found in ROM
            if (find_file())
            {                           // ..check for form arguments
                check_formargs();
            }
            else                        // File not found, get index.htm
            {
                romdir.f.name[0] = 0;
                find_file();
            }
            if (!fileidx)               // No files at all in ROM - disaster!
            {
                tpdlen = HTTP_FAIL_LEN;     // Inform user of failure..
                put_ip(TCPHDR_LEN+tpdlen);  // Output IP header to buffer
                checkhi = checklo = 0;      // Reset checksum
                strcpy(&txbuff[IPHDR_LEN+TCPHDR_LEN], HTTP_FAIL);
                txin = IPHDR_LEN + TCPHDR_LEN;
                check_txbytes(tpdlen);      // Checksum data
                txin = IPHDR_LEN;           // Go back to end of IP header
                tflags = TFIN+TPUSH+TACK;
                put_tcp();                  // Output TCP header to buffer
            }
            else                        // File found OK
            {
                tpdlen = romdir.f.len;      // Get TCP data length
                put_ip(TCPHDR_LEN+tpdlen);  // Output IP header to buffer
                checkhi = checklo = 0;      // Reset checksum
                check_byte(romdir.f.check); // Add on checksum on ROM file
                check_byte(romdir.f.check >> 8);
                tflags = TFIN+TPUSH+TACK;   // Close connection when sent
                txi2c = 1;                  // Set flag to enable ROM file O/P
                put_tcp();                  // Output TCP header to buffer
            }
        }
    }
    return(ret);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -