diff --git a/.gitignore b/.gitignore index 99a7f15..7876d29 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,6 @@ Makefile # Python cache (pico sdk tools) __pycache__/ *.pyc + +# FS +fsdata.c diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..9cdd037 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,57 @@ +cmake_minimum_required(VERSION 3.13) +set(PICO_BOARD pico_w) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(PICO_SDK_PATH ${CMAKE_SOURCE_DIR}/pico-sdk) + +# Pico SDK einbinden – MUSS vor project() stehen +include(${PICO_SDK_PATH}/external/pico_sdk_import.cmake) + + +project(sensor-pico C CXX ASM) +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) + +pico_sdk_init() + +add_subdirectory(lib/bme280 bme280_build) +add_subdirectory(lib/dhcp_server dhcp_server_build) + +add_custom_command( + OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/src/fsdata.c + COMMAND perl ${PICO_SDK_PATH}/lib/lwip/src/apps/http/makefsdata/makefsdata + COMMAND ${CMAKE_COMMAND} -E rename fsdata.c src/fsdata.c + COMMAND ${CMAKE_COMMAND} + -P ${CMAKE_CURRENT_SOURCE_DIR}/prepend_include.cmake + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS ${CMAKE_SOURCE_DIR}/fs/index.html +) + + +add_executable(sensor-pico + src/main.cpp + src/webserver.c + src/fsdata.c +) + + +# Standard Ein-/Ausgabe über USB (du siehst printf im Terminal) +pico_enable_stdio_usb(sensor-pico 1) +pico_enable_stdio_uart(sensor-pico 0) + +target_include_directories(sensor-pico PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} +) + +# Benötigte Bibliotheken +target_link_libraries(sensor-pico + pico_stdlib + pico_cyw43_arch_lwip_threadsafe_background + bme280 + dhcp_server + pico_lwip + pico_lwip_http +) + +# Erzeugt .uf2 Datei zum Flashen +pico_add_extra_outputs(sensor-pico) diff --git a/sensor-pico/CMakeLists.txt b/CMakeLists.txt.save similarity index 85% rename from sensor-pico/CMakeLists.txt rename to CMakeLists.txt.save index 8172c5b..9698ee2 100644 --- a/sensor-pico/CMakeLists.txt +++ b/CMakeLists.txt.save @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13) set(PICO_BOARD pico_w) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -set(PICO_SDK_PATH ${CMAKE_SOURCE_DIR}/../pico-sdk) +set(PICO_SDK_PATH ${CMAKE_SOURCE_DIR}/pico-sdk) # Pico SDK einbinden – MUSS vor project() stehen include(${PICO_SDK_PATH}/external/pico_sdk_import.cmake) @@ -14,14 +14,16 @@ set(CMAKE_CXX_STANDARD 17) pico_sdk_init() -add_subdirectory(../lib/bme280 bme280_build) -add_subdirectory(../lib/dhcp_server dhcp_server_build) +add_subdirectory(lib/bme280 bme280_build) +add_subdirectory(lib/dhcp_server dhcp_server_build) add_executable(sensor-pico src/main.cpp src/webserver.c ) + + # Standard Ein-/Ausgabe über USB (du siehst printf im Terminal) pico_enable_stdio_usb(sensor-pico 1) pico_enable_stdio_uart(sensor-pico 0) diff --git a/PROJEKT.md b/PROJEKT.md new file mode 100644 index 0000000..8324ba4 --- /dev/null +++ b/PROJEKT.md @@ -0,0 +1,377 @@ +# Raspberry Pi Pico W – Sensor Projekt + +## Regeln +- Claude erklärt Konzepte und gibt Hinweise, aber **kein fertiger Code** +- Ich schreibe den Code selbst +- Bei Fehlern analysieren wir gemeinsam +- Ausnahme: Setup und Boilerplate darf vorgegeben werden + +--- + +## Hardware + +| Komponente | Protokoll | Misst | +|---|---|---| +| Raspberry Pi Pico W | – | Mikrocontroller mit WLAN | +| BME280 (GY-BME280) | I2C (Adresse 0x76) | Temperatur + Luftdruck + Luftfeuchtigkeit | + +> AM2302 und DS18B20 werden nicht verwendet – BME280 liefert alle benötigten Messwerte. + +--- + +## Entwicklungsumgebung + +### System +- CachyOS (Arch-basiert) +- VS Code + +### Installierte Tools +```bash +sudo pacman -S arm-none-eabi-gcc arm-none-eabi-newlib cmake ninja git python +sudo pacman -S minicom +``` + +### VS Code Extensions +- C/C++ (ms-vscode.cpptools) +- CMake Tools (ms-vscode.cmake-tools) +- CMake (twxs.cmake) +- Serial Monitor (ms-vscode.vscode-serial-monitor) +- Raspberry Pi Pico (raspberry-pi.raspberry-pi-pico) + +### Serieller Monitor +- Port: `/dev/ttyACM0` +- Baud Rate: `115200` +- Gruppe für Zugriff: `uucp` +```bash +sudo usermod -aG uucp $USER +# Dann neu einloggen! +``` + +--- + +## Projekt Struktur + +Das Repo heißt `sensor-pico` und ist gleichzeitig der Root – keine extra Ebene darüber. + +``` +sensor-pico/ ← Git Repo Root +├── pico-sdk/ ← Git Submodule (Raspberry Pi Pico SDK) +├── lib/ +│ ├── bme280/ ← Git Submodule (lafftale1999/bme280_driver) +│ └── dhcp_server/ ← DHCP Server (von pico-examples, kein Submodule) +├── src/ +│ ├── main.cpp ← Hauptprogramm +│ ├── webserver.c ← lwIP httpd Initialisierung + CGI-Handler +│ └── fsdata.c ← Generiert von makefsdata, nicht im Git! +├── fs/ +│ └── index.html ← Weboberfläche, wird beim Build eingebaut +├── build/ ← Von cmake generiert, nicht im Git +├── CMakeLists.txt +├── lwipopts.h ← lwIP Konfiguration +└── prepend_include.cmake ← Hilfsskript für makefsdata-Build-Schritt +``` + +### Git Submodule +``` +[submodule "lib/bme280"] + path = lib/bme280 + url = git@github.com:lafftale1999/bme280_driver.git + +[submodule "pico-sdk"] + path = pico-sdk + url = https://github.com/raspberrypi/pico-sdk.git +``` + +### .gitignore +``` +build/ +.vscode/ +CMakeCache.txt +CMakeFiles/ +cmake_install.cmake +Makefile +*.uf2 +*.elf +*.bin +*.hex +*.map +*.dis +__pycache__/ +*.pyc +src/fsdata.c +``` + +> `src/fsdata.c` wird beim Build automatisch generiert und gehört nicht ins Repo. + +--- + +## CMakeLists.txt (aktueller Stand) + +```cmake +cmake_minimum_required(VERSION 3.13) +set(PICO_BOARD pico_w) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(PICO_SDK_PATH ${CMAKE_SOURCE_DIR}/pico-sdk) + +include(${PICO_SDK_PATH}/external/pico_sdk_import.cmake) + +project(sensor-pico C CXX ASM) +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) + +pico_sdk_init() + +add_subdirectory(lib/bme280 bme280_build) +add_subdirectory(lib/dhcp_server dhcp_server_build) + +# makefsdata: fs/index.html → src/fsdata.c +add_custom_command( + OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/src/fsdata.c + COMMAND perl ${PICO_SDK_PATH}/lib/lwip/src/apps/http/makefsdata/makefsdata + COMMAND ${CMAKE_COMMAND} -E rename fsdata.c src/fsdata.c + COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/prepend_include.cmake + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS ${CMAKE_SOURCE_DIR}/fs/index.html +) + +add_executable(sensor-pico + src/main.cpp + src/webserver.c + src/fsdata.c +) + +pico_enable_stdio_usb(sensor-pico 1) +pico_enable_stdio_uart(sensor-pico 0) + +target_include_directories(sensor-pico PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} +) + +target_link_libraries(sensor-pico + pico_stdlib + pico_cyw43_arch_lwip_threadsafe_background + pico_lwip + pico_lwip_http + bme280 + dhcp_server +) + +pico_add_extra_outputs(sensor-pico) +``` + +--- + +## prepend_include.cmake + +Dieses Script wird von CMake als Build-Schritt ausgeführt und fügt den fehlenden `#include` an den Anfang der generierten `fsdata.c` ein. Nötig weil das alte Perl-Script von lwIP keinen Header einfügt. + +```cmake +file(READ "src/fsdata.c" CONTENT) +file(WRITE "src/fsdata.c" "#include \"lwip/apps/fs.h\"\n${CONTENT}") +``` + +> Warum nicht direkt Perl dafür? CMake-Scripts haben kein Shell-Quoting-Problem – `file(READ/WRITE)` arbeitet direkt mit dem Dateisystem, ohne Shell-Umweg. + +--- + +## Build & Flash Workflow + +```bash +# Erstes Setup (nur einmal) +mkdir build + +# Bauen +cd build +cmake .. -DPICO_BOARD=pico_w # PICO_BOARD muss explizit angegeben werden! +make -j$(nproc) + +# Was passiert beim Build automatisch: +# 1. makefsdata liest fs/index.html +# 2. Generiert fsdata.c mit HTML-Inhalt als Byte-Array +# 3. Verschiebt fsdata.c nach src/fsdata.c +# 4. prepend_include.cmake fügt #include "lwip/apps/fs.h" ein +# 5. fsdata.c wird mitkompiliert + +# Flashen +# 1. BOOTSEL gedrückt halten +# 2. USB einstecken +# 3. Taste loslassen +# 4. RPI-RP2 erscheint als Laufwerk +cp sensor-pico.uf2 /run/media/$USER/RPI-RP2/ +``` + +--- + +## Verkabelung + +**I2C (BME280):** +``` +VCC → 3.3V (Pin 36) +GND → GND +SDA → GPIO 14 (Pin 19) ← Vorgabe der bme280-Bibliothek (i2c1) +SCL → GPIO 15 (Pin 20) ← Vorgabe der bme280-Bibliothek (i2c1) +``` + +--- + +## BME280 Messwerte + +Die Bibliothek gibt skalierte Integer zurück – kein Floating Point, üblich auf Embedded-Systemen wegen Speicher und Geschwindigkeit. + +| Wert | Skalierung | Beispiel | Umrechnung | +|---|---|---|---| +| Temperatur | × 100 | 2494 | `/ 100` → 24.94°C | +| Luftfeuchtigkeit | × 1024 | 30759 | `/ 1024` → 30.0% | +| Luftdruck | × 256 (Pa) | 26074767 | `/ 256 / 100` → 1018.54 hPa | + +JSON-Ausgabe per `bme280_get_json(handle)`: +```json +{"temperature":2494,"humidity":30759,"pressure":26074767} +``` + +Die Umrechnung kann auf dem Empfänger (z.B. Home Assistant) gemacht werden – der Pico sendet die Rohwerte. + +Lesbare Ausgabe per printf möglich: +```c +printf("Temp: %d.%02d C\n", temperature / 100, temperature % 100); +``` + +--- + +## Netzwerk / Webserver + +### Architektur + +Der Pico hat zwei Betriebsmodi: + +**Modus 1 – Erststart / Konfiguration (Access Point)** +- Pico öffnet einen eigenen Access Point (`SensorAP`, WPA2) +- DHCP-Server läuft – Clients bekommen automatisch eine IP (`192.168.4.x`) +- Pico ist erreichbar unter `192.168.4.1` +- Weboberfläche zeigt Konfigurationsformular + +**Modus 2 – Produktionsbetrieb (Station Mode)** +- Pico verbindet sich mit bestehendem WLAN (gespeicherte SSID + Passwort) +- Publisht Sensordaten per MQTT an Broker +- Webserver läuft weiterhin: Live-Daten + Einstellungen änderbar + +### Aktueller Stand +- ✅ Access Point (`SensorAP`, WPA2) öffnet sich +- ✅ DHCP-Server läuft – Clients bekommen IP +- ✅ Pico erreichbar unter `192.168.4.1` +- ✅ lwIP httpd läuft – Index-Seite wird ausgeliefert +- ✅ `makefsdata` automatisch im Build-Prozess eingebunden +- ✅ `fs/index.html` wird beim Build als Byte-Array in Firmware eingebaut + +### Geplante Anforderungen +1. Beim Erststart: Access Point für Erstkonfiguration +2. Weboberfläche zum Einstellen von: + - WLAN SSID + Passwort + - MQTT Broker (Adresse, Port, User, Passwort) + - Sendefrequenz +3. Im Produktionsbetrieb: Live-Daten + Einstellungen änderbar + +### makefsdata – wie es funktioniert + +`makefsdata` ist ein Perl-Script im lwIP-Quellcode: +``` +pico-sdk/lib/lwip/src/apps/http/makefsdata/makefsdata +``` + +Es liest alle Dateien aus dem `fs/`-Ordner und erzeugt daraus eine `fsdata.c` mit dem Dateiinhalt als statische Byte-Arrays. lwIP httpd schaut zur Laufzeit in dieser Datei nach statt auf einem echten Dateisystem. + +**Problem:** Das Script generiert `fsdata.c` ohne den nötigen `#include "lwip/apps/fs.h"` – der Compiler kennt dann weder `struct fsdata_file` noch `FS_FILE_FLAGS_*`. +**Lösung:** `prepend_include.cmake` fügt den Include als CMake-Build-Schritt nach der Generierung ein. + +### lwipopts.h +```c +#define NO_SYS 1 +#define LWIP_SOCKET 0 +#define LWIP_NETCONN 0 +#define LWIP_IPV4 1 +#define LWIP_TCP 1 +#define LWIP_UDP 1 +#define LWIP_DHCP 1 +#define LWIP_DNS 1 +#define LWIP_RAW 1 +#define LWIP_ARP 1 +#define LWIP_ETHERNET 1 +#define LWIP_ICMP 1 +#define LWIP_NETIF_HOSTNAME 1 +#define LWIP_NETIF_STATUS_CALLBACK 1 +#define MEM_ALIGNMENT 4 +#define MEM_SIZE 4000 +#define MEMP_NUM_TCP_SEG 32 +#define PBUF_POOL_SIZE 24 +#define TCP_MSS 1460 +#define TCP_WND (8 * TCP_MSS) +#define TCP_SND_BUF (8 * TCP_MSS) +#define LWIP_HTTPD 1 +#define LWIP_HTTPD_CGI 1 +#define LWIP_HTTPD_SSI 1 +``` + +--- + +## Nächste Schritte + +- [x] `makefsdata` automatisch in cmake einbinden damit `fs/index.html` beim Build in die Firmware eingebaut wird +- [ ] Konfigurationsformular in `index.html` (WLAN + MQTT + Sendefrequenz) +- [ ] CGI-Handler in `webserver.c` für POST-Request vom Formular +- [ ] Einstellungen im Flash speichern +- [ ] WLAN Station Mode (Verbindung mit bestehendem Netz) +- [ ] MQTT einbinden + +--- + +## Gelerntes + +### Konzepte + +- **I2C** – Bus-Protokoll, alle Geräte an 2 Drähten (SDA + SCL), jedes Gerät hat eine Adresse +- **Hexadezimal** – `0x` Prefix, 16 Ziffern (0-9, A-F) +- **ACK/NACK** – Antwort/keine Antwort bei I2C Kommunikation +- **Handle** – "Ticket" auf ein intern verwaltetes Objekt (Garderobe-Analogie) +- **Pull-up Widerstand** – nötig bei I2C und OneWire +- **printf** – Formatstring mit Platzhaltern (`%d`, `%s`, `%02X`), Zeilenumbruch mit `\n` +- **&variable** – Adressoperator, gibt Speicheradresse zurück +- **uint8_t** – 8-bit unsigned integer, genau 1 Byte +- **void** – Rückgabetyp wenn Funktion nichts zurückgibt +- **Embedded** – kein `std::cout`, `printf` bevorzugen wegen Speicher +- **IP-Adresse** – eindeutige Adresse im Netzwerk, 4 Zahlen (0-255) +- **Netzmaske** – definiert welcher Teil der IP das Netzwerk ist (`255.255.255.0`) +- **DHCP** – verteilt automatisch IP-Adressen an Geräte im Netzwerk +- **lwIP** – schlanker TCP/IP Stack für Embedded-Systeme +- **fsdata** – HTML-Dateien werden beim Build als C-Bytes in die Firmware eingebaut +- **makefsdata** – Perl-Script das `fs/`-Ordner in `fsdata.c` Byte-Array konvertiert +- **extern "C"** – verhindert C++ Name Mangling bei C-Bibliotheken +- **Name Mangling** – C++ kodiert Funktionsnamen mit Typinfo im Symbol (für Overloading); C nicht – das verursacht Linker-Fehler wenn man C-Bibliotheken aus C++ nutzt ohne `extern "C"` +- **-j$(nproc)** – paralleles Bauen mit allen CPU-Kernen +- **add_custom_command** – CMake-Befehl um externe Programme als Build-Schritt auszuführen; mit `OUTPUT` weiß CMake welche Datei erzeugt wird und wann neu gebaut werden muss +- **${CMAKE_COMMAND} -E** – plattformunabhängige CMake-Dateibefehle (rename, copy, remove) ohne Shell-Abhängigkeit +- **${CMAKE_COMMAND} -P** – führt ein CMake-Script direkt aus, ohne Shell-Umweg und ohne Quoting-Probleme +- **GET vs POST** – GET-Parameter landen in der URL (sichtbar, in Logs), POST-Daten im Body – für Passwörter immer POST + +### CMake-Konzepte + +- **add_subdirectory** – bindet einen Unterordner mit eigenem CMakeLists.txt ein; zweiter Parameter ist der Build-Unterordner +- **target_include_directories** – sagt dem Compiler wo er Header-Dateien suchen soll; `PRIVATE` = nur für dieses Target +- **target_link_libraries** – verknüpft Bibliotheken mit dem Executable +- **add_custom_command OUTPUT** – definiert wie eine generierte Datei erzeugt wird; CMake führt den Befehl aus wenn die Datei fehlt oder Abhängigkeiten neuer sind +- **DEPENDS in add_custom_command** – wenn diese Dateien sich ändern, wird der Befehl beim nächsten Build neu ausgeführt + +### Pico W Besonderheiten + +- Interne LED hängt am WLAN-Chip (CYW43), nicht an GPIO 25 +- Braucht `pico_cyw43_arch_none` (ohne Netzwerk) oder `pico_cyw43_arch_lwip_threadsafe_background` (mit lwIP) +- `PICO_BOARD=pico_w` muss **vor** `pico_sdk_import.cmake` gesetzt werden +- `MEM_LIBC_MALLOC` ist inkompatibel mit `threadsafe_background` +- `lwipopts.h` muss selbst erstellt werden – lwIP hat keine Defaults +- lwIP httpd CGI erwartet C-Funktionen – in `.cpp`-Dateien mit `extern "C"` wrappen + +### Bekannte Fallstricke + +- `makefsdata` generiert `fsdata.c` ohne `#include "lwip/apps/fs.h"` → Compiler kennt `struct fsdata_file` nicht → `prepend_include.cmake` als Workaround +- Shell-Quoting in CMake `COMMAND` ist fehleranfällig bei komplexen Perl-Ausdrücken → CMake-Scripts (`-P`) verwenden statt Shell-Befehle +- `add_custom_command OUTPUT` mit relativem Pfad legt die Datei im Build-Verzeichnis ab, nicht im Source-Verzeichnis → immer absoluten Pfad mit `${CMAKE_CURRENT_SOURCE_DIR}` angeben diff --git a/sensor-pico/fs/index.html b/fs/index.html similarity index 91% rename from sensor-pico/fs/index.html rename to fs/index.html index f4b8565..bbf8d63 100644 --- a/sensor-pico/fs/index.html +++ b/fs/index.html @@ -4,7 +4,6 @@ Konfiguration -

WLAN Einstellungen

diff --git a/lib/dhcp_server/dhcp_server.h b/lib/dhcp_server/dhcp_server.h index e3d61f2..89edca7 100644 --- a/lib/dhcp_server/dhcp_server.h +++ b/lib/dhcp_server/dhcp_server.h @@ -24,13 +24,13 @@ * THE SOFTWARE. */ +#ifndef MICROPY_INCLUDED_LIB_NETUTILS_DHCPSERVER_H +#define MICROPY_INCLUDED_LIB_NETUTILS_DHCPSERVER_H + #ifdef __cplusplus extern "C" { #endif -#ifndef MICROPY_INCLUDED_LIB_NETUTILS_DHCPSERVER_H -#define MICROPY_INCLUDED_LIB_NETUTILS_DHCPSERVER_H - #include "lwip/ip_addr.h" #define DHCPS_BASE_IP (16) @@ -51,8 +51,8 @@ typedef struct _dhcp_server_t { void dhcp_server_init(dhcp_server_t *d, ip_addr_t *ip, ip_addr_t *nm); void dhcp_server_deinit(dhcp_server_t *d); -#endif // MICROPY_INCLUDED_LIB_NETUTILS_DHCPSERVER_H - #ifdef __cplusplus } #endif + +#endif // MICROPY_INCLUDED_LIB_NETUTILS_DHCPSERVER_H diff --git a/sensor-pico/lwipopts.h b/lwipopts.h similarity index 100% rename from sensor-pico/lwipopts.h rename to lwipopts.h diff --git a/prepend_include.cmake b/prepend_include.cmake new file mode 100644 index 0000000..0bcf56f --- /dev/null +++ b/prepend_include.cmake @@ -0,0 +1,2 @@ +file(READ "src/fsdata.c" CONTENT) +file(WRITE "src/fsdata.c" "#include \"lwip/apps/fs.h\"\n${CONTENT}") diff --git a/sensor-pico/fs/style.css b/sensor-pico/fs/style.css deleted file mode 100644 index e69de29..0000000 diff --git a/sensor-pico/src/main.cpp b/sensor-pico/src/main.cpp deleted file mode 100644 index 3d19a44..0000000 --- a/sensor-pico/src/main.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "bme280.h" -#include "dhcp_server.h" -#include "hardware/i2c.h" -#include "lwip/apps/httpd.h" -#include "pico/cyw43_arch.h" -#include "pico/stdlib.h" -#include - -int main() { - stdio_init_all(); - sleep_ms(3000); - cyw43_arch_init(); - cyw43_arch_enable_ap_mode("SensorAP", "passwort123", CYW43_AUTH_WPA2_AES_PSK); - - ip_addr_t gw{}; - ip_addr_t mask{}; - IP4_ADDR(&gw, 192, 168, 4, 1); - IP4_ADDR(&mask, 255, 255, 255, 0); - - dhcp_server_t dhcp_server; - dhcp_server_init(&dhcp_server, &gw, &mask); - - httpd_init(); - - while (true) { - cyw43_arch_poll(); - sleep_ms(100); - } -} diff --git a/sensor-pico/src/webserver.c b/sensor-pico/src/webserver.c deleted file mode 100644 index d71b938..0000000 --- a/sensor-pico/src/webserver.c +++ /dev/null @@ -1 +0,0 @@ -// to be continued diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..3803914 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,55 @@ +#include "bme280.h" +#include "dhcp_server.h" +#include "hardware/i2c.h" +#include "lwip/apps/httpd.h" +#include "pico/cyw43_arch.h" +#include "pico/stdlib.h" +#include "webserver.h" +#include +#include + +void ap_init() { + cyw43_arch_enable_ap_mode("SensorAP", "passwort123", CYW43_AUTH_WPA2_AES_PSK); + + ip_addr_t gw{}; + ip_addr_t mask{}; + IP4_ADDR(&gw, 192, 168, 4, 1); + IP4_ADDR(&mask, 255, 255, 255, 0); + + static dhcp_server_t dhcp_server{}; + dhcp_server_init(&dhcp_server, &gw, &mask); +} + +int main() { + + stdio_init_all(); + sleep_ms(3000); + cyw43_arch_init(); + httpd_init(); + webserver_init(); + + while (true) { + memset(saved_ssid, 0, sizeof(saved_ssid)); + memset(saved_password, 0, sizeof(saved_password)); + ap_init(); + + while (saved_ssid[0] == '\0') { + cyw43_arch_poll(); + sleep_ms(100); + } + cyw43_arch_disable_ap_mode(); + cyw43_arch_enable_sta_mode(); + + if (!(cyw43_arch_wifi_connect_timeout_ms(saved_ssid, saved_password, + CYW43_AUTH_WPA2_AES_PSK, 20000))) { + break; + } + } + + while (true) { + cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1); + sleep_ms(200); + cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0); + sleep_ms(200); + } +} diff --git a/src/webserver.c b/src/webserver.c new file mode 100644 index 0000000..7d3899d --- /dev/null +++ b/src/webserver.c @@ -0,0 +1,22 @@ +#include "lwip/apps/httpd.h" +#include "string.h" + +char saved_ssid[33]; +char saved_password[65]; + +static const char *config_handler(int iIndex, int iNumParams, char *pcParam[], + char *pcValue[]) { + for (int i = 0; i < iNumParams; i++) { + if (strcmp(pcParam[i], "ssid") == 0) { + strncpy(saved_ssid, pcValue[i], 32); + } + if (strcmp(pcParam[i], "password") == 0) { + strncpy(saved_password, pcValue[i], 64); + } + } + return "/index.html"; +} + +static const tCGI cgi_handlers[] = {{"/config", config_handler}}; + +void webserver_init(void) { http_set_cgi_handlers(cgi_handlers, 1); } diff --git a/src/webserver.h b/src/webserver.h new file mode 100644 index 0000000..66ad397 --- /dev/null +++ b/src/webserver.h @@ -0,0 +1,17 @@ +#ifndef WEBSERVER_H +#define WEBSERVER_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern char saved_ssid[33]; +extern char saved_password[65]; + +void webserver_init(void); + +#ifdef __cplusplus +} +#endif + +#endif