mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-08-30 14:52:51 +08:00
Add POST code for firmware update
This commit is contained in:
+228
-26
@@ -7,6 +7,9 @@
|
|||||||
#include "uip.h"
|
#include "uip.h"
|
||||||
#include "../html_data.h"
|
#include "../html_data.h"
|
||||||
|
|
||||||
|
// Upload Firmware to 1M
|
||||||
|
#define FIRMWARE_UPLOAD_START 0x100000
|
||||||
|
|
||||||
#define CMARK_S 6
|
#define CMARK_S 6
|
||||||
|
|
||||||
#pragma codeseg BANK1
|
#pragma codeseg BANK1
|
||||||
@@ -15,6 +18,10 @@ extern __code struct f_data f_data[];
|
|||||||
extern __code fcall_ptr f_calls[];
|
extern __code fcall_ptr f_calls[];
|
||||||
extern __code char * __code mime_strings[];
|
extern __code char * __code mime_strings[];
|
||||||
|
|
||||||
|
// Flash buffer to optimize flash writing speed, write_len is the current filling position
|
||||||
|
extern __xdata uint8_t flash_buf[512];
|
||||||
|
__xdata uint16_t write_len;
|
||||||
|
|
||||||
__xdata uint8_t outbuf[TCP_OUTBUF_SIZE];
|
__xdata uint8_t outbuf[TCP_OUTBUF_SIZE];
|
||||||
__xdata uint8_t entry;
|
__xdata uint8_t entry;
|
||||||
__xdata uint16_t slen;
|
__xdata uint16_t slen;
|
||||||
@@ -22,11 +29,21 @@ __xdata uint16_t o_idx;
|
|||||||
__xdata uint16_t mpos;
|
__xdata uint16_t mpos;
|
||||||
__xdata uint16_t len_left;
|
__xdata uint16_t len_left;
|
||||||
|
|
||||||
|
// HTTP header properties
|
||||||
|
__xdata uint8_t boundary[72];
|
||||||
|
__xdata uint8_t *content_type = 0;
|
||||||
|
|
||||||
|
// Global variables holding POST state
|
||||||
|
__xdata uint32_t uptr; // Current flash write position
|
||||||
|
__xdata uint16_t bindex; // Current index into the boundary
|
||||||
|
|
||||||
|
__xdata uint16_t short_parsed;
|
||||||
|
|
||||||
#define TSTATE_NONE 0
|
#define TSTATE_NONE 0
|
||||||
#define TSTATE_TX 1
|
#define TSTATE_TX 1
|
||||||
#define TSTATE_ACKED 2
|
#define TSTATE_ACKED 2
|
||||||
#define TSTATE_CLOSED 3
|
#define TSTATE_CLOSED 3
|
||||||
|
#define TSTATE_POST 4
|
||||||
|
|
||||||
|
|
||||||
inline uint8_t is_separator(uint8_t c)
|
inline uint8_t is_separator(uint8_t c)
|
||||||
@@ -46,7 +63,7 @@ void httpd_init(void) __banked
|
|||||||
|
|
||||||
uint8_t find_entry(__xdata uint8_t * __xdata e)
|
uint8_t find_entry(__xdata uint8_t * __xdata e)
|
||||||
{
|
{
|
||||||
register uint8_t i, j;
|
__xdata uint8_t i, j;
|
||||||
|
|
||||||
for (i = 0; f_data[i].len; i++) {
|
for (i = 0; f_data[i].len; i++) {
|
||||||
j = 0;
|
j = 0;
|
||||||
@@ -65,9 +82,8 @@ char strcmp(__xdata uint8_t * __xdata c, __code uint8_t * __xdata d)
|
|||||||
{
|
{
|
||||||
register uint8_t i = 0;
|
register uint8_t i = 0;
|
||||||
|
|
||||||
while (d[i] && (d[i] == c[i])) {
|
while (d[i] && (d[i] == c[i]))
|
||||||
i++;
|
i++;
|
||||||
}
|
|
||||||
|
|
||||||
if (c[i] < d[i])
|
if (c[i] < d[i])
|
||||||
return -1;
|
return -1;
|
||||||
@@ -77,15 +93,47 @@ char strcmp(__xdata uint8_t * __xdata c, __code uint8_t * __xdata d)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint8_t parse_short(register uint16_t *n, __xdata uint8_t * __xdata p)
|
char is_word(__xdata uint8_t * __xdata c, __code uint8_t * __xdata d)
|
||||||
|
{
|
||||||
|
register uint8_t i = 0;
|
||||||
|
|
||||||
|
while (d[i] && (d[i] == c[i]))
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (d[i])
|
||||||
|
return 0;
|
||||||
|
if (c[i] != ' ' && c[i] != '\t' && c[i] != ':' && c[i] != '?' && c[i] != '=' && c[i] != '\n' && c[i] != '\r' && c[i])
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char is_word_x(__xdata uint8_t * __xdata c, __xdata uint8_t *d)
|
||||||
|
{
|
||||||
|
register uint8_t i = 0;
|
||||||
|
|
||||||
|
while (d[i] && (d[i] == c[i]))
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (d[i])
|
||||||
|
return 0;
|
||||||
|
if (c[i] != ' ' && c[i] != '\t' && c[i] != ':' && c[i] != '?' && c[i] != '=' && c[i] != '\n' && c[i] != '\r' && c[i])
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t parse_short(__xdata uint8_t *p)
|
||||||
{
|
{
|
||||||
uint8_t err = 1;
|
uint8_t err = 1;
|
||||||
*n = 0;
|
uint8_t c = 0;
|
||||||
|
|
||||||
while (*p >= '0' && *p <= '9') {
|
short_parsed = 0;
|
||||||
|
while(1) {
|
||||||
|
c = *p++ - '0';
|
||||||
|
if (c > 9) { break; }
|
||||||
err = 0;
|
err = 0;
|
||||||
*n = (*n * 10) + *p - '0';
|
short_parsed = (short_parsed * 10) + c;
|
||||||
p++;
|
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -93,33 +141,180 @@ uint8_t parse_short(register uint16_t *n, __xdata uint8_t * __xdata p)
|
|||||||
|
|
||||||
void send_not_found(void)
|
void send_not_found(void)
|
||||||
{
|
{
|
||||||
slen = strtox(outbuf, "HTTP/1.1 404 Not found\r\nContent-Type: text/html\r\n\r\n");
|
slen = strtox(outbuf, "HTTP/1.1 404 Not found\r\nContent-Type: text/html\r\n\r\n" \
|
||||||
print_string("slen: "); print_short(slen); write_char('\n');
|
"<!DOCTYPE HTML PUBLIC>\n<title>404 Not Found</title>\n<h1>Not Found</h1>\n");
|
||||||
slen += strtox(outbuf + slen, "<!DOCTYPE HTML PUBLIC>\n<title>404 Not Found</title>\n<h1>Not Found</h1>\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_post(void)
|
|
||||||
|
void send_bad_request(void)
|
||||||
{
|
{
|
||||||
__xdata uint8_t *p = uip_appdata;
|
slen = strtox(outbuf, "HTTP/1.1 400 Bad Request\r\nContent-Type: text/html\r\n\r\n" \
|
||||||
|
"<!DOCTYPE HTML PUBLIC>\n<title>400 Bad Request</title>\n<h1>Bad Request</h1>\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
__xdata uint8_t *skip_boundary(__xdata uint8_t *p)
|
||||||
|
{
|
||||||
|
while (*p) {
|
||||||
|
if (is_word_x(p, boundary))
|
||||||
|
return p + strlen_x(boundary);
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
__xdata uint8_t *scan_header(__xdata uint8_t *p)
|
||||||
|
{
|
||||||
|
content_type = 0;
|
||||||
|
|
||||||
while (*p != '\r' || *(p + 1) != '\n' || *(p + 2) != '\r' || *(p + 3) != '\n') {
|
while (*p != '\r' || *(p + 1) != '\n' || *(p + 2) != '\r' || *(p + 3) != '\n') {
|
||||||
write_char(*p);
|
write_char(*p);
|
||||||
if (!*p++)
|
if (!*p++)
|
||||||
break;
|
break;
|
||||||
|
if (is_word(p, "\nContent-Type:"))
|
||||||
|
content_type = p + 15;
|
||||||
}
|
}
|
||||||
if (!*p) {
|
if (content_type && is_word(content_type, "multipart/form-data; boundary")) {
|
||||||
print_string("No body found!\n");
|
print_string("\nFound multiplart\n");
|
||||||
|
content_type += 30;
|
||||||
|
uint8_t i = 0;
|
||||||
|
while (content_type[i] != '\r' && content_type[i] != '\n') {
|
||||||
|
boundary[i + 2] = content_type[i];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
// The boundary between parts is "--" + the boundary given in the header
|
||||||
|
boundary[0] = '-';
|
||||||
|
boundary[1] = '-';
|
||||||
|
boundary[i + 2] = 0;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reads post data from the http stream and writes it into flash memory
|
||||||
|
* Input: the current position in the TCP buffer (uip_appdata)
|
||||||
|
* Returns 1: More data to read, 0: Upload complete, all parts reads
|
||||||
|
*/
|
||||||
|
uint8_t stream_upload(__xdata uint16_t bptr)
|
||||||
|
{
|
||||||
|
__xdata uint8_t *p = uip_appdata;
|
||||||
|
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
|
||||||
|
|
||||||
|
print_string("Stream_upload called: ");
|
||||||
|
print_short(bptr); write_char('\n');
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (bptr >= uip_len) {
|
||||||
|
s->tstate = TSTATE_POST;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// Have we reached the end of the part?
|
||||||
|
if (!boundary[bindex]) {
|
||||||
|
s->tstate = TSTATE_NONE;
|
||||||
|
print_string("len 2: "); print_short(write_len); write_char(' ');
|
||||||
|
flash_write_bytes(uptr, flash_buf, write_len);
|
||||||
|
uptr += write_len;
|
||||||
|
write_len = 0;
|
||||||
|
// TODO: This is a bit premature, what about a nice web-page saying the device will reset???
|
||||||
|
reset_chip();
|
||||||
|
if (bptr >= uip_len)
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (p[bptr] == boundary[bindex]) {
|
||||||
|
bptr++;
|
||||||
|
bindex++;
|
||||||
|
} else {
|
||||||
|
if (bindex) {
|
||||||
|
memcpy(flash_buf + write_len, boundary, bindex);
|
||||||
|
write_len += bindex;
|
||||||
|
bindex = 0;
|
||||||
|
}
|
||||||
|
flash_buf[write_len++] = p[bptr++];
|
||||||
|
if (write_len >= 256) {
|
||||||
|
print_string("len: "); print_short(write_len); write_char(' ');
|
||||||
|
flash_write_bytes(uptr, flash_buf, write_len);
|
||||||
|
uptr += write_len;
|
||||||
|
write_len = 0;
|
||||||
|
}
|
||||||
|
bindex = 0;
|
||||||
|
}
|
||||||
|
} while(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void handle_post(void)
|
||||||
|
{
|
||||||
|
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
|
||||||
|
__xdata uint8_t *p = uip_appdata;
|
||||||
|
__xdata uint8_t *request_path = p + 6;
|
||||||
|
|
||||||
|
print_string("Is POST\n");
|
||||||
|
p += 5; // Skip post
|
||||||
|
// Find end of request path
|
||||||
|
while (*p && !is_separator(*p))
|
||||||
|
p++;
|
||||||
|
*p = '\0';
|
||||||
|
|
||||||
|
// Find end of request header
|
||||||
|
boundary[0] ='\0';
|
||||||
|
p = scan_header(p + 1);
|
||||||
|
print_string("Boundary: >"); print_string_x(boundary); print_string("<\n");
|
||||||
|
if (!*p || !content_type) {
|
||||||
|
print_string("Bad Request!\n");
|
||||||
send_not_found();
|
send_not_found();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
register uint8_t i = 0;
|
|
||||||
p += 4;
|
|
||||||
while (*p && *p != '\n' && *p != '\r')
|
|
||||||
cmd_buffer[i++] = *p++;
|
|
||||||
cmd_buffer[i] = '\0';
|
|
||||||
|
|
||||||
if (i && !cmd_tokenize())
|
if (is_word(request_path, "cmd")) {
|
||||||
|
register uint8_t i = 0;
|
||||||
|
p += 4;
|
||||||
|
while (*p && *p != '\n' && *p != '\r')
|
||||||
|
cmd_buffer[i++] = *p++;
|
||||||
|
cmd_buffer[i] = '\0';
|
||||||
|
|
||||||
|
if (i && !cmd_tokenize())
|
||||||
cmd_parser();
|
cmd_parser();
|
||||||
|
} else if (is_word(request_path, "upload")) {
|
||||||
|
print_string("POST upload request\n");
|
||||||
|
if (!boundary[0]) {
|
||||||
|
print_string("Bad request, no boundary!\n");
|
||||||
|
send_bad_request();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// We skip the intial parts as part of the header
|
||||||
|
do {
|
||||||
|
p = skip_boundary(p);
|
||||||
|
if (!*p)
|
||||||
|
goto bad_request;
|
||||||
|
p = scan_header(p);
|
||||||
|
if (!*p)
|
||||||
|
goto bad_request;
|
||||||
|
if (!content_type) // We are waiting for the part with the octet stream
|
||||||
|
continue;
|
||||||
|
} while (!is_word(content_type, "application/octet-stream"));
|
||||||
|
print_string("Have content octets\n");
|
||||||
|
p += 4; // Skip \r\n\r\n sequence at end of preamble of part
|
||||||
|
|
||||||
|
uptr = FIRMWARE_UPLOAD_START;
|
||||||
|
bindex = 0;
|
||||||
|
write_len = 0;
|
||||||
|
stream_upload(p - uip_appdata);
|
||||||
|
|
||||||
|
print_string("Done reading first fragment\n");
|
||||||
|
return;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
send_not_found();
|
||||||
|
return;
|
||||||
|
}
|
||||||
slen = strtox(outbuf, "HTTP/1.1 200 OK\r\n\r\n");
|
slen = strtox(outbuf, "HTTP/1.1 200 OK\r\n\r\n");
|
||||||
|
return;
|
||||||
|
bad_request:
|
||||||
|
send_bad_request();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -168,20 +363,28 @@ void httpd_appcall(void)
|
|||||||
print_string("Sending B done\n");
|
print_string("Sending B done\n");
|
||||||
s->tstate = TSTATE_TX;
|
s->tstate = TSTATE_TX;
|
||||||
}
|
}
|
||||||
|
} else if (uip_newdata() && s->tstate == TSTATE_POST) {
|
||||||
|
stream_upload(0);
|
||||||
} else if (uip_newdata() && s->tstate != TSTATE_TX) {
|
} else if (uip_newdata() && s->tstate != TSTATE_TX) {
|
||||||
write_char('<'); print_short(uip_len); write_char('\n');
|
write_char('<'); print_short(uip_len); write_char('\n');
|
||||||
__xdata uint8_t *p = uip_appdata;
|
__xdata uint8_t *p = uip_appdata;
|
||||||
|
// Mark end of request header with \0
|
||||||
p[uip_len] = 0;
|
p[uip_len] = 0;
|
||||||
while (*p)
|
while (*p)
|
||||||
write_char(*p++);
|
write_char(*p++);
|
||||||
write_char('\n');
|
write_char('\n');
|
||||||
p = uip_appdata;
|
p = uip_appdata;
|
||||||
if (p[0] == 'P' && p[1] == 'O' && p[2] == 'S' && p[3] == 'T' && p[4] == ' ') {
|
if (is_word(p, "POST")) {
|
||||||
handle_post();
|
handle_post();
|
||||||
|
// If this is an ongoing post stream, then wait for the next packet
|
||||||
|
if (s->tstate == TSTATE_POST) {
|
||||||
|
uip_len = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
goto do_send;
|
goto do_send;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p[0] == 'G' && p[1] == 'E' && p[2] == 'T' && p[3] == ' ')
|
if (is_word(p, "GET"))
|
||||||
print_string("GET request ");
|
print_string("GET request ");
|
||||||
p += 4;
|
p += 4;
|
||||||
__xdata uint8_t *q = p;
|
__xdata uint8_t *q = p;
|
||||||
@@ -199,9 +402,8 @@ void httpd_appcall(void)
|
|||||||
if (!strcmp(q, "/status.json")) {
|
if (!strcmp(q, "/status.json")) {
|
||||||
send_status();
|
send_status();
|
||||||
} else if (!strcmp(q, "/vlan.json")) {
|
} else if (!strcmp(q, "/vlan.json")) {
|
||||||
__xdata uint16_t vlan;
|
parse_short(q + 15);
|
||||||
parse_short(&vlan, q + 15);
|
send_vlan(short_parsed);
|
||||||
send_vlan(vlan);
|
|
||||||
} else if (!strcmp(q, "/counters.json")) {
|
} else if (!strcmp(q, "/counters.json")) {
|
||||||
send_counters(q[19]-'0');
|
send_counters(q[19]-'0');
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user