📄 picweb.c
字号:
/* 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 + -