From 426c04116f6ac2121fcd8024eb92bfd9eb8b1b49 Mon Sep 17 00:00:00 2001 From: Arthur Lu Date: Tue, 13 Feb 2024 21:05:01 -0800 Subject: [PATCH] implement async handlers for pulsing pw_sw --- .gitignore | 2 +- Makefile | 17 ++--- cgi.h | 56 +++++++++------- handlers.h | 38 +++++++++++ html_files/index.shtml | 20 ------ lwipopts.h | 2 +- makefsdata.py | 142 +++++++++++++++++++++-------------------- ssi.h | 40 ++++++------ www/power.ssi | 1 + www/status.ssi | 5 ++ 10 files changed, 176 insertions(+), 147 deletions(-) create mode 100644 handlers.h delete mode 100644 html_files/index.shtml create mode 100644 www/power.ssi create mode 100644 www/status.ssi diff --git a/.gitignore b/.gitignore index e7516f7..360dd94 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ **/build/* **/secret.h -**/htmldata.c \ No newline at end of file +**/wwwdata.c \ No newline at end of file diff --git a/Makefile b/Makefile index dec91a7..75e4bca 100644 --- a/Makefile +++ b/Makefile @@ -1,16 +1,13 @@ -#TOPTARGETS := all clean +.PHONY: all clean build makefsdata -SUBDIRS := build +all: clean makefsdata build -all: makefsdata $(SUBDIRS) +clean: + $(MAKE) -C build/ clean + rm -rf wwwdata.c makefsdata: python3 makefsdata.py -clean: $(SUBDIRS) - rm -rf htmldata.c - -$(SUBDIRS): - $(MAKE) -C $@ $(MAKECMDGOALS) - -.PHONY: all makefsdata clean $(SUBDIRS) \ No newline at end of file +build: + $(MAKE) -C build/ \ No newline at end of file diff --git a/cgi.h b/cgi.h index 3608d98..8d9dddc 100644 --- a/cgi.h +++ b/cgi.h @@ -1,32 +1,40 @@ +#ifndef CGI_H +#define CGI_H + #include "lwip/apps/httpd.h" #include "pico/cyw43_arch.h" +#include "handlers.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"; +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){ + // 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) { + bmc_power_handler(false); + } + else if(strcmp(pcValue[0], "1") == 0) { + bmc_power_handler(true); + } + } + // Send the index page back to the user + return "/power.ssi"; +} + +const char * cgi_status_handler (int iIndex, int iNumParams, char *pcParam[], char *pcValue[]) { + return "/status.ssi"; } -// 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 - }, + { + "/power", cgi_power_handler + }, + { + "/status", cgi_status_handler + } }; -void cgi_init(void) -{ - http_set_cgi_handlers(cgi_handlers, 1); -} \ No newline at end of file +void cgi_init(void) { + http_set_cgi_handlers(cgi_handlers, 2); +} + +#endif \ No newline at end of file diff --git a/handlers.h b/handlers.h new file mode 100644 index 0000000..e384aca --- /dev/null +++ b/handlers.h @@ -0,0 +1,38 @@ +#ifndef HANDLERS_H +#define HANDLERS_H + +#include "pico/stdlib.h" + +#define PW_SW_DELAY_MS 100 +#define STATE_UPDATE_REPEAT_DELAY_MS 100 + +bool current_state = false; + +int64_t pw_sw_on_async (alarm_id_t id, void * user_data) { + cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1); + return 0; // do not reschedule alarm +} + +int64_t pw_sw_off_async (alarm_id_t id, void * user_data) { + cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0); + return 0; // do not reschedule alarm +} + +bool update_current_state_async (repeating_timer_t * rt) { + return true; // continue repeating alarm +} + +bool bmc_power_handler (bool requested_state) { + if (requested_state != current_state) { + add_alarm_in_ms(0, pw_sw_on_async, NULL, true); + add_alarm_in_ms(PW_SW_DELAY_MS, pw_sw_off_async, NULL, true); + } +} + +struct repeating_timer * bmc_handler_init () { + struct repeating_timer * timer = malloc(sizeof(struct repeating_timer)); + add_repeating_timer_ms(STATE_UPDATE_REPEAT_DELAY_MS, update_current_state_async, NULL, timer); + return timer; +} + +#endif \ No newline at end of file diff --git a/html_files/index.shtml b/html_files/index.shtml deleted file mode 100644 index 1ce5ee8..0000000 --- a/html_files/index.shtml +++ /dev/null @@ -1,20 +0,0 @@ - - - - PicoW Webserver - -

PicoW Webserver Tutorial

-
-

This bit is SSI:

-

Voltage:

-

Temp: C

-

LED is:

-
-

This bit is CGI:

- - -
-
- Refresh - - \ No newline at end of file diff --git a/lwipopts.h b/lwipopts.h index b4ea9a3..4ac3fd8 100644 --- a/lwipopts.h +++ b/lwipopts.h @@ -90,4 +90,4 @@ #define LWIP_HTTPD_CGI 1 #define LWIP_HTTPD_SSI_INCLUDE_TAG 0 #define HTTPD_SERVER_PORT 80 -#define HTTPD_FSDATA_FILE "htmldata.c" \ No newline at end of file +#define HTTPD_FSDATA_FILE "wwwdata.c" \ No newline at end of file diff --git a/makefsdata.py b/makefsdata.py index d9bba5a..7a734af 100644 --- a/makefsdata.py +++ b/makefsdata.py @@ -8,13 +8,13 @@ import os import binascii #Create file to write output into -output = open('htmldata.c', 'w') +output = open('wwwdata.c', 'w') #Traverse directory, generate list of files files = list() -os.chdir('./html_files') +os.chdir('./www') for(dirpath, dirnames, filenames) in os.walk('.'): - files += [os.path.join(dirpath, file) for file in filenames] + files += [os.path.join(dirpath, file) for file in filenames] filenames = list() varnames = list() @@ -22,85 +22,87 @@ 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" + 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" + 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" + 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" + 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 + 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)) + 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") + #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") + #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") + #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) + filenames.append(file[1:]) + varnames.append(fvar) for i in range(len(filenames)): - prevfile = "NULL" - if(i > 0): - prevfile = "file" + varnames[i-1] + 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("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))) \ No newline at end of file diff --git a/ssi.h b/ssi.h index 9d9b472..0af385d 100644 --- a/ssi.h +++ b/ssi.h @@ -1,51 +1,49 @@ +#ifndef SSI_H +#define SSI_H + #include "lwip/apps/httpd.h" #include "pico/cyw43_arch.h" #include "hardware/adc.h" +#include "handlers.h" -// SSI tags - tag length limited to 8 bytes by default -const char * ssi_tags[] = {"volt","temp","led"}; +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); + 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); + 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 + case 2: // power { - 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"); - } + printed = snprintf(pcInsert, iInsertLen, "%d", current_state); } break; default: - printed = 0; + { + printed = 0; + } break; } - return (u16_t)printed; + 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)); -} \ No newline at end of file +} + +#endif \ No newline at end of file diff --git a/www/power.ssi b/www/power.ssi new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/www/power.ssi @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/www/status.ssi b/www/status.ssi new file mode 100644 index 0000000..aa05888 --- /dev/null +++ b/www/status.ssi @@ -0,0 +1,5 @@ +{ + "volt": , + "temp": , + "power": +} \ No newline at end of file