implement http using tcp sockets,
remove cgi ssi lwip_http, remove makefsdata.py
This commit is contained in:
parent
7aadd6d4e0
commit
8cd68286df
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,5 +1,4 @@
|
|||||||
**/build/*
|
**/build/*
|
||||||
**/secret.h
|
**/secret.h
|
||||||
**/wwwdata.c
|
|
||||||
**/*.log
|
**/*.log
|
||||||
**/*.raw
|
**/*.raw
|
@ -12,7 +12,6 @@ target_include_directories(${PROGRAM_NAME} PRIVATE
|
|||||||
)
|
)
|
||||||
target_link_libraries(${PROGRAM_NAME}
|
target_link_libraries(${PROGRAM_NAME}
|
||||||
pico_cyw43_arch_lwip_threadsafe_background
|
pico_cyw43_arch_lwip_threadsafe_background
|
||||||
pico_lwip_http
|
|
||||||
pico_stdlib
|
pico_stdlib
|
||||||
hardware_adc
|
hardware_adc
|
||||||
)
|
)
|
||||||
|
6
Makefile
6
Makefile
@ -1,13 +1,9 @@
|
|||||||
.PHONY: all clean build makefsdata
|
.PHONY: all clean build makefsdata
|
||||||
|
|
||||||
all: clean makefsdata build
|
all: clean build
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(MAKE) -C build/ clean
|
$(MAKE) -C build/ clean
|
||||||
rm -rf wwwdata.c
|
|
||||||
|
|
||||||
makefsdata:
|
|
||||||
python3 makefsdata.py
|
|
||||||
|
|
||||||
build:
|
build:
|
||||||
$(MAKE) -C build/
|
$(MAKE) -C build/
|
45
cgi.h
45
cgi.h
@ -1,45 +0,0 @@
|
|||||||
#ifndef CGI_H
|
|
||||||
#define CGI_H
|
|
||||||
|
|
||||||
#include "lwip/apps/httpd.h"
|
|
||||||
#include "handlers.h"
|
|
||||||
|
|
||||||
const char * cgi_power_handler (int iIndex, int iNumParams, char * pcParam [], char * pcValue []) {
|
|
||||||
// Check if an request for power has been made (/power?requested_state=x)
|
|
||||||
if (strcmp(pcParam[0] , "requested_state") == 0){
|
|
||||||
if (strcmp(pcValue[0], "0") == 0) {
|
|
||||||
bmc_power_handler(false);
|
|
||||||
return "/power.ssi";
|
|
||||||
}
|
|
||||||
else if (strcmp(pcValue[0], "1") == 0) {
|
|
||||||
bmc_power_handler(true);
|
|
||||||
return "/power.ssi";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return "/error_requested_state_invalid.ssi";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Send the index page back to the user
|
|
||||||
else {
|
|
||||||
return "/error_missing_requested_state.ssi";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char * cgi_status_handler (int iIndex, int iNumParams, char *pcParam[], char *pcValue[]) {
|
|
||||||
return "/status.ssi";
|
|
||||||
}
|
|
||||||
|
|
||||||
static const tCGI cgi_handlers[] = {
|
|
||||||
{
|
|
||||||
"/power", cgi_power_handler
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"/status", cgi_status_handler
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void cgi_init(void) {
|
|
||||||
http_set_cgi_handlers(cgi_handlers, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
26
handlers.h
26
handlers.h
@ -8,8 +8,15 @@
|
|||||||
#define PW_STATE_UPDATE_REPEAT_DELAY_MS 100
|
#define PW_STATE_UPDATE_REPEAT_DELAY_MS 100
|
||||||
#define PW_STATE_INV 1
|
#define PW_STATE_INV 1
|
||||||
|
|
||||||
bool current_state = false;
|
typedef struct CURRENT_STATE_T_ {
|
||||||
struct repeating_timer * state_update_timer = NULL;
|
float voltage;
|
||||||
|
float tempC;
|
||||||
|
bool power_state;
|
||||||
|
} CURRENT_STATE_T;
|
||||||
|
|
||||||
|
struct repeating_timer * state_update_timer = NULL;
|
||||||
|
|
||||||
|
CURRENT_STATE_T current_state;
|
||||||
|
|
||||||
// handler fn to set the power switch pin to an active state
|
// handler fn to set the power switch pin to an active state
|
||||||
int64_t pw_sw_on_async (alarm_id_t id, void * user_data) {
|
int64_t pw_sw_on_async (alarm_id_t id, void * user_data) {
|
||||||
@ -27,13 +34,15 @@ int64_t pw_sw_off_async (alarm_id_t id, void * user_data) {
|
|||||||
|
|
||||||
// hander fn to read from the power state
|
// hander fn to read from the power state
|
||||||
bool update_current_state_async (repeating_timer_t * rt) {
|
bool update_current_state_async (repeating_timer_t * rt) {
|
||||||
current_state = gpio_get(PW_STATE_PIN) ^ PW_STATE_INV;
|
current_state.voltage = adc_read() * 3.3f / (1 << 12);
|
||||||
|
current_state.tempC = 27.0f - (current_state.voltage - 0.706f) / 0.001721f;
|
||||||
|
current_state.power_state = gpio_get(PW_STATE_PIN) ^ PW_STATE_INV;
|
||||||
return true; // continue repeating alarm
|
return true; // continue repeating alarm
|
||||||
}
|
}
|
||||||
|
|
||||||
// handler fn called to attempt to set the power state to the requested state
|
// handler fn called to attempt to set the power state to the requested state
|
||||||
void bmc_power_handler (bool requested_state) {
|
void bmc_power_handler (bool requested_power_state) {
|
||||||
if (requested_state != current_state) {
|
if (requested_power_state != current_state.power_state) {
|
||||||
add_alarm_in_ms(0, pw_sw_on_async, NULL, true);
|
add_alarm_in_ms(0, pw_sw_on_async, NULL, true);
|
||||||
add_alarm_in_ms(PW_SWITCH_DELAY_MS, pw_sw_off_async, NULL, true);
|
add_alarm_in_ms(PW_SWITCH_DELAY_MS, pw_sw_off_async, NULL, true);
|
||||||
}
|
}
|
||||||
@ -48,9 +57,16 @@ void bmc_handler_init () {
|
|||||||
gpio_init(PW_STATE_PIN);
|
gpio_init(PW_STATE_PIN);
|
||||||
gpio_set_dir(PW_STATE_PIN, GPIO_IN);
|
gpio_set_dir(PW_STATE_PIN, GPIO_IN);
|
||||||
|
|
||||||
|
// init adc input
|
||||||
|
adc_init();
|
||||||
|
adc_set_temp_sensor_enabled(true);
|
||||||
|
adc_select_input(4);
|
||||||
|
|
||||||
// set repeating timer for power state update
|
// set repeating timer for power state update
|
||||||
state_update_timer = malloc(sizeof(struct repeating_timer));
|
state_update_timer = malloc(sizeof(struct repeating_timer));
|
||||||
add_repeating_timer_ms(PW_STATE_UPDATE_REPEAT_DELAY_MS, update_current_state_async, NULL, state_update_timer);
|
add_repeating_timer_ms(PW_STATE_UPDATE_REPEAT_DELAY_MS, update_current_state_async, NULL, state_update_timer);
|
||||||
|
|
||||||
|
DEBUG_printf("[BMC ] [OK ] BMC initialized successfully\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void bmc_handler_deinit () {
|
void bmc_handler_deinit () {
|
||||||
|
298
http_serv.h
Normal file
298
http_serv.h
Normal file
@ -0,0 +1,298 @@
|
|||||||
|
#ifndef HTTP_SERV_H
|
||||||
|
#define HTTP_SERV_H
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include "lwip/pbuf.h"
|
||||||
|
#include "lwip/tcp.h"
|
||||||
|
|
||||||
|
#define POLL_TIME_S 5
|
||||||
|
#define HTTP_GET "GET"
|
||||||
|
#define HTTP_POST "POST"
|
||||||
|
#define HTTP_RESPONSE_HEADER "HTTP/1.1 %d OK\nContent-Length: %d\nContent-Type: application/json; charset=utf-8\nConnection: close\n\n"
|
||||||
|
|
||||||
|
extern CURRENT_STATE_T current_state;
|
||||||
|
|
||||||
|
typedef struct TCP_SERVER_T_ {
|
||||||
|
struct tcp_pcb * server_pcb;
|
||||||
|
bool complete;
|
||||||
|
ip_addr_t gw;
|
||||||
|
|
||||||
|
} TCP_SERVER_T;
|
||||||
|
|
||||||
|
typedef struct TCP_CONNECT_STATE_T_ {
|
||||||
|
struct tcp_pcb * pcb;
|
||||||
|
int sent_len;
|
||||||
|
char headers[128];
|
||||||
|
char result[256];
|
||||||
|
int header_len;
|
||||||
|
int result_len;
|
||||||
|
ip_addr_t * gw;
|
||||||
|
} TCP_CONNECT_STATE_T;
|
||||||
|
|
||||||
|
TCP_SERVER_T * state = NULL;
|
||||||
|
|
||||||
|
static err_t tcp_close_client_connection(TCP_CONNECT_STATE_T * con_state, struct tcp_pcb * client_pcb, err_t close_err) {
|
||||||
|
if (client_pcb) {
|
||||||
|
assert(con_state && con_state->pcb == client_pcb);
|
||||||
|
tcp_arg(client_pcb, NULL);
|
||||||
|
tcp_poll(client_pcb, NULL, 0);
|
||||||
|
tcp_sent(client_pcb, NULL);
|
||||||
|
tcp_recv(client_pcb, NULL);
|
||||||
|
tcp_err(client_pcb, NULL);
|
||||||
|
err_t err = tcp_close(client_pcb);
|
||||||
|
if (err != ERR_OK) {
|
||||||
|
DEBUG_printf("[HTTP] [ERR] Close failed %d, calling abort\n", err);
|
||||||
|
tcp_abort(client_pcb);
|
||||||
|
close_err = ERR_ABRT;
|
||||||
|
}
|
||||||
|
if (con_state) {
|
||||||
|
free(con_state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return close_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tcp_server_close(TCP_SERVER_T *state) {
|
||||||
|
if (state->server_pcb) {
|
||||||
|
tcp_arg(state->server_pcb, NULL);
|
||||||
|
tcp_close(state->server_pcb);
|
||||||
|
state->server_pcb = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static err_t tcp_server_sent(void * arg, struct tcp_pcb * pcb, u16_t len) {
|
||||||
|
TCP_CONNECT_STATE_T * con_state = (TCP_CONNECT_STATE_T *)arg;
|
||||||
|
DEBUG_printf("[HTTP] [OK ] Sent %u\n", len);
|
||||||
|
con_state->sent_len += len;
|
||||||
|
if (con_state->sent_len >= con_state->header_len + con_state->result_len) {
|
||||||
|
DEBUG_printf("[HTTP] [OK ] Send done\n");
|
||||||
|
return tcp_close_client_connection(con_state, pcb, ERR_OK);
|
||||||
|
}
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_status_get (const char * request, const char * params, char * result, size_t max_result_len) {
|
||||||
|
return snprintf(result, max_result_len, "{volt: %f, temp: %f, power: %d}", current_state.voltage, current_state.tempC, current_state.power_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_power_post (const char * request, const char * params, char * result, size_t max_result_len) {
|
||||||
|
if (params) {
|
||||||
|
int requested_power_state_int;
|
||||||
|
int led_param = sscanf(params, "requested_state=%d", &requested_power_state_int);
|
||||||
|
if (led_param) {
|
||||||
|
if (requested_power_state_int == 0 || requested_power_state_int == 1) {
|
||||||
|
bmc_power_handler((bool) requested_power_state_int);
|
||||||
|
return snprintf(result, max_result_len, "{}");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return snprintf(result, max_result_len, "{error: true, description: \"invalid requested state, must be 0 or 1\"}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return snprintf(result, max_result_len, "{error: true, description: \"invalid requested state, must be 0 or 1\"}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return snprintf(result, max_result_len, "{error: true, description: \"missing required parameter requested_state\"}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err_t tcp_server_recv(void * arg, struct tcp_pcb * pcb, struct pbuf * p, err_t err) {
|
||||||
|
TCP_CONNECT_STATE_T * con_state = (TCP_CONNECT_STATE_T *)arg;
|
||||||
|
if (!p) {
|
||||||
|
DEBUG_printf("[HTTP] [ERR] Client connection closed\n");
|
||||||
|
return tcp_close_client_connection(con_state, pcb, ERR_OK);
|
||||||
|
}
|
||||||
|
assert(con_state && con_state->pcb == pcb);
|
||||||
|
if (p->tot_len > 0) {
|
||||||
|
DEBUG_printf("[HTTP] [OK ] Server recieved %d err %d\n", p->tot_len, err);
|
||||||
|
// Copy the request into the buffer
|
||||||
|
pbuf_copy_partial(p, con_state->headers, p->tot_len > sizeof(con_state->headers) - 1 ? sizeof(con_state->headers) - 1 : p->tot_len, 0);
|
||||||
|
|
||||||
|
// parse header, should probably put this into a separate method
|
||||||
|
char * method = con_state->headers;
|
||||||
|
char * request = NULL;
|
||||||
|
if (strncmp(method, HTTP_GET, sizeof(HTTP_GET) - 1) == 0) {
|
||||||
|
*(con_state->headers + sizeof(HTTP_GET) - 1) = 0;
|
||||||
|
request = con_state->headers + sizeof(HTTP_GET); // + space
|
||||||
|
}
|
||||||
|
else if (strncmp(method, HTTP_POST, sizeof(HTTP_POST) - 1) == 0) {
|
||||||
|
*(con_state->headers + sizeof(HTTP_POST) - 1) = 0;
|
||||||
|
request = con_state->headers + sizeof(HTTP_POST); // + space
|
||||||
|
}
|
||||||
|
char * params = strchr(request, '?');
|
||||||
|
if (params) {
|
||||||
|
if (*params) {
|
||||||
|
char * space = strchr(request, ' ');
|
||||||
|
*params++ = 0;
|
||||||
|
if (space) {
|
||||||
|
*space = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
params = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
char * space = strchr(request, ' ');
|
||||||
|
if (space) {
|
||||||
|
*space = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// print request
|
||||||
|
if (params) {
|
||||||
|
DEBUG_printf("[HTTP] [OK ] Request: %s %s?%s\n", method, request, params);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DEBUG_printf("[HTTP] [OK ] Request: %s %s\n", method, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
int response_code;
|
||||||
|
|
||||||
|
// parse request depending on method and request
|
||||||
|
if (strncmp(method, HTTP_GET, sizeof(HTTP_GET) - 1) == 0 && strncmp(request, "/status", sizeof("/status") - 1) == 0) {
|
||||||
|
con_state->result_len = handle_status_get(request, params, con_state->result, sizeof(con_state->result));
|
||||||
|
response_code = 200;
|
||||||
|
con_state->header_len = snprintf(con_state->headers, sizeof(con_state->headers), HTTP_RESPONSE_HEADER, response_code, con_state->result_len);
|
||||||
|
}
|
||||||
|
else if (strncmp(method, HTTP_POST, sizeof(HTTP_POST) - 1) == 0 && strncmp(request, "/power", sizeof("/power") - 1) == 0) {
|
||||||
|
con_state->result_len = handle_power_post(request, params, con_state->result, sizeof(con_state->result));
|
||||||
|
response_code = 200;
|
||||||
|
con_state->header_len = snprintf(con_state->headers, sizeof(con_state->headers), HTTP_RESPONSE_HEADER, response_code, con_state->result_len);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
con_state->result_len = 0;
|
||||||
|
response_code = 501;
|
||||||
|
con_state->header_len = snprintf(con_state->headers, sizeof(con_state->headers), HTTP_RESPONSE_HEADER, response_code, con_state->result_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
// print result
|
||||||
|
DEBUG_printf("[HTTP] [OK ] Result: %d %s\n", response_code, con_state->result);
|
||||||
|
|
||||||
|
// Check result buffer size
|
||||||
|
if (con_state->result_len > sizeof(con_state->result) - 1) {
|
||||||
|
DEBUG_printf("[HTTP] [ERR] Too much result data %d\n", con_state->result_len);
|
||||||
|
return tcp_close_client_connection(con_state, pcb, ERR_CLSD);
|
||||||
|
}
|
||||||
|
// Check header buffer size
|
||||||
|
if (con_state->header_len > sizeof(con_state->headers) - 1) {
|
||||||
|
DEBUG_printf("[HTTP] [ERR] Too much header data %d\n", con_state->header_len);
|
||||||
|
return tcp_close_client_connection(con_state, pcb, ERR_CLSD);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the headers to the client
|
||||||
|
con_state->sent_len = 0;
|
||||||
|
err_t err = tcp_write(pcb, con_state->headers, con_state->header_len, 0);
|
||||||
|
if (err != ERR_OK) {
|
||||||
|
DEBUG_printf("[HTTP] [ERR] Failed to write header data %d\n", err);
|
||||||
|
return tcp_close_client_connection(con_state, pcb, err);
|
||||||
|
}
|
||||||
|
// Send the body to the client
|
||||||
|
if (con_state->result_len) {
|
||||||
|
err = tcp_write(pcb, con_state->result, con_state->result_len, 0);
|
||||||
|
if (err != ERR_OK) {
|
||||||
|
DEBUG_printf("[HTTP] [ERR] Failed to write result data %d\n", err);
|
||||||
|
return tcp_close_client_connection(con_state, pcb, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tcp_recved(pcb, p->tot_len);
|
||||||
|
}
|
||||||
|
pbuf_free(p);
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static err_t tcp_server_poll(void * arg, struct tcp_pcb * pcb) {
|
||||||
|
TCP_CONNECT_STATE_T * con_state = (TCP_CONNECT_STATE_T *)arg;
|
||||||
|
return tcp_close_client_connection(con_state, pcb, ERR_OK); // Just disconnect clent?
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tcp_server_err(void * arg, err_t err) {
|
||||||
|
TCP_CONNECT_STATE_T * con_state = (TCP_CONNECT_STATE_T *)arg;
|
||||||
|
if (err != ERR_ABRT) {
|
||||||
|
DEBUG_printf("[HTTP] [ERR] Error %d\n", err);
|
||||||
|
tcp_close_client_connection(con_state, con_state->pcb, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static err_t tcp_server_accept(void * arg, struct tcp_pcb * client_pcb, err_t err) {
|
||||||
|
TCP_SERVER_T * state = (TCP_SERVER_T *)arg;
|
||||||
|
if (err != ERR_OK || client_pcb == NULL) {
|
||||||
|
DEBUG_printf("[HTTP] [ERR] Failure accepting client connection\n");
|
||||||
|
return ERR_VAL;
|
||||||
|
}
|
||||||
|
DEBUG_printf("[HTTP] [OK ] Client connected\n");
|
||||||
|
|
||||||
|
// Create the state for the connection
|
||||||
|
TCP_CONNECT_STATE_T * con_state = calloc(1, sizeof(TCP_CONNECT_STATE_T));
|
||||||
|
if (!con_state) {
|
||||||
|
DEBUG_printf("[HTTP] [ERR] Failed to allocate connect state\n");
|
||||||
|
return ERR_MEM;
|
||||||
|
}
|
||||||
|
con_state->pcb = client_pcb; // for checking
|
||||||
|
con_state->gw = &state->gw;
|
||||||
|
|
||||||
|
// setup connection to client
|
||||||
|
tcp_arg(client_pcb, con_state);
|
||||||
|
tcp_sent(client_pcb, tcp_server_sent);
|
||||||
|
tcp_recv(client_pcb, tcp_server_recv);
|
||||||
|
tcp_poll(client_pcb, tcp_server_poll, POLL_TIME_S * 2);
|
||||||
|
tcp_err(client_pcb, tcp_server_err);
|
||||||
|
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool tcp_server_open(void * arg) {
|
||||||
|
TCP_SERVER_T * state = (TCP_SERVER_T *)arg;
|
||||||
|
DEBUG_printf("[HTTP] [OK ] Starting server at %s on port %d\n", ip4addr_ntoa(netif_ip4_addr(netif_list)), TCP_PORT);
|
||||||
|
|
||||||
|
struct tcp_pcb * pcb = tcp_new_ip_type(IPADDR_TYPE_ANY);
|
||||||
|
if (!pcb) {
|
||||||
|
DEBUG_printf("[HTTP] [ERR] Failed to create pcb\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
err_t err = tcp_bind(pcb, IP_ANY_TYPE, TCP_PORT);
|
||||||
|
if (err) {
|
||||||
|
DEBUG_printf("[HTTP] [ERR] Failed to bind to port %d\n", TCP_PORT);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->server_pcb = tcp_listen_with_backlog(pcb, 1);
|
||||||
|
if (!state->server_pcb) {
|
||||||
|
DEBUG_printf("[HTTP] [ERR] Failed to listen on port %d\n", TCP_PORT);
|
||||||
|
if (pcb) {
|
||||||
|
tcp_close(pcb);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
tcp_arg(state->server_pcb, state);
|
||||||
|
tcp_accept(state->server_pcb, tcp_server_accept);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int http_serv_init () {
|
||||||
|
state = calloc(1, sizeof(TCP_SERVER_T));
|
||||||
|
if (!state) {
|
||||||
|
DEBUG_printf("[HTTP] [ERR] Failed to allocate state\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tcp_server_open(state)) {
|
||||||
|
DEBUG_printf("[HTTP] [ERR] Failed to open server\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_printf("[HTTP] [OK ] Sucessfully initialized http server\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int http_serv_deinit () {
|
||||||
|
tcp_server_close(state);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -82,12 +82,3 @@
|
|||||||
#define PPP_DEBUG LWIP_DBG_OFF
|
#define PPP_DEBUG LWIP_DBG_OFF
|
||||||
#define SLIP_DEBUG LWIP_DBG_OFF
|
#define SLIP_DEBUG LWIP_DBG_OFF
|
||||||
#define DHCP_DEBUG LWIP_DBG_OFF
|
#define DHCP_DEBUG LWIP_DBG_OFF
|
||||||
|
|
||||||
// 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 "wwwdata.c"
|
|
45
main.c
45
main.c
@ -1,45 +1,38 @@
|
|||||||
#include "lwip/apps/httpd.h"
|
#define TCP_PORT 80
|
||||||
|
#define DEBUG_printf printf
|
||||||
|
|
||||||
#include "pico_lib.h"
|
#include "pico_lib.h"
|
||||||
#include "lwipopts.h"
|
#include "handlers.h"
|
||||||
#include "ssi.h"
|
#include "http_serv.h"
|
||||||
#include "cgi.h"
|
|
||||||
#include "secret.h"
|
#include "secret.h"
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
stdio_init_all();
|
stdio_init_all();
|
||||||
|
|
||||||
if (cyw43_arch_init()) {
|
if (cyw43_arch_init()) {
|
||||||
printf("Wi-Fi init failed\n");
|
DEBUG_printf("[INIT] [ERR] Failed to initialise cyw43\n");
|
||||||
return -1;
|
return 1;
|
||||||
}
|
}
|
||||||
printf("Wi-Fi init succeeded\n");
|
|
||||||
|
|
||||||
cyw43_arch_enable_sta_mode();
|
cyw43_arch_enable_sta_mode();
|
||||||
|
|
||||||
if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASS, CYW43_AUTH_WPA2_AES_PSK, 30000)){
|
if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASS, CYW43_AUTH_WPA2_AES_PSK, 30000)){
|
||||||
printf("Wi-Fi failed to connect\n");
|
DEBUG_printf("[INIT] [ERR] Wi-Fi failed to connect\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
printf("Wi-Fi connected\n");
|
DEBUG_printf("[INIT] [OK ] Wi-Fi connected successfully\n");
|
||||||
|
|
||||||
// init httpd
|
|
||||||
httpd_init();
|
|
||||||
printf("HTTP Server initialized at %s on port %d\n", ip4addr_ntoa(netif_ip4_addr(netif_list)), HTTPD_SERVER_PORT);
|
|
||||||
|
|
||||||
// enable ssi
|
http_serv_init();
|
||||||
ssi_init();
|
|
||||||
printf("SSI Handler initialized\n");
|
|
||||||
|
|
||||||
// enable cgi
|
|
||||||
cgi_init();
|
|
||||||
printf("CGI Handler initialised\n");
|
|
||||||
|
|
||||||
// init bmc handler
|
// init bmc handler
|
||||||
bmc_handler_init();
|
bmc_handler_init();
|
||||||
printf("BMC handler initialized\n");
|
|
||||||
|
|
||||||
// set LED to on to indicate it has connected and initialized
|
// set LED to on to indicate it has connected and initialized
|
||||||
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1);
|
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1);
|
||||||
|
|
||||||
while(1);
|
while(true);
|
||||||
|
|
||||||
|
http_serv_deinit();
|
||||||
|
cyw43_arch_deinit();
|
||||||
|
return 0;
|
||||||
}
|
}
|
108
makefsdata.py
108
makefsdata.py
@ -1,108 +0,0 @@
|
|||||||
#!/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('wwwdata.c', 'w')
|
|
||||||
|
|
||||||
#Traverse directory, generate list of files
|
|
||||||
files = list()
|
|
||||||
os.chdir('./www')
|
|
||||||
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"
|
|
||||||
elif ".ssi" in file:
|
|
||||||
header += "Content-type: application/json\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)))
|
|
47
ssi.h
47
ssi.h
@ -1,47 +0,0 @@
|
|||||||
#ifndef SSI_H
|
|
||||||
#define SSI_H
|
|
||||||
|
|
||||||
#include "lwip/apps/httpd.h"
|
|
||||||
#include "handlers.h"
|
|
||||||
|
|
||||||
const char * ssi_tags[] = {"volt", "temp", "power"};
|
|
||||||
|
|
||||||
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: // power
|
|
||||||
{
|
|
||||||
printed = snprintf(pcInsert, iInsertLen, "%d", current_state);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
printed = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (u16_t) printed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ssi_init() {
|
|
||||||
adc_init();
|
|
||||||
adc_set_temp_sensor_enabled(true);
|
|
||||||
adc_select_input(4);
|
|
||||||
http_set_ssi_handler(ssi_handler, ssi_tags, LWIP_ARRAYSIZE(ssi_tags));
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"error": true,
|
|
||||||
"description": "Missing search parameter requested_state"
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"error": true,
|
|
||||||
"description": "Invalid requested_state must be 0 or 1"
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
{}
|
|
@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"volt": <!--#volt-->,
|
|
||||||
"temp": <!--#temp-->,
|
|
||||||
"power": <!--#power-->
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user