X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=boards%2Fsam3x-ek%2Fexamples%2Fsam3x-ek_http_server%2Fmain.c;h=fcce73575d6ec9e0a76f225e53a3f99b42a6b4b5;hb=397b786cf067438239bb1cdbf90d91e3fe2062ee;hp=276265a66418f804a839fefa8766cd32298a4df3;hpb=a40850b888e38a4ff88138639a22bfd373b8af81;p=bertos.git diff --git a/boards/sam3x-ek/examples/sam3x-ek_http_server/main.c b/boards/sam3x-ek/examples/sam3x-ek_http_server/main.c index 276265a6..fcce7357 100644 --- a/boards/sam3x-ek/examples/sam3x-ek_http_server/main.c +++ b/boards/sam3x-ek/examples/sam3x-ek_http_server/main.c @@ -26,21 +26,34 @@ * invalidate any other reasons why the executable file might be covered by * the GNU General Public License. * - * Copyright 2010,2011 Develer S.r.l. (http://www.develer.com/) + * Copyright 2011 Develer S.r.l. (http://www.develer.com/) * * --> * * \author Andrea Righi + * \author Daniele Basile * - * \brief lwIP TCP/IP echo server listening on port 80. + * \brief Simple Http server. + * + * This simple web server read the site's pages from SD card, and manage + * the cases where SD is not present or page not found, using embedded pages. + * Quering from browser some cgi page, the server return a json dictionary. */ -#include "bertos.c" +#include "bitmaps.h" + +#include "hw/hw_http.h" #include "hw/hw_sd.h" #include "hw/hw_adc.h" #include "hw/hw_sdram.h" +#include "hw/hw_led.h" +#include "hw/hw_lcd.h" +// Define logging setting (for cfg/log.h module). +#define LOG_LEVEL 3 +#define LOG_VERBOSITY 0 +#include #include #include @@ -51,9 +64,13 @@ #include #include #include +#include #include #include +#include + +#include #include @@ -63,30 +80,51 @@ #include #include +#include +#include +#include + #include +#include + +#include #include #include +/* Macro to unpack the ip addres from lwip format in 4 int*/ +#define IP_ADDR_TO_INT_TUPLE(addr) \ + (int)((addr) >> 0 & 0xff), \ + (int)((addr) >> 8 & 0xff), \ + (int)((addr) >> 16 & 0xff), \ + (int)((addr) >> 24 & 0xff) + /* Network interface global variables */ static struct ip_addr ipaddr, netmask, gw; static struct netif netif; -// SD fat filesystem context -static Sd sd; -static FATFS fs; -static FatFile in_file; + +#define GET_LED_STATUS(status, led_id) (((status) & BV((led_id))) >> (led_id)) +#define CLEAR_LED_STATUS(status, led_id) ((status) &= ~BV((led_id))) +#define SET_LED_STATUS(status, led_id) ((status) |= BV((led_id))) typedef struct BoardStatus { char local_ip[sizeof("123.123.123.123")]; char last_connected_ip[sizeof("123.123.123.123")]; + uint8_t led_status; uint16_t internal_temp; - ticks_t up_time; + uint32_t up_time; size_t tot_req; } BoardStatus; static BoardStatus status; +static uint8_t raster[RAST_SIZE(LCD_WIDTH, LCD_HEIGHT)]; +static Bitmap *lcd_bitmap; +extern Font font_gohu; +static int lcd_brightness = LCD_BACKLIGHT_MAX; +static struct Heap heap; + static void init(void) { @@ -104,6 +142,28 @@ static void init(void) */ proc_init(); sdram_init(); + dmac_init(); + adc_init(); + + /* Enable the adc to read internal temperature sensor */ + hw_enableTempRead(); + LED_INIT(); + + heap_init(&heap, (void *)SDRAM_BASE, SDRAM_SIZE); + lcd_bitmap = heap_allocmem(&heap, RAST_SIZE(LCD_WIDTH, LCD_HEIGHT)); + if (lcd_bitmap) + kprintf("Allocated memory for display raster, addr 0x%x\n", (unsigned)lcd_bitmap); + else + { + kprintf("Error allocating memory for LCD raster!\n"); + } + + lcd_hx8347_init(); + lcd_setBacklight(lcd_brightness); + + gfx_bitmapInit(lcd_bitmap, raster, LCD_WIDTH, LCD_HEIGHT); + gfx_setFont(lcd_bitmap, &font_luBS14); + lcd_hx8347_blitBitmap(lcd_bitmap); /* Initialize TCP/IP stack */ tcpip_init(NULL, NULL); @@ -112,188 +172,437 @@ static void init(void) netif_add(&netif, &ipaddr, &netmask, &gw, NULL, ethernetif_init, tcpip_input); netif_set_default(&netif); netif_set_up(&netif); +} - dmac_init(); - - adc_init(); - /* Enable the adc to read internal temperature sensor */ - hw_enableTempRead(); +static void sec_to_hms(uint32_t sec_time, uint32_t *h, uint32_t *m, uint32_t *s) +{ + *m = sec_time / 60; + *h = (*m) / 60; + *s = sec_time - ((*m) * 60) - ((*h) * 3600); } -static NORETURN void status_process(void) +static NORETURN void proc_displayRefresh(void) { while (1) { + //LOG_INFO("Refresh display\n"); + uint32_t m; + uint32_t h; + uint32_t s; status.internal_temp = hw_convertToDegree(adc_read(ADC_TEMPERATURE_CH)); - status.up_time++; - timer_delay(1000); + status.up_time += 5; + sec_to_hms(status.up_time, &h, &m, &s); + + text_xprintf(lcd_bitmap, 11, 0, TEXT_FILL, " "); + text_xprintf(lcd_bitmap, 11, 0, 0, "Board ip: %s", status.local_ip); + + text_xprintf(lcd_bitmap, 12, 0, TEXT_FILL, " "); + text_xprintf(lcd_bitmap, 12, 0, 0, "Last connected ip: %s", status.last_connected_ip); + + text_xprintf(lcd_bitmap, 13, 0, TEXT_FILL, " "); + text_xprintf(lcd_bitmap, 13, 0, 0, "Temperature: %d.%dC", status.internal_temp / 10, status.internal_temp % 10); + + text_xprintf(lcd_bitmap, 14, 0, TEXT_FILL, " "); + text_xprintf(lcd_bitmap, 14, 0, 0, "Up time: %ldh %ldm %lds", h, m, s); + + lcd_hx8347_blitBitmap(lcd_bitmap); + lcd_hx8347_blitBitmap24(10, 0, BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, bmp_logo); + + timer_delay(5000); } } -static void get_fileName(char *revc_buf, char *name, size_t len) + +static uint8_t tx_buf[2048]; + +/* + * Return a JSON string of board status. + */ +static int cgi_status(struct netconn *client, const char *name, char *recv_buf, size_t recv_len) +{ + (void)recv_buf; + (void)recv_len; + (void)name; + + status.tot_req++; + uint16_t volt = ADC_RANGECONV(adc_read(1), 0, 3300); + //Update board status. + sprintf(status.last_connected_ip, "%d.%d.%d.%d", IP_ADDR_TO_INT_TUPLE(client->pcb.ip->remote_ip.addr)); + sprintf(status.local_ip, "%d.%d.%d.%d", IP_ADDR_TO_INT_TUPLE(client->pcb.ip->local_ip.addr)); + + sprintf((char *)tx_buf, "{ \"local_ip\":\"%s\",\"last_connected_ip\":\"%s\", \"temp\":%d.%d,\"volt\":%d.%d,\"up_time\":%ld,\"tot_req\":%d, \ +\"leds\":{ \"0\":\"%d\", \"1\":\"%d\", \"2\":\"%d\"}}", + status.local_ip, status.last_connected_ip, + status.internal_temp / 10, status.internal_temp % 10, + volt / 1000, volt % 1000, + status.up_time, status.tot_req, + GET_LED_STATUS(status.led_status, 0), + GET_LED_STATUS(status.led_status, 1), + GET_LED_STATUS(status.led_status, 2)); + + http_sendOk(client, HTTP_CONTENT_JSON); + netconn_write(client, tx_buf, strlen((char *)tx_buf), NETCONN_COPY); + return 0; +} + +static int cgi_logo(struct netconn *client, const char *name, char *recv_buf, size_t recv_len) +{ + (void)recv_buf; + (void)recv_len; + (void)name; + + http_sendOk(client, HTTP_CONTENT_JPEG); + netconn_write(client, bertos_logo_jpg, bertos_logo_jpg_len, NETCONN_NOCOPY); + return 0; +} + +/* + * Return the internal micro temperature string. + */ +static int cgi_temp(struct netconn *client, const char *name, char *recv_buf, size_t recv_len) +{ + (void)recv_buf; + (void)recv_len; + (void)name; + + sprintf((char *)tx_buf, "[%d.%d]", status.internal_temp / 10, status.internal_temp % 10); + + http_sendOk(client, HTTP_CONTENT_JSON); + netconn_write(client, tx_buf, strlen((char *)tx_buf), NETCONN_COPY); + return 0; +} + + +/* + * Return the board uptime. + */ +static int cgi_uptime(struct netconn *client, const char *name, char *recv_buf, size_t recv_len) { - char *p = strstr(revc_buf, "GET"); - if (p) + (void)recv_buf; + (void)recv_len; + (void)name; + + uint32_t m; + uint32_t h; + uint32_t s; + sec_to_hms(status.up_time, &h, &m, &s); + + sprintf((char *)tx_buf, "[\"%ldh %ldm %lds\"]", h, m, s); + + http_sendOk(client, HTTP_CONTENT_JSON); + netconn_write(client, tx_buf, strlen((char *)tx_buf), NETCONN_COPY); + return 0; +} + +/* + * Return the VR1 potentiometer voltage. + */ +static int cgi_resistor(struct netconn *client, const char *name, char *recv_buf, size_t recv_len) +{ + (void)recv_buf; + (void)recv_len; + (void)name; + + uint16_t volt = ADC_RANGECONV(adc_read(1), 0, 3300); + kprintf("volt %d\n", volt); + sprintf((char *)tx_buf, "[ \"%d.%dV\" ]", volt / 1000, volt % 1000); + + http_sendOk(client, HTTP_CONTENT_JSON); + netconn_write(client, tx_buf, strlen((char *)tx_buf), NETCONN_COPY); + return 0; +} + + +#define CGI_LED_ID_KEY "n" +#define CGI_LED_CMD_KEY "set" + +static char key_value[80]; + +/* + * Reply to client the request string. + */ +static int cgi_led(struct netconn *client, const char *name, char *recv_buf, size_t recv_len) +{ + (void)recv_buf; + (void)recv_len; + (void)name; + + char *query_str = strstr(name, "?") + 1; + size_t query_str_len = strlen(query_str); + int led_id; + int led_cmd; + + int len = http_tokenizeGetRequest(query_str, query_str_len); + + LOG_INFO("Found %d key/value pair\n", len); + + if (http_getValue(query_str, query_str_len, CGI_LED_ID_KEY, key_value, sizeof(key_value)) < 0) { - //skip the "/" in get string request - p += sizeof("GET") + 1; - for (size_t i = 0; *p != ' '; i++,p++) - { - if (i > len) - break; - name[i] = *p; - } + LOG_ERR("key %s, not found\n", CGI_LED_ID_KEY); + goto error; + } + + LOG_INFO("Found key %s = %s\n", CGI_LED_ID_KEY, key_value); + led_id = atoi(key_value); + + + if (http_getValue(query_str, query_str_len, CGI_LED_CMD_KEY, key_value, sizeof(key_value)) < 0) + { + LOG_ERR("key %s, not found\n", CGI_LED_CMD_KEY); + goto error; } + + LOG_INFO("Found key %s = %s\n", CGI_LED_CMD_KEY, key_value); + led_cmd = atoi(key_value); + + if (led_cmd) + { + LED_ON(led_id); + SET_LED_STATUS(status.led_status, led_id); + } + else + { + LED_OFF(led_id); + CLEAR_LED_STATUS(status.led_status, led_id); + } + + sprintf((char *)tx_buf, "{\"n\":%d, \"set\":,%d}", led_id, led_cmd); + + http_sendOk(client, HTTP_CONTENT_JSON); + netconn_write(client, tx_buf, strlen((char *)tx_buf), NETCONN_COPY); + return 0; + +error: + http_sendInternalErr(client, HTTP_CONTENT_JSON); + return 0; } -static const char http_html_hdr_200[] = "HTTP/1.1 200 OK\r\nContent-type: text/html\r\n\r\n"; -static const char http_html_hdr_404[] = "HTTP/1.1 404 Not Found\r\nContent-type: text/html\r\n\r\n"; +static int cgi_ledStatus(struct netconn *client, const char *name, char *recv_buf, size_t recv_len) +{ + (void)recv_buf; + (void)recv_len; + (void)name; + + sprintf((char *)tx_buf, "{ \"0\":\"%d\", \"1\":\"%d\", \"2\":\"%d\"}", + GET_LED_STATUS(status.led_status, 0), + GET_LED_STATUS(status.led_status, 1), + GET_LED_STATUS(status.led_status, 2)); + + http_sendOk(client, HTTP_CONTENT_JSON); + netconn_write(client, tx_buf, strlen((char *)tx_buf), NETCONN_COPY); + return 0; +} -static const char http_file_not_found[] = "\ - \ - \ -404 Not Found

404 Not Found

\ -

The requested URL was not found on this server.


\ -
BeRTOS simple HTTP server
"; +#define CGI_MSG_CMD_KEY "msg" -static const char http_sd_not_present[] = " \ - \ - \ -BeRTOS simple HTTP Server \ -

BeRTOS simple HTTP Server

Simple Http server, the site's pages are stored on SD card, check it if is present.


\ -www.BeRTOS.org \ -"; +static int cgi_displayMsg(struct netconn *client, const char *name, char *recv_buf, size_t recv_len) +{ + (void)recv_buf; + (void)recv_len; + (void)name; -static uint8_t tx_buf[2048]; + char *query_str = strstr(name, "?") + 1; + size_t query_str_len = strlen(query_str); -#define IP_ADDR_TO_INT_TUPLE(addr) \ - (int)((addr) >> 0 & 0xff), \ - (int)((addr) >> 8 & 0xff), \ - (int)((addr) >> 16 & 0xff), \ - (int)((addr) >> 24 & 0xff) + int len = http_tokenizeGetRequest(query_str, query_str_len); + LOG_INFO("Found %d key/value pair\n", len); -static char file_name[80]; -int main(void) + if (http_getValue(query_str, query_str_len, CGI_MSG_CMD_KEY, key_value, sizeof(key_value)) < 0) + { + LOG_ERR("key %s, not found\n", CGI_MSG_CMD_KEY); + goto error; + } + + LOG_INFO("Found key %s = %s\n", CGI_MSG_CMD_KEY, key_value); + + text_xprintf(lcd_bitmap, 10, 0, TEXT_FILL, " "); + text_xprintf(lcd_bitmap, 10, 0, TEXT_CENTER, "%s", key_value); + + http_sendOk(client, HTTP_CONTENT_JSON); + return 0; + +error: + http_sendInternalErr(client, HTTP_CONTENT_JSON); + return 0; +} + +/* + * Reply to client the request string. + */ +static int cgi_echo(struct netconn *client, const char *name, char *recv_buf, size_t recv_len) { - struct netconn *server; - FRESULT result; + (void)name; - /* Hardware initialization */ - init(); + http_sendOk(client, HTTP_CONTENT_PLAIN); + netconn_write(client, recv_buf, recv_len, NETCONN_COPY); + return 0; +} - proc_new(status_process, NULL, KERN_MINSTACKSIZE * 2, NULL); +/* + * Return to client a string that display the CHIP ID information. + * See datasheet for more detail. + */ +static int cgi_chipInfo(struct netconn *client, const char *name, char *recv_buf, size_t recv_len) +{ + (void)recv_buf; + (void)recv_len; + (void)name; - dhcp_start(&netif); - while (!netif.ip_addr.addr) - timer_delay(DHCP_FINE_TIMER_MSECS); - kprintf("dhcp ok: ip = %d.%d.%d.%d\n", IP_ADDR_TO_INT_TUPLE(netif.ip_addr.addr)); + sprintf((char *)tx_buf, "{ \"core_name\":\"%s\", \"arch_name\":\"%s\", \"sram_size\":\"%s\",\"flash_size\":\"%s\", \"mem_boot_type\":\"%s\" }", + chipid_eproc_name(CHIPID_EPRCOC()), + chipid_archnames(CHIPID_ARCH()), + chipid_sramsize(CHIPID_SRAMSIZ()), + chipid_nvpsize(CHIPID_NVPSIZ()), + chipid_nvptype(CHIPID_NVTYP())); - server = netconn_new(NETCONN_TCP); - netconn_bind(server, IP_ADDR_ANY, 80); - netconn_listen(server); + http_sendOk(client, HTTP_CONTENT_JSON); + netconn_write(client, tx_buf, strlen((char *)tx_buf), NETCONN_COPY); - while (1) + return 0; +} + + +static int cgi_error(struct netconn *client, const char *name, char *recv_buf, size_t recv_len) +{ + (void)client; + (void)name; + (void)recv_buf; + (void)recv_len; + + return -1; +} + + +/* + * Default function that http server call every client request, if it doesn't match a cgi table. + * In this implementation all client request are associate to real file stored on FAT file + * sistem on SD card. If the file there is not on SD card the server reply to client the + * error File not found, and send an harcoded page. In the same way, the server reply + * error page if the SD card is not present. + * + */ +static int http_htmPageLoad(struct netconn *client, const char *name, char *recv_buf, size_t recv_len) +{ + (void)recv_buf; + (void)recv_len; + + if (SD_CARD_PRESENT()) { - struct netconn *client; - struct netbuf *rx_buf_conn; - char *rx_buf; - u16_t len; - - client = netconn_accept(server); - if (!client) - continue; - - //Update board status. - sprintf(status.local_ip, "%d.%d.%d.%d", IP_ADDR_TO_INT_TUPLE(client->pcb.ip->remote_ip.addr)); - sprintf(status.last_connected_ip, "%d.%d.%d.%d", IP_ADDR_TO_INT_TUPLE(client->pcb.ip->local_ip.addr)); - status.tot_req++; - - rx_buf_conn = netconn_recv(client); - if (rx_buf_conn) + + // SD fat filesystem context + Sd sd; + FATFS fs; + FatFile in_file; + FRESULT result; + + bool sd_ok = sd_init(&sd, NULL, 0); + if (sd_ok) { - netbuf_data(rx_buf_conn, (void **)&rx_buf, &len); - if (rx_buf) + LOG_INFO("Mount FAT filesystem.\n"); + result = f_mount(0, &fs); + if (result != FR_OK) { - memset(file_name, 0, sizeof(file_name)); - memset(tx_buf, 0, sizeof(tx_buf)); - - get_fileName(rx_buf, file_name, sizeof(file_name)); + LOG_ERR("Mounting FAT volumes error[%d]\n", result); + sd_ok = false; + f_mount(0, NULL); + } - kprintf("%s\n", file_name); - if (strlen(file_name) == 0) - strcpy(file_name, "index.htm"); + if (sd_ok) + { + result = fatfile_open(&in_file, name, FA_OPEN_EXISTING | FA_READ); - if (!strcmp("bertos_jpg.jpg", file_name)) + size_t count = 0; + if (result == FR_OK) { - netconn_write(client, bertos_jpg, sizeof(bertos_jpg), NETCONN_NOCOPY); - } - else if (!strcmp("status", file_name)) - { - sprintf((char *)tx_buf, "[ %s, %s, %d.%d, %ld, %d ]", status.local_ip, status.last_connected_ip, - status.internal_temp / 10, status.internal_temp % 10, - status.up_time, status.tot_req); + LOG_INFO("Opened file '%s' size %ld\n", name, in_file.fat_file.fsize); - netconn_write(client, tx_buf, strlen((char *)tx_buf), NETCONN_COPY); - } - else if (SD_CARD_PRESENT()) - { - bool sd_ok = sd_init(&sd, NULL, 0); - if (sd_ok) + int type = http_searchContentType(name); + http_sendOk(client, type); + + while (count < in_file.fat_file.fsize) { - kprintf("Mount FAT filesystem.\n"); - result = f_mount(0, &fs); - if (result != FR_OK) - { - kprintf("Mounting FAT volumes error[%d]\n", result); - sd_ok = false; - f_mount(0, NULL); - } - - if (sd_ok) - { - result = fatfile_open(&in_file, file_name, FA_OPEN_EXISTING | FA_READ); - - size_t count = 0; - if (result == FR_OK) - { - kprintf("Opened file '%s' size %ld\n", file_name, in_file.fat_file.fsize); - - netconn_write(client, http_html_hdr_200, sizeof(http_html_hdr_200) - 1, NETCONN_NOCOPY); - - while (count < in_file.fat_file.fsize) - { - int len = kfile_read(&in_file.fd, tx_buf, sizeof(tx_buf)); - netconn_write(client, tx_buf, len, NETCONN_COPY); - count += len; - } - - kfile_flush(&in_file.fd); - kfile_close(&in_file.fd); - - kprintf("Sent: %d\n", count); - } - else - { - kprintf("Unable to open file: '%s' error[%d]\n", file_name, result); - netconn_write(client, http_html_hdr_404, sizeof(http_html_hdr_404) - 1, NETCONN_NOCOPY); - netconn_write(client, http_file_not_found, sizeof(http_file_not_found) - 1, NETCONN_NOCOPY); - } - } + int len = kfile_read(&in_file.fd, tx_buf, sizeof(tx_buf)); + netconn_write(client, tx_buf, len, NETCONN_COPY); + count += len; } - f_mount(0, NULL); - kprintf("Umount FAT filesystem.\n"); + + kfile_flush(&in_file.fd); + kfile_close(&in_file.fd); + + LOG_INFO("Sent: %d\n", count); } else { - netconn_write(client, http_html_hdr_404, sizeof(http_html_hdr_404) - 1, NETCONN_NOCOPY); - netconn_write(client, http_sd_not_present, sizeof(http_sd_not_present), NETCONN_NOCOPY); + LOG_ERR("Unable to open file: '%s' error[%d]\n", name, result); + http_sendFileNotFound(client, HTTP_CONTENT_HTML); + netconn_write(client, http_file_not_found, http_file_not_found_len - 1, NETCONN_NOCOPY); } } - netconn_close(client); - netbuf_delete(rx_buf_conn); } - netconn_delete(client); + f_mount(0, NULL); + LOG_INFO("Umount FAT filesystem.\n"); + } + else + { + http_sendFileNotFound(client, HTTP_CONTENT_HTML); + netconn_write(client, http_sd_not_present, http_sd_not_present_len, NETCONN_NOCOPY); + } + + return 0; +} + + +/* + * Static cgi table where we associate callback to page. + */ +static HttpCGI cgi_table[] = +{ + { CGI_MATCH_NAME, "echo", cgi_echo }, + { CGI_MATCH_NAME, "get_temperature", cgi_temp }, + { CGI_MATCH_NAME, "get_uptime", cgi_uptime }, + { CGI_MATCH_NAME, "get_resistor", cgi_resistor }, + { CGI_MATCH_NAME, "set_led", cgi_led }, + { CGI_MATCH_NAME, "get_ledStatus", cgi_ledStatus }, + { CGI_MATCH_NAME, "error", cgi_error }, + { CGI_MATCH_NAME, "status", cgi_status }, + { CGI_MATCH_NAME, "get_chipinfo", cgi_chipInfo }, + { CGI_MATCH_NAME, "display", cgi_displayMsg }, + { CGI_MATCH_NAME, "bertos_logo_jpg", cgi_logo }, + { CGI_MATCH_NONE, NULL, NULL } +}; + + +int main(void) +{ + struct netconn *server; + + /* Hardware initialization */ + init(); + http_init(http_htmPageLoad, cgi_table); + + proc_new(proc_displayRefresh, NULL, KERN_MINSTACKSIZE * 2, NULL); + + dhcp_start(&netif); + while (!netif.ip_addr.addr) + timer_delay(DHCP_FINE_TIMER_MSECS); + + sprintf(status.local_ip, "%d.%d.%d.%d", IP_ADDR_TO_INT_TUPLE(netif.ip_addr.addr)); + sprintf(status.last_connected_ip, "%d.%d.%d.%d", IP_ADDR_TO_INT_TUPLE(0)); + kprintf("dhcp ok: ip = %s", status.local_ip); + + text_xprintf(lcd_bitmap, 12, 0, 0, "Board ip: %s", status.local_ip); + + lcd_hx8347_blitBitmap(lcd_bitmap); + lcd_hx8347_blitBitmap24(12, 0, BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, bmp_logo); + + server = netconn_new(NETCONN_TCP); + netconn_bind(server, IP_ADDR_ANY, 80); + netconn_listen(server); + + while (1) + { + http_poll(server); } }