├── .gitignore ├── .vscode ├── c_cpp_properties.json ├── cmake-kits.json ├── extensions.json ├── launch.json ├── settings.json └── tasks.json ├── CMakeLists.txt ├── LICENSE ├── README.md ├── cgi.h ├── html_files └── index.shtml ├── htmldata.c ├── lwipopts.h ├── main.c ├── makefsdata.py ├── pico_sdk_import.cmake └── ssi.h /.gitignore: -------------------------------------------------------------------------------- 1 | build -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Pico", 5 | "includePath": [ 6 | "${workspaceFolder}/**", 7 | "${env:PICO_SDK_PATH}/**" 8 | ], 9 | "defines": [], 10 | "compilerPath": "${env:PICO_INSTALL_PATH}/gcc-arm-none-eabi/bin/arm-none-eabi-gcc.exe", 11 | "cStandard": "c11", 12 | "cppStandard": "c++11", 13 | "intelliSenseMode": "linux-gcc-arm", 14 | "configurationProvider": "ms-vscode.cmake-tools" 15 | } 16 | ], 17 | "version": 4 18 | } 19 | -------------------------------------------------------------------------------- /.vscode/cmake-kits.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Pico ARM GCC", 4 | "description": "Pico SDK Toolchain with GCC arm-none-eabi", 5 | "toolchainFile": "${env:PICO_SDK_PATH}/cmake/preload/toolchains/pico_arm_gcc.cmake" 6 | } 7 | ] 8 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "marus25.cortex-debug", 4 | "ms-vscode.cmake-tools", 5 | "ms-vscode.cpptools", 6 | "ms-vscode.cpptools-extension-pack", 7 | "ms-vscode.vscode-serial-monitor" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Pico Debug (Cortex-Debug)", 6 | "cwd": "${workspaceFolder}", 7 | "executable": "${command:cmake.launchTargetPath}", 8 | "request": "launch", 9 | "type": "cortex-debug", 10 | "servertype": "openocd", 11 | "gdbPath": "arm-none-eabi-gdb", 12 | "device": "RP2040", 13 | "configFiles": [ 14 | "interface/cmsis-dap.cfg", 15 | "target/rp2040.cfg" 16 | ], 17 | "svdFile": "${env:PICO_SDK_PATH}/src/rp2040/hardware_regs/rp2040.svd", 18 | "runToEntryPoint": "main", 19 | "openOCDLaunchCommands": [ 20 | "adapter speed 1000" 21 | ] 22 | }, 23 | { 24 | "name": "Pico Debug (Cortex-Debug with external OpenOCD)", 25 | "cwd": "${workspaceFolder}", 26 | "executable": "${command:cmake.launchTargetPath}", 27 | "request": "launch", 28 | "type": "cortex-debug", 29 | "servertype": "external", 30 | "gdbTarget": "localhost:3333", 31 | "gdbPath": "arm-none-eabi-gdb", 32 | "device": "RP2040", 33 | "svdFile": "${env:PICO_SDK_PATH}/src/rp2040/hardware_regs/rp2040.svd", 34 | "runToEntryPoint": "main" 35 | }, 36 | { 37 | "name": "Pico Debug (C++ Debugger)", 38 | "type": "cppdbg", 39 | "request": "launch", 40 | "cwd": "${workspaceFolder}", 41 | "program": "${command:cmake.launchTargetPath}", 42 | "MIMode": "gdb", 43 | "miDebuggerPath": "arm-none-eabi-gdb", 44 | "miDebuggerServerAddress": "localhost:3333", 45 | "debugServerPath": "openocd", 46 | "debugServerArgs": "-f interface/cmsis-dap.cfg -f target/rp2040.cfg -c \"adapter speed 1000\"", 47 | "serverStarted": "Listening on port .* for gdb connections", 48 | "filterStderr": true, 49 | "stopAtEntry": true, 50 | "hardwareBreakpoints": { 51 | "require": true, 52 | "limit": 4 53 | }, 54 | "preLaunchTask": "Flash", 55 | "svdPath": "${env:PICO_SDK_PATH}/src/rp2040/hardware_regs/rp2040.svd" 56 | } 57 | ] 58 | } 59 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | // These settings tweaks to the cmake plugin will ensure 3 | // that you debug using cortex-debug instead of trying to launch 4 | // a Pico binary on the host 5 | "cmake.statusbar.advanced": { 6 | "debug": { 7 | "visibility": "hidden" 8 | }, 9 | "launch": { 10 | "visibility": "hidden" 11 | }, 12 | "build": { 13 | "visibility": "hidden" 14 | }, 15 | "buildTarget": { 16 | "visibility": "hidden" 17 | } 18 | }, 19 | "cmake.buildBeforeRun": true, 20 | "cmake.configureOnOpen": true, 21 | "cmake.configureSettings": { 22 | "CMAKE_MODULE_PATH": "${env:PICO_INSTALL_PATH}/pico-sdk-tools" 23 | }, 24 | "cmake.generator": "Ninja", 25 | "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools", 26 | "files.associations": { 27 | "stdlib.h": "c" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "Flash", 6 | "type": "shell", 7 | "command": "openocd", 8 | "args": [ 9 | "-f", 10 | "interface/cmsis-dap.cfg", 11 | "-f", 12 | "target/rp2040.cfg", 13 | "-c", 14 | "adapter speed 1000; program {${command:cmake.launchTargetPath}} verify reset exit" 15 | ], 16 | "problemMatcher": [] 17 | }, 18 | { 19 | "label": "Build", 20 | "type": "cmake", 21 | "command": "build", 22 | "problemMatcher": "$gcc", 23 | "group": { 24 | "kind": "build", 25 | "isDefault": true 26 | } 27 | } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | 3 | set(PROGRAM_NAME pico_w_webserver) 4 | set(PICO_BOARD pico_w) 5 | 6 | include(pico_sdk_import.cmake) 7 | 8 | project(pico_w_webserver) 9 | 10 | pico_sdk_init() 11 | 12 | message("Running makefsdata python script") 13 | execute_process(COMMAND 14 | py makefsdata.py 15 | WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} 16 | ) 17 | 18 | add_executable(${PROGRAM_NAME} 19 | main.c 20 | ) 21 | 22 | target_include_directories(${PROGRAM_NAME} PRIVATE 23 | ${CMAKE_CURRENT_LIST_DIR} 24 | ) 25 | 26 | target_link_libraries(${PROGRAM_NAME} 27 | pico_cyw43_arch_lwip_threadsafe_background 28 | pico_lwip_http 29 | pico_stdlib 30 | hardware_adc 31 | ) 32 | 33 | pico_enable_stdio_usb(${PROGRAM_NAME} TRUE) 34 | pico_enable_stdio_uart(${PROGRAM_NAME} FALSE) 35 | 36 | pico_add_extra_outputs(${PROGRAM_NAME}) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 LearnEmbeddedSystems 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pico-w-webserver-template -------------------------------------------------------------------------------- /cgi.h: -------------------------------------------------------------------------------- 1 | #include "lwip/apps/httpd.h" 2 | #include "pico/cyw43_arch.h" 3 | 4 | // CGI handler which is run when a request for /led.cgi is detected 5 | const char * cgi_led_handler(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]) 6 | { 7 | // Check if an request for LED has been made (/led.cgi?led=x) 8 | if (strcmp(pcParam[0] , "led") == 0){ 9 | // Look at the argument to check if LED is to be turned on (x=1) or off (x=0) 10 | if(strcmp(pcValue[0], "0") == 0) 11 | cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0); 12 | else if(strcmp(pcValue[0], "1") == 0) 13 | cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1); 14 | } 15 | 16 | // Send the index page back to the user 17 | return "/index.shtml"; 18 | } 19 | 20 | // tCGI Struct 21 | // Fill this with all of the CGI requests and their respective handlers 22 | static const tCGI cgi_handlers[] = { 23 | { 24 | // Html request for "/led.cgi" triggers cgi_handler 25 | "/led.cgi", cgi_led_handler 26 | }, 27 | }; 28 | 29 | void cgi_init(void) 30 | { 31 | http_set_cgi_handlers(cgi_handlers, 1); 32 | } -------------------------------------------------------------------------------- /html_files/index.shtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | PicoW Webserver 5 | 6 |

PicoW Webserver Tutorial

7 |
8 |

This bit is SSI:

9 |

Voltage:

10 |

Temp: C

11 |

LED is:

12 |
13 |

This bit is CGI:

14 | 15 | 16 |
17 |
18 | Refresh 19 | 20 | 21 | -------------------------------------------------------------------------------- /htmldata.c: -------------------------------------------------------------------------------- 1 | static const unsigned char data_index_shtml[] = { 2 | /* .\index.shtml */ 3 | 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0, 4 | 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x32, 5 | 0x30, 0x30, 0x20, 0x4f, 0x4b, 0x0d, 0x0a, 0x53, 0x65, 0x72, 6 | 0x76, 0x65, 0x72, 0x3a, 0x20, 0x6c, 0x77, 0x49, 0x50, 0x2f, 7 | 0x70, 0x72, 0x65, 0x2d, 0x30, 0x2e, 0x36, 0x20, 0x28, 0x68, 8 | 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 9 | 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, 10 | 0x64, 0x61, 0x6d, 0x2f, 0x6c, 0x77, 0x69, 0x70, 0x2f, 0x29, 11 | 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 12 | 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 13 | 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x0d, 0x0a, 0x0d, 0x0a, 14 | 0x3c, 0x21, 0x44, 0x4f, 0x43, 0x54, 0x59, 0x50, 0x45, 0x20, 15 | 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0x0d, 0x0a, 0x3c, 0x68, 0x74, 16 | 0x6d, 0x6c, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x3c, 17 | 0x68, 0x65, 0x61, 0x64, 0x3e, 0x20, 0x0d, 0x0a, 0x20, 0x20, 18 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x69, 0x74, 19 | 0x6c, 0x65, 0x3e, 0x50, 0x69, 0x63, 0x6f, 0x57, 0x20, 0x57, 20 | 0x65, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3c, 0x2f, 21 | 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0x20, 0x0d, 0x0a, 0x20, 22 | 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x3e, 23 | 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x62, 0x6f, 0x64, 24 | 0x79, 0x3e, 0x20, 0x3c, 0x68, 0x31, 0x3e, 0x50, 0x69, 0x63, 25 | 0x6f, 0x57, 0x20, 0x57, 0x65, 0x62, 0x73, 0x65, 0x72, 0x76, 26 | 0x65, 0x72, 0x20, 0x54, 0x75, 0x74, 0x6f, 0x72, 0x69, 0x61, 27 | 0x6c, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 28 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x62, 0x72, 0x3e, 29 | 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 30 | 0x3c, 0x68, 0x32, 0x3e, 0x54, 0x68, 0x69, 0x73, 0x20, 0x62, 31 | 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x53, 0x53, 0x49, 0x3a, 32 | 0x3c, 0x2f, 0x68, 0x32, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x20, 33 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x70, 0x3e, 0x56, 0x6f, 34 | 0x6c, 0x74, 0x61, 0x67, 0x65, 0x3a, 0x20, 0x3c, 0x21, 0x2d, 35 | 0x2d, 0x23, 0x76, 0x6f, 0x6c, 0x74, 0x2d, 0x2d, 0x3e, 0x3c, 36 | 0x2f, 0x70, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 37 | 0x20, 0x20, 0x20, 0x3c, 0x70, 0x3e, 0x54, 0x65, 0x6d, 0x70, 38 | 0x3a, 0x20, 0x3c, 0x21, 0x2d, 0x2d, 0x23, 0x74, 0x65, 0x6d, 39 | 0x70, 0x2d, 0x2d, 0x3e, 0x20, 0x43, 0x3c, 0x2f, 0x70, 0x3e, 40 | 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 41 | 0x3c, 0x70, 0x3e, 0x4c, 0x45, 0x44, 0x20, 0x69, 0x73, 0x3a, 42 | 0x20, 0x3c, 0x21, 0x2d, 0x2d, 0x23, 0x6c, 0x65, 0x64, 0x2d, 43 | 0x2d, 0x3e, 0x3c, 0x2f, 0x70, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 44 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x62, 0x72, 0x3e, 45 | 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 46 | 0x3c, 0x68, 0x32, 0x3e, 0x54, 0x68, 0x69, 0x73, 0x20, 0x62, 47 | 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x43, 0x47, 0x49, 0x3a, 48 | 0x3c, 0x2f, 0x68, 0x32, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x20, 49 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x61, 0x20, 0x68, 0x72, 50 | 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x6c, 0x65, 0x64, 0x2e, 0x63, 51 | 0x67, 0x69, 0x3f, 0x6c, 0x65, 0x64, 0x3d, 0x31, 0x22, 0x3e, 52 | 0x3c, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x3e, 0x4c, 0x45, 53 | 0x44, 0x20, 0x4f, 0x4e, 0x3c, 0x2f, 0x62, 0x75, 0x74, 0x74, 54 | 0x6f, 0x6e, 0x3e, 0x3c, 0x2f, 0x61, 0x3e, 0x0d, 0x0a, 0x20, 55 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x61, 0x20, 56 | 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x6c, 0x65, 0x64, 57 | 0x2e, 0x63, 0x67, 0x69, 0x3f, 0x6c, 0x65, 0x64, 0x3d, 0x30, 58 | 0x22, 0x3e, 0x3c, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x3e, 59 | 0x4c, 0x45, 0x44, 0x20, 0x4f, 0x46, 0x46, 0x3c, 0x2f, 0x62, 60 | 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x3e, 0x3c, 0x2f, 0x61, 0x3e, 61 | 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 62 | 0x3c, 0x62, 0x72, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 63 | 0x20, 0x20, 0x20, 0x20, 0x3c, 0x62, 0x72, 0x3e, 0x0d, 0x0a, 64 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x61, 65 | 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x69, 0x6e, 66 | 0x64, 0x65, 0x78, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0x22, 67 | 0x3e, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x3c, 0x2f, 68 | 0x61, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x62, 69 | 0x6f, 0x64, 0x79, 0x3e, 0x0d, 0x0a, 0x3c, 0x2f, 0x68, 0x74, 70 | 0x6d, 0x6c, 0x3e, 0x0d, 0x0a, }; 71 | 72 | const struct fsdata_file file_index_shtml[] = {{ NULL, data_index_shtml, data_index_shtml + 13, sizeof(data_index_shtml) - 13, FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT}}; 73 | 74 | #define FS_ROOT file_index_shtml 75 | #define FS_NUMFILES 1 76 | -------------------------------------------------------------------------------- /lwipopts.h: -------------------------------------------------------------------------------- 1 | // Common settings used in most of the pico_w examples 2 | // (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html for details)] 3 | 4 | // allow override in some examples 5 | #ifndef NO_SYS 6 | #define NO_SYS 1 7 | #endif 8 | // allow override in some examples 9 | #ifndef LWIP_SOCKET 10 | #define LWIP_SOCKET 0 11 | #endif 12 | #if PICO_CYW43_ARCH_POLL 13 | #define MEM_LIBC_MALLOC 1 14 | #else 15 | // MEM_LIBC_MALLOC is incompatible with non polling versions 16 | #define MEM_LIBC_MALLOC 0 17 | #endif 18 | #define MEM_ALIGNMENT 4 19 | #define MEM_SIZE 4000 20 | #define MEMP_NUM_TCP_SEG 32 21 | #define MEMP_NUM_ARP_QUEUE 10 22 | #define PBUF_POOL_SIZE 24 23 | #define LWIP_ARP 1 24 | #define LWIP_ETHERNET 1 25 | #define LWIP_ICMP 1 26 | #define LWIP_RAW 1 27 | #define TCP_WND (8 * TCP_MSS) 28 | #define TCP_MSS 1460 29 | #define TCP_SND_BUF (8 * TCP_MSS) 30 | #define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS)) 31 | #define LWIP_NETIF_STATUS_CALLBACK 1 32 | #define LWIP_NETIF_LINK_CALLBACK 1 33 | #define LWIP_NETIF_HOSTNAME 1 34 | #define LWIP_NETCONN 0 35 | #define MEM_STATS 0 36 | #define SYS_STATS 0 37 | #define MEMP_STATS 0 38 | #define LINK_STATS 0 39 | // #define ETH_PAD_SIZE 2 40 | #define LWIP_CHKSUM_ALGORITHM 3 41 | #define LWIP_DHCP 1 42 | #define LWIP_IPV4 1 43 | #define LWIP_TCP 1 44 | #define LWIP_UDP 1 45 | #define LWIP_DNS 1 46 | #define LWIP_TCP_KEEPALIVE 1 47 | #define LWIP_NETIF_TX_SINGLE_PBUF 1 48 | #define DHCP_DOES_ARP_CHECK 0 49 | #define LWIP_DHCP_DOES_ACD_CHECK 0 50 | 51 | #ifndef NDEBUG 52 | #define LWIP_DEBUG 1 53 | #define LWIP_STATS 1 54 | #define LWIP_STATS_DISPLAY 1 55 | #endif 56 | 57 | #define ETHARP_DEBUG LWIP_DBG_OFF 58 | #define NETIF_DEBUG LWIP_DBG_OFF 59 | #define PBUF_DEBUG LWIP_DBG_OFF 60 | #define API_LIB_DEBUG LWIP_DBG_OFF 61 | #define API_MSG_DEBUG LWIP_DBG_OFF 62 | #define SOCKETS_DEBUG LWIP_DBG_OFF 63 | #define ICMP_DEBUG LWIP_DBG_OFF 64 | #define INET_DEBUG LWIP_DBG_OFF 65 | #define IP_DEBUG LWIP_DBG_OFF 66 | #define IP_REASS_DEBUG LWIP_DBG_OFF 67 | #define RAW_DEBUG LWIP_DBG_OFF 68 | #define MEM_DEBUG LWIP_DBG_OFF 69 | #define MEMP_DEBUG LWIP_DBG_OFF 70 | #define SYS_DEBUG LWIP_DBG_OFF 71 | #define TCP_DEBUG LWIP_DBG_OFF 72 | #define TCP_INPUT_DEBUG LWIP_DBG_OFF 73 | #define TCP_OUTPUT_DEBUG LWIP_DBG_OFF 74 | #define TCP_RTO_DEBUG LWIP_DBG_OFF 75 | #define TCP_CWND_DEBUG LWIP_DBG_OFF 76 | #define TCP_WND_DEBUG LWIP_DBG_OFF 77 | #define TCP_FR_DEBUG LWIP_DBG_OFF 78 | #define TCP_QLEN_DEBUG LWIP_DBG_OFF 79 | #define TCP_RST_DEBUG LWIP_DBG_OFF 80 | #define UDP_DEBUG LWIP_DBG_OFF 81 | #define TCPIP_DEBUG LWIP_DBG_OFF 82 | #define PPP_DEBUG LWIP_DBG_OFF 83 | #define SLIP_DEBUG LWIP_DBG_OFF 84 | #define DHCP_DEBUG LWIP_DBG_OFF 85 | 86 | // This section enables HTTPD server with SSI, SGI 87 | // and tells server which converted HTML files to use 88 | #define LWIP_HTTPD 1 89 | #define LWIP_HTTPD_SSI 1 90 | #define LWIP_HTTPD_CGI 1 91 | #define LWIP_HTTPD_SSI_INCLUDE_TAG 0 92 | #define HTTPD_FSDATA_FILE "htmldata.c" -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include "lwip/apps/httpd.h" 2 | #include "pico/stdlib.h" 3 | #include "pico/cyw43_arch.h" 4 | #include "lwipopts.h" 5 | #include "ssi.h" 6 | #include "cgi.h" 7 | 8 | // WIFI Credentials - take care if pushing to github! 9 | const char WIFI_SSID[] = "XXX"; 10 | const char WIFI_PASSWORD[] = "XXX"; 11 | 12 | int main() { 13 | stdio_init_all(); 14 | 15 | cyw43_arch_init(); 16 | 17 | cyw43_arch_enable_sta_mode(); 18 | 19 | // Connect to the WiFI network - loop until connected 20 | while(cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000) != 0){ 21 | printf("Attempting to connect...\n"); 22 | } 23 | // Print a success message once connected 24 | printf("Connected! \n"); 25 | 26 | // Initialise web server 27 | httpd_init(); 28 | printf("Http server initialised\n"); 29 | 30 | // Configure SSI and CGI handler 31 | ssi_init(); 32 | printf("SSI Handler initialised\n"); 33 | cgi_init(); 34 | printf("CGI Handler initialised\n"); 35 | 36 | // Infinite loop 37 | while(1); 38 | } -------------------------------------------------------------------------------- /makefsdata.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | # This script is by @rspeir on GitHub: 4 | # https://github.com/krzmaz/pico-w-webserver-example/pull/1/files/4b3e78351dd236f213da9bebbb20df690d470476#diff-e675c4a367e382db6f9ba61833a58c62029d8c71c3156a9f238b612b69de279d 5 | # Renamed output to avoid linking incorrect file 6 | 7 | import os 8 | import binascii 9 | 10 | #Create file to write output into 11 | output = open('htmldata.c', 'w') 12 | 13 | #Traverse directory, generate list of files 14 | files = list() 15 | os.chdir('./html_files') 16 | for(dirpath, dirnames, filenames) in os.walk('.'): 17 | files += [os.path.join(dirpath, file) for file in filenames] 18 | 19 | filenames = list() 20 | varnames = list() 21 | 22 | #Generate appropriate HTTP headers 23 | for file in files: 24 | 25 | if '404' in file: 26 | header = "HTTP/1.0 404 File not found\r\n" 27 | else: 28 | header = "HTTP/1.0 200 OK\r\n" 29 | 30 | header += "Server: lwIP/pre-0.6 (http://www.sics.se/~adam/lwip/)\r\n" 31 | 32 | if '.html' in file: 33 | header += "Content-type: text/html\r\n" 34 | elif '.shtml' in file: 35 | header += "Content-type: text/html\r\n" 36 | elif '.jpg' in file: 37 | header += "Content-type: image/jpeg\r\n" 38 | elif '.gif' in file: 39 | header += "Content-type: image/gif\r\n" 40 | elif '.png' in file: 41 | header += "Content-type: image/png\r\n" 42 | elif '.class' in file: 43 | header += "Content-type: application/octet-stream\r\n" 44 | elif '.js' in file: 45 | header += "Content-type: text/javascript\r\n" 46 | elif '.css' in file: 47 | header += "Content-type: text/css\r\n" 48 | elif '.svg' in file: 49 | header += "Content-type: image/svg+xml\r\n" 50 | else: 51 | header += "Content-type: text/plain\r\n" 52 | 53 | header += "\r\n" 54 | 55 | fvar = file[1:] #remove leading dot in filename 56 | fvar = fvar.replace('/', '_') #replace *nix path separator with underscore 57 | fvar = fvar.replace('\\', '_') #replace DOS path separator with underscore 58 | fvar = fvar.replace('.', '_') #replace file extension dot with underscore 59 | 60 | output.write("static const unsigned char data{}[] = {{\n".format(fvar)) 61 | output.write("\t/* {} */\n\t".format(file)) 62 | 63 | #first set of hex data encodes the filename 64 | b = bytes(file[1:].replace('\\', '/'), 'utf-8') #change DOS path separator to forward slash 65 | for byte in binascii.hexlify(b, b' ', 1).split(): 66 | output.write("0x{}, ".format(byte.decode())) 67 | output.write("0,\n\t") 68 | 69 | #second set of hex data is the HTTP header/mime type we generated above 70 | b = bytes(header, 'utf-8') 71 | count = 0 72 | for byte in binascii.hexlify(b, b' ', 1).split(): 73 | output.write("0x{}, ".format(byte.decode())) 74 | count = count + 1 75 | if(count == 10): 76 | output.write("\n\t") 77 | count = 0 78 | output.write("\n\t") 79 | 80 | #finally, dump raw hex data from files 81 | with open(file, 'rb') as f: 82 | count = 0 83 | while(byte := f.read(1)): 84 | byte = binascii.hexlify(byte) 85 | output.write("0x{}, ".format(byte.decode())) 86 | count = count + 1 87 | if(count == 10): 88 | output.write("\n\t") 89 | count = 0 90 | output.write("};\n\n") 91 | 92 | filenames.append(file[1:]) 93 | varnames.append(fvar) 94 | 95 | for i in range(len(filenames)): 96 | prevfile = "NULL" 97 | if(i > 0): 98 | prevfile = "file" + varnames[i-1] 99 | 100 | output.write("const struct fsdata_file file{0}[] = {{{{ {1}, data{2}, ".format(varnames[i], prevfile, varnames[i])) 101 | output.write("data{} + {}, ".format(varnames[i], len(filenames[i]) + 1)) 102 | output.write("sizeof(data{}) - {}, ".format(varnames[i], len(filenames[i]) + 1)) 103 | output.write("FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT}};\n") 104 | 105 | output.write("\n#define FS_ROOT file{}\n".format(varnames[-1])) 106 | output.write("#define FS_NUMFILES {}\n".format(len(filenames))) -------------------------------------------------------------------------------- /pico_sdk_import.cmake: -------------------------------------------------------------------------------- 1 | # This is a copy of /external/pico_sdk_import.cmake 2 | 3 | # This can be dropped into an external project to help locate this SDK 4 | # It should be include()ed prior to project() 5 | 6 | if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) 7 | set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) 8 | message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") 9 | endif () 10 | 11 | if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) 12 | set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) 13 | message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") 14 | endif () 15 | 16 | if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) 17 | set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) 18 | message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") 19 | endif () 20 | 21 | set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") 22 | set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") 23 | set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") 24 | 25 | if (NOT PICO_SDK_PATH) 26 | if (PICO_SDK_FETCH_FROM_GIT) 27 | include(FetchContent) 28 | set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) 29 | if (PICO_SDK_FETCH_FROM_GIT_PATH) 30 | get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") 31 | endif () 32 | # GIT_SUBMODULES_RECURSE was added in 3.17 33 | if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") 34 | FetchContent_Declare( 35 | pico_sdk 36 | GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk 37 | GIT_TAG master 38 | GIT_SUBMODULES_RECURSE FALSE 39 | ) 40 | else () 41 | FetchContent_Declare( 42 | pico_sdk 43 | GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk 44 | GIT_TAG master 45 | ) 46 | endif () 47 | 48 | if (NOT pico_sdk) 49 | message("Downloading Raspberry Pi Pico SDK") 50 | FetchContent_Populate(pico_sdk) 51 | set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) 52 | endif () 53 | set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) 54 | else () 55 | message(FATAL_ERROR 56 | "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." 57 | ) 58 | endif () 59 | endif () 60 | 61 | get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") 62 | if (NOT EXISTS ${PICO_SDK_PATH}) 63 | message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") 64 | endif () 65 | 66 | set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) 67 | if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) 68 | message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") 69 | endif () 70 | 71 | set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) 72 | 73 | include(${PICO_SDK_INIT_CMAKE_FILE}) 74 | -------------------------------------------------------------------------------- /ssi.h: -------------------------------------------------------------------------------- 1 | #include "lwip/apps/httpd.h" 2 | #include "pico/cyw43_arch.h" 3 | #include "hardware/adc.h" 4 | 5 | // SSI tags - tag length limited to 8 bytes by default 6 | const char * ssi_tags[] = {"volt","temp","led"}; 7 | 8 | u16_t ssi_handler(int iIndex, char *pcInsert, int iInsertLen) { 9 | size_t printed; 10 | switch (iIndex) { 11 | case 0: // volt 12 | { 13 | const float voltage = adc_read() * 3.3f / (1 << 12); 14 | printed = snprintf(pcInsert, iInsertLen, "%f", voltage); 15 | } 16 | break; 17 | case 1: // temp 18 | { 19 | const float voltage = adc_read() * 3.3f / (1 << 12); 20 | const float tempC = 27.0f - (voltage - 0.706f) / 0.001721f; 21 | printed = snprintf(pcInsert, iInsertLen, "%f", tempC); 22 | } 23 | break; 24 | case 2: // led 25 | { 26 | bool led_status = cyw43_arch_gpio_get(CYW43_WL_GPIO_LED_PIN); 27 | if(led_status == true){ 28 | printed = snprintf(pcInsert, iInsertLen, "ON"); 29 | } 30 | else{ 31 | printed = snprintf(pcInsert, iInsertLen, "OFF"); 32 | } 33 | } 34 | break; 35 | default: 36 | printed = 0; 37 | break; 38 | } 39 | 40 | return (u16_t)printed; 41 | } 42 | 43 | // Initialise the SSI handler 44 | void ssi_init() { 45 | // Initialise ADC (internal pin) 46 | adc_init(); 47 | adc_set_temp_sensor_enabled(true); 48 | adc_select_input(4); 49 | 50 | http_set_ssi_handler(ssi_handler, ssi_tags, LWIP_ARRAYSIZE(ssi_tags)); 51 | } 52 | --------------------------------------------------------------------------------