├── .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 |
--------------------------------------------------------------------------------