implement basic http server
This commit is contained in:
parent
d7cfc0d782
commit
c0e774c08c
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
|||||||
**/build/*
|
**/build/*
|
||||||
**/secret.h
|
**/secret.h
|
||||||
|
**/htmldata.c
|
@ -1,17 +1,21 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
set(PROGRAM_NAME pico_bmc)
|
||||||
|
set(PICO_BOARD pico_w)
|
||||||
include(pico_sdk_import.cmake)
|
include(pico_sdk_import.cmake)
|
||||||
project(bmc)
|
project(pico_bmc)
|
||||||
set(CMAKE_C_STANDARD 11)
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
|
||||||
pico_sdk_init()
|
pico_sdk_init()
|
||||||
add_executable(bmc
|
add_executable(${PROGRAM_NAME}
|
||||||
bmc.c
|
main.c
|
||||||
)
|
)
|
||||||
target_link_libraries(bmc
|
target_include_directories(${PROGRAM_NAME} PRIVATE
|
||||||
pico_stdlib
|
${CMAKE_CURRENT_LIST_DIR}
|
||||||
|
)
|
||||||
|
target_link_libraries(${PROGRAM_NAME}
|
||||||
pico_cyw43_arch_lwip_threadsafe_background
|
pico_cyw43_arch_lwip_threadsafe_background
|
||||||
|
pico_lwip_http
|
||||||
|
pico_stdlib
|
||||||
|
hardware_adc
|
||||||
)
|
)
|
||||||
pico_enable_stdio_usb(bmc 1)
|
pico_enable_stdio_usb(${PROGRAM_NAME} TRUE)
|
||||||
pico_enable_stdio_uart(bmc 0)
|
pico_enable_stdio_uart(${PROGRAM_NAME} FALSE)
|
||||||
pico_add_extra_outputs(bmc)
|
pico_add_extra_outputs(${PROGRAM_NAME})
|
||||||
target_include_directories(bmc PRIVATE ${CMAKE_CURRENT_LIST_DIR})
|
|
15
Makefile
15
Makefile
@ -1,9 +1,16 @@
|
|||||||
TOPTARGETS := all clean
|
#TOPTARGETS := all clean
|
||||||
|
|
||||||
SUBDIRS := $(wildcard */.)
|
SUBDIRS := build
|
||||||
|
|
||||||
|
all: makefsdata $(SUBDIRS)
|
||||||
|
|
||||||
|
makefsdata:
|
||||||
|
python3 makefsdata.py
|
||||||
|
|
||||||
|
clean: $(SUBDIRS)
|
||||||
|
rm -rf htmldata.c
|
||||||
|
|
||||||
$(TOPTARGETS): $(SUBDIRS)
|
|
||||||
$(SUBDIRS):
|
$(SUBDIRS):
|
||||||
$(MAKE) -C $@ $(MAKECMDGOALS)
|
$(MAKE) -C $@ $(MAKECMDGOALS)
|
||||||
|
|
||||||
.PHONY: $(TOPTARGETS) $(SUBDIRS)
|
.PHONY: all makefsdata clean $(SUBDIRS)
|
25
bmc.c
25
bmc.c
@ -1,25 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include "pico/stdlib.h"
|
|
||||||
#include "pico/cyw43_arch.h"
|
|
||||||
#include "secret.h"
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
stdio_init_all();
|
|
||||||
if (cyw43_arch_init()) {
|
|
||||||
printf("Wi-Fi init failed\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
printf("Wi-Fi init succeeded\n");
|
|
||||||
cyw43_arch_enable_sta_mode();
|
|
||||||
if (cyw43_arch_wifi_connect_timeout_ms(ssid, pass, CYW43_AUTH_WPA2_AES_PSK, 10000)) {
|
|
||||||
printf("WiFi failed to connect\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
printf("WiFi connected\n");
|
|
||||||
while (true) {
|
|
||||||
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1);
|
|
||||||
sleep_ms(1000);
|
|
||||||
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0);
|
|
||||||
sleep_ms(1000);
|
|
||||||
}
|
|
||||||
}
|
|
32
cgi.h
Normal file
32
cgi.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#include "lwip/apps/httpd.h"
|
||||||
|
#include "pico/cyw43_arch.h"
|
||||||
|
|
||||||
|
// CGI handler which is run when a request for /led.cgi is detected
|
||||||
|
const char * cgi_led_handler(int iIndex, int iNumParams, char *pcParam[], char *pcValue[])
|
||||||
|
{
|
||||||
|
// Check if an request for LED has been made (/led.cgi?led=x)
|
||||||
|
if (strcmp(pcParam[0] , "led") == 0){
|
||||||
|
// Look at the argument to check if LED is to be turned on (x=1) or off (x=0)
|
||||||
|
if(strcmp(pcValue[0], "0") == 0)
|
||||||
|
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0);
|
||||||
|
else if(strcmp(pcValue[0], "1") == 0)
|
||||||
|
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the index page back to the user
|
||||||
|
return "/index.shtml";
|
||||||
|
}
|
||||||
|
|
||||||
|
// tCGI Struct
|
||||||
|
// Fill this with all of the CGI requests and their respective handlers
|
||||||
|
static const tCGI cgi_handlers[] = {
|
||||||
|
{
|
||||||
|
// Html request for "/led.cgi" triggers cgi_handler
|
||||||
|
"/led.cgi", cgi_led_handler
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
void cgi_init(void)
|
||||||
|
{
|
||||||
|
http_set_cgi_handlers(cgi_handlers, 1);
|
||||||
|
}
|
20
html_files/index.shtml
Normal file
20
html_files/index.shtml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>PicoW Webserver</title>
|
||||||
|
</head>
|
||||||
|
<body> <h1>PicoW Webserver Tutorial</h1>
|
||||||
|
<br>
|
||||||
|
<h2>This bit is SSI:</h2>
|
||||||
|
<p>Voltage: <!--#volt--></p>
|
||||||
|
<p>Temp: <!--#temp--> C</p>
|
||||||
|
<p>LED is: <!--#led--></p>
|
||||||
|
<br>
|
||||||
|
<h2>This bit is CGI:</h2>
|
||||||
|
<a href="/led.cgi?led=1"><button>LED ON</button></a>
|
||||||
|
<a href="/led.cgi?led=0"><button>LED OFF</button></a>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<a href="/index.shtml">Refresh</a>
|
||||||
|
</body>
|
||||||
|
</html>
|
15
lwipopts.h
15
lwipopts.h
@ -1,9 +1,5 @@
|
|||||||
#ifndef _LWIPOPTS_EXAMPLE_COMMONH_H
|
|
||||||
#define _LWIPOPTS_EXAMPLE_COMMONH_H
|
|
||||||
|
|
||||||
|
|
||||||
// Common settings used in most of the pico_w examples
|
// Common settings used in most of the pico_w examples
|
||||||
// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html for details)
|
// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html for details)]
|
||||||
|
|
||||||
// allow override in some examples
|
// allow override in some examples
|
||||||
#ifndef NO_SYS
|
#ifndef NO_SYS
|
||||||
@ -87,4 +83,11 @@
|
|||||||
#define SLIP_DEBUG LWIP_DBG_OFF
|
#define SLIP_DEBUG LWIP_DBG_OFF
|
||||||
#define DHCP_DEBUG LWIP_DBG_OFF
|
#define DHCP_DEBUG LWIP_DBG_OFF
|
||||||
|
|
||||||
#endif /* __LWIPOPTS_H__ */
|
// This section enables HTTPD server with SSI, SGI
|
||||||
|
// and tells server which converted HTML files to use
|
||||||
|
#define LWIP_HTTPD 1
|
||||||
|
#define LWIP_HTTPD_SSI 1
|
||||||
|
#define LWIP_HTTPD_CGI 1
|
||||||
|
#define LWIP_HTTPD_SSI_INCLUDE_TAG 0
|
||||||
|
#define HTTPD_SERVER_PORT 80
|
||||||
|
#define HTTPD_FSDATA_FILE "htmldata.c"
|
36
main.c
Normal file
36
main.c
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#include "lwip/apps/httpd.h"
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
#include "pico/cyw43_arch.h"
|
||||||
|
#include "lwipopts.h"
|
||||||
|
#include "ssi.h"
|
||||||
|
#include "cgi.h"
|
||||||
|
#include "secret.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
stdio_init_all();
|
||||||
|
|
||||||
|
if (cyw43_arch_init()) {
|
||||||
|
printf("Wi-Fi init failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
printf("Wi-Fi init succeeded\n");
|
||||||
|
|
||||||
|
cyw43_arch_enable_sta_mode();
|
||||||
|
|
||||||
|
if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASS, CYW43_AUTH_WPA2_AES_PSK, 30000)){
|
||||||
|
printf("Wi-Fi failed to connect\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
printf("Wi-Fi connected\n");
|
||||||
|
|
||||||
|
httpd_init();
|
||||||
|
printf("HTTP Server initialized at %s on port %d\n", ip4addr_ntoa(netif_ip4_addr(netif_list)), HTTPD_SERVER_PORT);
|
||||||
|
|
||||||
|
ssi_init();
|
||||||
|
printf("SSI Handler initialized\n");
|
||||||
|
|
||||||
|
cgi_init();
|
||||||
|
printf("CGI Handler initialised\n");
|
||||||
|
|
||||||
|
while(1);
|
||||||
|
}
|
106
makefsdata.py
Normal file
106
makefsdata.py
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
# This script is by @rspeir on GitHub:
|
||||||
|
# https://github.com/krzmaz/pico-w-webserver-example/pull/1/files/4b3e78351dd236f213da9bebbb20df690d470476#diff-e675c4a367e382db6f9ba61833a58c62029d8c71c3156a9f238b612b69de279d
|
||||||
|
# Renamed output to avoid linking incorrect file
|
||||||
|
|
||||||
|
import os
|
||||||
|
import binascii
|
||||||
|
|
||||||
|
#Create file to write output into
|
||||||
|
output = open('htmldata.c', 'w')
|
||||||
|
|
||||||
|
#Traverse directory, generate list of files
|
||||||
|
files = list()
|
||||||
|
os.chdir('./html_files')
|
||||||
|
for(dirpath, dirnames, filenames) in os.walk('.'):
|
||||||
|
files += [os.path.join(dirpath, file) for file in filenames]
|
||||||
|
|
||||||
|
filenames = list()
|
||||||
|
varnames = list()
|
||||||
|
|
||||||
|
#Generate appropriate HTTP headers
|
||||||
|
for file in files:
|
||||||
|
|
||||||
|
if '404' in file:
|
||||||
|
header = "HTTP/1.0 404 File not found\r\n"
|
||||||
|
else:
|
||||||
|
header = "HTTP/1.0 200 OK\r\n"
|
||||||
|
|
||||||
|
header += "Server: lwIP/pre-0.6 (http://www.sics.se/~adam/lwip/)\r\n"
|
||||||
|
|
||||||
|
if '.html' in file:
|
||||||
|
header += "Content-type: text/html\r\n"
|
||||||
|
elif '.shtml' in file:
|
||||||
|
header += "Content-type: text/html\r\n"
|
||||||
|
elif '.jpg' in file:
|
||||||
|
header += "Content-type: image/jpeg\r\n"
|
||||||
|
elif '.gif' in file:
|
||||||
|
header += "Content-type: image/gif\r\n"
|
||||||
|
elif '.png' in file:
|
||||||
|
header += "Content-type: image/png\r\n"
|
||||||
|
elif '.class' in file:
|
||||||
|
header += "Content-type: application/octet-stream\r\n"
|
||||||
|
elif '.js' in file:
|
||||||
|
header += "Content-type: text/javascript\r\n"
|
||||||
|
elif '.css' in file:
|
||||||
|
header += "Content-type: text/css\r\n"
|
||||||
|
elif '.svg' in file:
|
||||||
|
header += "Content-type: image/svg+xml\r\n"
|
||||||
|
else:
|
||||||
|
header += "Content-type: text/plain\r\n"
|
||||||
|
|
||||||
|
header += "\r\n"
|
||||||
|
|
||||||
|
fvar = file[1:] #remove leading dot in filename
|
||||||
|
fvar = fvar.replace('/', '_') #replace *nix path separator with underscore
|
||||||
|
fvar = fvar.replace('\\', '_') #replace DOS path separator with underscore
|
||||||
|
fvar = fvar.replace('.', '_') #replace file extension dot with underscore
|
||||||
|
|
||||||
|
output.write("static const unsigned char data{}[] = {{\n".format(fvar))
|
||||||
|
output.write("\t/* {} */\n\t".format(file))
|
||||||
|
|
||||||
|
#first set of hex data encodes the filename
|
||||||
|
b = bytes(file[1:].replace('\\', '/'), 'utf-8') #change DOS path separator to forward slash
|
||||||
|
for byte in binascii.hexlify(b, b' ', 1).split():
|
||||||
|
output.write("0x{}, ".format(byte.decode()))
|
||||||
|
output.write("0,\n\t")
|
||||||
|
|
||||||
|
#second set of hex data is the HTTP header/mime type we generated above
|
||||||
|
b = bytes(header, 'utf-8')
|
||||||
|
count = 0
|
||||||
|
for byte in binascii.hexlify(b, b' ', 1).split():
|
||||||
|
output.write("0x{}, ".format(byte.decode()))
|
||||||
|
count = count + 1
|
||||||
|
if(count == 10):
|
||||||
|
output.write("\n\t")
|
||||||
|
count = 0
|
||||||
|
output.write("\n\t")
|
||||||
|
|
||||||
|
#finally, dump raw hex data from files
|
||||||
|
with open(file, 'rb') as f:
|
||||||
|
count = 0
|
||||||
|
while(byte := f.read(1)):
|
||||||
|
byte = binascii.hexlify(byte)
|
||||||
|
output.write("0x{}, ".format(byte.decode()))
|
||||||
|
count = count + 1
|
||||||
|
if(count == 10):
|
||||||
|
output.write("\n\t")
|
||||||
|
count = 0
|
||||||
|
output.write("};\n\n")
|
||||||
|
|
||||||
|
filenames.append(file[1:])
|
||||||
|
varnames.append(fvar)
|
||||||
|
|
||||||
|
for i in range(len(filenames)):
|
||||||
|
prevfile = "NULL"
|
||||||
|
if(i > 0):
|
||||||
|
prevfile = "file" + varnames[i-1]
|
||||||
|
|
||||||
|
output.write("const struct fsdata_file file{0}[] = {{{{ {1}, data{2}, ".format(varnames[i], prevfile, varnames[i]))
|
||||||
|
output.write("data{} + {}, ".format(varnames[i], len(filenames[i]) + 1))
|
||||||
|
output.write("sizeof(data{}) - {}, ".format(varnames[i], len(filenames[i]) + 1))
|
||||||
|
output.write("FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT}};\n")
|
||||||
|
|
||||||
|
output.write("\n#define FS_ROOT file{}\n".format(varnames[-1]))
|
||||||
|
output.write("#define FS_NUMFILES {}\n".format(len(filenames)))
|
51
ssi.h
Normal file
51
ssi.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#include "lwip/apps/httpd.h"
|
||||||
|
#include "pico/cyw43_arch.h"
|
||||||
|
#include "hardware/adc.h"
|
||||||
|
|
||||||
|
// SSI tags - tag length limited to 8 bytes by default
|
||||||
|
const char * ssi_tags[] = {"volt","temp","led"};
|
||||||
|
|
||||||
|
u16_t ssi_handler(int iIndex, char *pcInsert, int iInsertLen) {
|
||||||
|
size_t printed;
|
||||||
|
switch (iIndex) {
|
||||||
|
case 0: // volt
|
||||||
|
{
|
||||||
|
const float voltage = adc_read() * 3.3f / (1 << 12);
|
||||||
|
printed = snprintf(pcInsert, iInsertLen, "%f", voltage);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1: // temp
|
||||||
|
{
|
||||||
|
const float voltage = adc_read() * 3.3f / (1 << 12);
|
||||||
|
const float tempC = 27.0f - (voltage - 0.706f) / 0.001721f;
|
||||||
|
printed = snprintf(pcInsert, iInsertLen, "%f", tempC);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2: // led
|
||||||
|
{
|
||||||
|
bool led_status = cyw43_arch_gpio_get(CYW43_WL_GPIO_LED_PIN);
|
||||||
|
if(led_status == true){
|
||||||
|
printed = snprintf(pcInsert, iInsertLen, "ON");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
printed = snprintf(pcInsert, iInsertLen, "OFF");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printed = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (u16_t)printed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialise the SSI handler
|
||||||
|
void ssi_init() {
|
||||||
|
// Initialise ADC (internal pin)
|
||||||
|
adc_init();
|
||||||
|
adc_set_temp_sensor_enabled(true);
|
||||||
|
adc_select_input(4);
|
||||||
|
|
||||||
|
http_set_ssi_handler(ssi_handler, ssi_tags, LWIP_ARRAYSIZE(ssi_tags));
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
#ifndef SECRET_H
|
#ifndef SECRET_H
|
||||||
#define SECRET_H
|
#define SECRET_H
|
||||||
|
|
||||||
char ssid[] = "wifi ssid";
|
const char WIFI_SSID[] = "ssid";
|
||||||
char pass[] = "wifi pass";
|
const char WIFI_PASS[] = "pass";
|
||||||
|
|
||||||
#endif
|
#endif
|
Loading…
Reference in New Issue
Block a user