diff --git a/.gitignore b/.gitignore index bc9e916..d9fe7f5 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,7 @@ cmake/pico_sdk_import.cmake # clangd stuff .cache compile_commands.json + +#kate backups +*~ + diff --git a/CMakeLists.txt b/CMakeLists.txt index 18bf22d..9856d5d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.19) +cmake_minimum_required(VERSION 3.18) find_package(Perl) if(NOT PERL_FOUND) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c44f51a..9864242 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,12 +14,13 @@ execute_process(COMMAND WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} ECHO_OUTPUT_VARIABLE ECHO_ERROR_VARIABLE - COMMAND_ERROR_IS_FATAL ANY ) file(RENAME fsdata.c my_fsdata.c) add_executable(${PROGRAM_NAME} main.cpp + ssi.cpp + cgi.cpp ) target_compile_definitions(${PROGRAM_NAME} PRIVATE WIFI_SSID=\"${WIFI_SSID}\" @@ -37,7 +38,7 @@ target_link_libraries(${PROGRAM_NAME} ) pico_enable_stdio_usb(${PROGRAM_NAME} TRUE) -pico_enable_stdio_uart(${PROGRAM_NAME} FALSE) +pico_enable_stdio_uart(${PROGRAM_NAME} TRUE) suppress_tinyusb_warnings() pico_add_extra_outputs(${PROGRAM_NAME}) diff --git a/src/cgi.cpp b/src/cgi.cpp new file mode 100644 index 0000000..10fb034 --- /dev/null +++ b/src/cgi.cpp @@ -0,0 +1,138 @@ +#include "lwip/apps/httpd.h" +#include "pico/cyw43_arch.h" +#include "lwipopts.h" +#include "cgi.h" + + +static const tCGI cgi_handlers[] = { + { + /* Html request for "/leds.cgi" will start cgi_handler_basic */ + "/leds.cgi", cgi_handler_basic + }, + { + /* Html request for "/leds2.cgi" will start cgi_handler_extended */ + "/leds_ext.cgi", cgi_handler_extended + } +}; + + + +/* cgi-handler triggered by a request for "/leds.cgi" */ +const char * +cgi_handler_basic(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]) +{ + int i=0; + + /* We use this handler for one page request only: "/leds.cgi" + * and it is at position 0 in the tCGI array (see above). + * So iIndex should be 0. + */ + printf("cgi_handler_basic called with index %d\n", iIndex); + + /* All leds off */ + Led_Off(LED1); + Led_Off(LED2); + Led_Off(LED3); + Led_Off(LED4); + + /* Check the query string. + * A request to turn LED2 and LED4 on would look like: "/leds.cgi?led=2&led=4" + */ + for (i = 0; i < iNumParams; i++){ + /* check if parameter is "led" */ + if (strcmp(pcParam[i] , "led") == 0){ + /* look ar argument to find which led to turn on */ + if(strcmp(pcValue[i], "1") == 0) + Led_On(LED1); + else if(strcmp(pcValue[i], "2") == 0) + Led_On(LED2); + else if(strcmp(pcValue[i], "3") == 0) + Led_On(LED3); + else if(strcmp(pcValue[i], "4") == 0) + Led_On(LED4); + } + } + + /* Our response to the "SUBMIT" is to simply send the same page again*/ + return "/cgi.html"; +} + +/* cgi-handler triggered by a request for "/leds_ext.cgi". + * + * It is almost identical to cgi_handler_basic(). + * Both handlers could be easily implemented in one function - + * distinguish them by looking at the iIndex parameter. + * I left it this way to show how to implement two (or more) + * enirely different handlers. + */ +const char * +cgi_handler_extended(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]) +{ + int i=0; + + /* We use this handler for one page request only: "/leds_ext.cgi" + * and it is at position 1 in the tCGI array (see above). + * So iIndex should be 1. + */ + printf("cgi_handler_extended called with index %d\n", iIndex); + + /* All leds off */ + Led_Off(LED1); + Led_Off(LED2); + Led_Off(LED3); + Led_Off(LED4); + + /* Check the query string. + * A request to turn LED2 and LED4 on would look like: "/leds.cgi?led=2&led=4" + */ + for (i = 0; i < iNumParams; i++){ + /* check if parameter is "led" */ + if (strcmp(pcParam[i] , "led") == 0){ + /* look ar argument to find which led to turn on */ + if(strcmp(pcValue[i], "1") == 0) + Led_On(LED1); + else if(strcmp(pcValue[i], "2") == 0) + Led_On(LED2); + else if(strcmp(pcValue[i], "3") == 0) + Led_On(LED3); + else if(strcmp(pcValue[i], "4") == 0) + Led_On(LED4); + } + } + + /* Our response to the "SUBMIT" is to send "/ssi_cgi.shtml". + * The extension ".shtml" tells the server to insert some values + * which show the user what has been done in response. + */ + return "/ssi_cgi.shtml"; +} + +/* initialize the CGI handler */ +void +cgi_init(void) +{ + http_set_cgi_handlers(cgi_handlers, 2); + + for(int i = LED1; i <= LED4; i++){ + gpio_init(i); + gpio_set_dir(i, GPIO_OUT); + gpio_put(i, 0); + } +} + +/* led control and debugging info */ +void +Led_On(int led) +{ + printf("GPIO%d on\n", led); + gpio_put(led, 1); +} + +void +Led_Off(int led) +{ + printf("GPIO%d off\n", led); + gpio_put(led, 0); +} + + diff --git a/src/cgi.h b/src/cgi.h new file mode 100644 index 0000000..de1f8cf --- /dev/null +++ b/src/cgi.h @@ -0,0 +1,23 @@ +#ifndef __CGI_H__ +#define __CGI_H__ + +// GPIOs for Leds +#define LED1 18 +#define LED2 19 +#define LED3 20 +#define LED4 21 + +/* initialize the CGI handler */ +void cgi_init(void); + +/* CGI handler for LED control */ +const char * cgi_handler_basic(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]); +/* CGI handler for LED control with feedback*/ +const char * cgi_handler_extended(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]); + + +/* led control and debugging info */ +void Led_On(int led); +void Led_Off(int led); + +#endif // __CGI_H__ diff --git a/src/fs/cgi.html b/src/fs/cgi.html new file mode 100644 index 0000000..ef3c8a4 --- /dev/null +++ b/src/fs/cgi.html @@ -0,0 +1,25 @@ + + + Pico W CGI-PAGE +

Pico W

+

CGI-PAGE

+ + + This page allows you to control four leds: LED1, LED2, LED3 and LED4 connected to GPIO18 - 21

+ To turn a led on/off check/uncheck its corresponding checkbox.
+ Then click on the "Send" button to submit the changes.
+
+
+
+ LED1
+ LED2
+ LED3
+ LED4
+
+ +
+
+
+ Back + + diff --git a/src/fs/index.html b/src/fs/index.html index 84671f9..054cc2c 100644 --- a/src/fs/index.html +++ b/src/fs/index.html @@ -3,5 +3,11 @@ Pico W

Pico W

Hello World

- - \ No newline at end of file +
+
+
+  ssi-page: Counter and Voltage
+  cgi-page: Ledcontrol
+  cgi-page: Ledcontrol with feedback
+ + diff --git a/src/fs/ssi.shtml b/src/fs/ssi.shtml index bb8a8e6..b356a5f 100644 --- a/src/fs/ssi.shtml +++ b/src/fs/ssi.shtml @@ -1,8 +1,13 @@ - Pico W -

Pico W

+ Pico W SSI-PAGE + +

Pico W

+

SSI-PAGE

Times !

GPIO26 voltage is: !

+
+
+ Back - \ No newline at end of file + diff --git a/src/fs/ssi_cgi.shtml b/src/fs/ssi_cgi.shtml new file mode 100644 index 0000000..a92642d --- /dev/null +++ b/src/fs/ssi_cgi.shtml @@ -0,0 +1,29 @@ + + + Pico W CGI-SSI-PAGE +

Pico W

+

CGI with Feedback (ssi) PAGE

+ + + This page allows you to control four leds: LED1, LED2, LED3 and LED4 connected to GPIO18 - 21

+ To turn a led on/off check/uncheck its corresponding checkbox.
+ Then click on the "Send" button to submit the changes.
+
+
+
+ > + >LED1
+ > + >LED2
+ > + >LED3
+ > + >LED4
+ +
+
+
+ Back + + + diff --git a/src/lwipopts.h b/src/lwipopts.h index e545ae1..6bc1d62 100644 --- a/src/lwipopts.h +++ b/src/lwipopts.h @@ -57,6 +57,7 @@ #define LWIP_HTTPD 1 #define LWIP_HTTPD_SSI 1 +#define LWIP_HTTPD_CGI 1 // don't include the tag comment - less work for the CPU, but may be harder to debug #define LWIP_HTTPD_SSI_INCLUDE_TAG 0 // use generated fsdata diff --git a/src/main.cpp b/src/main.cpp index 694cf36..4211996 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,11 +6,13 @@ #include "pico/cyw43_arch.h" #include "lwipopts.h" +#include "cgi.h" #include "ssi.h" void run_server() { httpd_init(); ssi_init(); + cgi_init(); printf("Http server initialized.\n"); // infinite loop for now for (;;) {} @@ -23,9 +25,6 @@ int main() { printf("failed to initialise\n"); return 1; } - // turn on LED to distinguish from BOOTSEL mode - cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1); - cyw43_arch_enable_sta_mode(); // this seems to be the best be can do using the predefined `cyw43_pm_value` macro: // cyw43_wifi_pm(&cyw43_state, CYW43_PERFORMANCE_PM); @@ -43,6 +42,9 @@ int main() { auto ip_addr = cyw43_state.netif[CYW43_ITF_STA].ip_addr.addr; printf("IP Address: %lu.%lu.%lu.%lu\n", ip_addr & 0xFF, (ip_addr >> 8) & 0xFF, (ip_addr >> 16) & 0xFF, ip_addr >> 24); } - + // turn on LED to signal connected + cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1); + + run_server(); -} \ No newline at end of file +} diff --git a/src/ssi.cpp b/src/ssi.cpp new file mode 100644 index 0000000..622faef --- /dev/null +++ b/src/ssi.cpp @@ -0,0 +1,110 @@ +#include "hardware/adc.h" +#include "lwip/apps/httpd.h" +#include "pico/cyw43_arch.h" +#include "lwipopts.h" +#include "ssi.h" +#include "cgi.h" + + +// max length of the tags defaults to be 8 chars +// LWIP_HTTPD_MAX_TAG_NAME_LEN +const char * __not_in_flash("httpd") ssi_example_tags[] = { + "Hello", // 0 + "counter", // 1 + "GPIO", // 2 + "state1", // 3 + "state2", // 4 + "state3", // 5 + "state4", // 6 + "bg1", // 7 + "bg2", // 8 + "bg3", // 9 + "bg4" // 10 +}; + +u16_t __time_critical_func(ssi_handler)(int iIndex, char *pcInsert, int iInsertLen) +{ + size_t printed; + switch (iIndex) { + case 0: /* "Hello" */ + printed = snprintf(pcInsert, iInsertLen, "Hello user number %d!", rand()); + break; + case 1: /* "counter" */ + { + static int counter; + counter++; + printed = snprintf(pcInsert, iInsertLen, "%d", counter); + } + break; + case 2: /* "GPIO" */ + { + const float voltage = adc_read() * 3.3f / (1 << 12); + printed = snprintf(pcInsert, iInsertLen, "%f", voltage); + } + break; + case 3: /* "state1" */ + case 4: /* "state2" */ + case 5: /* "state3" */ + case 6: /* "state4" */ + { + bool state; + if(iIndex == 3) + state = gpio_get(LED1); + else if(iIndex == 4) + state = gpio_get(LED2); + else if(iIndex == 5) + state = gpio_get(LED3); + else if(iIndex == 6) + state = gpio_get(LED4); + + if(state) + printed = snprintf(pcInsert, iInsertLen, "checked"); + else + printed = snprintf(pcInsert, iInsertLen, " "); + } + break; + + case 7: /* "bg1" */ + case 8: /* "bg2" */ + case 9: /* "bg3" */ + case 10: /* "bg4" */ + { + bool state; + if(iIndex == 7) + state = gpio_get(LED1); + else if(iIndex == 8) + state = gpio_get(LED2); + else if(iIndex == 9) + state = gpio_get(LED3); + else if(iIndex == 10) + state = gpio_get(LED4); + + if(state) + printed = snprintf(pcInsert, iInsertLen, "\"background-color:green;\""); + else + printed = snprintf(pcInsert, iInsertLen, "\"background-color:red;\""); + } + break; + default: /* unknown tag */ + printed = 0; + break; + } + LWIP_ASSERT("sane length", printed <= 0xFFFF); + return (u16_t)printed; +} + +void ssi_init() +{ + adc_init(); + adc_gpio_init(26); + adc_select_input(0); + size_t i; + for (i = 0; i < LWIP_ARRAYSIZE(ssi_example_tags); i++) { + LWIP_ASSERT("tag too long for LWIP_HTTPD_MAX_TAG_NAME_LEN", + strlen(ssi_example_tags[i]) <= LWIP_HTTPD_MAX_TAG_NAME_LEN); + } + + http_set_ssi_handler(ssi_handler, + ssi_example_tags, LWIP_ARRAYSIZE(ssi_example_tags) + ); +} diff --git a/src/ssi.h b/src/ssi.h index 4879418..ad2e62b 100644 --- a/src/ssi.h +++ b/src/ssi.h @@ -1,56 +1,7 @@ -#pragma once +#ifndef __SSI_H__ +#define __SSI_H__ -#include "hardware/adc.h" -#include "lwip/apps/httpd.h" -#include "pico/cyw43_arch.h" +u16_t __time_critical_func(ssi_handler)(int iIndex, char *pcInsert, int iInsertLen); +void ssi_init(); -#include "lwipopts.h" - -// max length of the tags defaults to be 8 chars -// LWIP_HTTPD_MAX_TAG_NAME_LEN -const char * __not_in_flash("httpd") ssi_example_tags[] = { - "Hello", - "counter", - "GPIO" -}; -u16_t __time_critical_func(ssi_handler)(int iIndex, char *pcInsert, int iInsertLen) { - size_t printed; - switch (iIndex) { - case 0: /* "Hello" */ - printed = snprintf(pcInsert, iInsertLen, "Hello user number %d!", rand()); - break; - case 1: /* "counter" */ - { - static int counter; - counter++; - printed = snprintf(pcInsert, iInsertLen, "%d", counter); - } - break; - case 2: /* "GPIO" */ - { - const float voltage = adc_read() * 3.3f / (1 << 12); - printed = snprintf(pcInsert, iInsertLen, "%f", voltage); - } - break; - default: /* unknown tag */ - printed = 0; - break; - } - LWIP_ASSERT("sane length", printed <= 0xFFFF); - return (u16_t)printed; -} - -void ssi_init() { - adc_init(); - adc_gpio_init(26); - adc_select_input(0); - size_t i; - for (i = 0; i < LWIP_ARRAYSIZE(ssi_example_tags); i++) { - LWIP_ASSERT("tag too long for LWIP_HTTPD_MAX_TAG_NAME_LEN", - strlen(ssi_example_tags[i]) <= LWIP_HTTPD_MAX_TAG_NAME_LEN); - } - - http_set_ssi_handler(ssi_handler, - ssi_example_tags, LWIP_ARRAYSIZE(ssi_example_tags) - ); -} +#endif // __SSI_H__