// Copyright (c) 2025 Cesanta Software Limited // All rights reserved #include "mongoose.h" #include "hal.h" #define WIFI_SSID "YOUR_WIFI_NETWORK_NAME" // SET THIS! #define WIFI_PASS "YOUR_WIFI_PASSWORD" // SET THIS! static const struct mg_tcpip_spi spi = {NULL, hwspecific_spi_begin, hwspecific_spi_end, hwspecific_spi_txn}; #ifndef CYW43_RESOURCE_ATTRIBUTE #define CYW43_RESOURCE_ATTRIBUTE #endif #include "pico-sdk/lib/cyw43-driver/firmware/w43439A0_7_95_49_00_combined.h" #include "pico-sdk/lib/cyw43-driver/firmware/wifi_nvram_43439.h" static const struct mg_tcpip_driver_cyw_firmware fw = { (const uint8_t *)w43439A0_7_95_49_00_combined, (size_t)CYW43_WIFI_FW_LEN, (const uint8_t *)wifi_nvram_4343, (size_t)sizeof(wifi_nvram_4343), (const uint8_t *)(w43439A0_7_95_49_00_combined + sizeof(w43439A0_7_95_49_00_combined) - CYW43_CLM_LEN), (size_t)CYW43_CLM_LEN}; // mif user states enum {AP, SCANNING, STOPPING_AP, CONNECTING, READY}; static unsigned int state; static void mif_fn(struct mg_tcpip_if *ifp, int ev, void *ev_data) { // TODO(): should we include this inside ifp ? add an fn_data ? if (ev == MG_TCPIP_EV_ST_CHG) { MG_INFO(("State change: %u", *(uint8_t *) ev_data)); } switch(state) { case AP: // we are in AP mode, wait for a user connection to trigger a scan or a connection to a network if (ev == MG_TCPIP_EV_ST_CHG && *(uint8_t *) ev_data == MG_TCPIP_STATE_READY) { MG_INFO(("Access Point READY !")); // simulate user request to scan for networks bool res = mg_wifi_scan(); MG_INFO(("Starting scan: %s", res ? "OK":"FAIL")); if (res) state = SCANNING; } break; case SCANNING: if (ev == MG_TCPIP_EV_WIFI_SCAN_RESULT) { struct mg_wifi_scan_bss_data *bss = (struct mg_wifi_scan_bss_data *) ev_data; MG_INFO(("BSS: %.*s (%u) (%M) %d dBm %u", bss->SSID.len, bss->SSID.buf, bss->channel, mg_print_mac, bss->BSSID, (int) bss->RSSI, bss->security)); } else if (ev == MG_TCPIP_EV_WIFI_SCAN_END) { //struct mg_tcpip_driver_cyw_data *d = (struct mg_tcpip_driver_cyw_data *) ifp->driver_data; MG_INFO(("Wi-Fi scan finished")); // simulate user selection of a network (1/2: stop AP) bool res = mg_wifi_ap_stop(); MG_INFO(("Manually stopping AP: %s", res ? "OK":"FAIL")); if (res) state = STOPPING_AP; // else we have a hw/fw problem } break; case STOPPING_AP: if (ev == MG_TCPIP_EV_ST_CHG && *(uint8_t *) ev_data == MG_TCPIP_STATE_DOWN) { struct mg_wifi_data *wifi = &((struct mg_tcpip_driver_cyw_data *) ifp->driver_data)->wifi; wifi->apmode = false; // simulate user selection of a network (2/2: actual connect) bool res = mg_wifi_connect(wifi); MG_INFO(("Manually connecting: %s", res ? "OK":"FAIL")); if (res) { state = CONNECTING; } // else manually start AP as below } break; case CONNECTING: if (ev == MG_TCPIP_EV_ST_CHG && *(uint8_t *) ev_data == MG_TCPIP_STATE_READY) { MG_INFO(("READY!")); state = READY; // simulate user code disconnection and go back to AP mode (1/2: disconnect) bool res = mg_wifi_disconnect(); MG_INFO(("Manually disconnecting: %s", res ? "OK":"FAIL")); } else if (ev == MG_TCPIP_EV_WIFI_CONNECT_ERR) { MG_ERROR(("Wi-Fi connect failed")); // manually start AP as below } break; case READY: // go back to AP mode after a disconnection (simulation 2/2), you could retry if (ev == MG_TCPIP_EV_ST_CHG && *(uint8_t *) ev_data == MG_TCPIP_STATE_DOWN) { struct mg_wifi_data *wifi = &((struct mg_tcpip_driver_cyw_data *) ifp->driver_data)->wifi; bool res = mg_wifi_ap_start(wifi); MG_INFO(("Disconnected")); MG_INFO(("Manually starting AP: %s", res ? "OK":"FAIL")); if (res) { state = AP; wifi->apmode = true; } } break; } } static struct mg_tcpip_driver_cyw_data d = { {WIFI_SSID, WIFI_PASS, "mongoose", "mongoose", 0, 0, 0, 0, 10, true}, (struct mg_tcpip_spi *)&spi, (struct mg_tcpip_driver_cyw_firmware *)&fw, false}; static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { if (ev == MG_EV_HTTP_MSG) { // New HTTP request received struct mg_http_message *hm = (struct mg_http_message *) ev_data; uint64_t tick = to_ms_since_boot(get_absolute_time()); if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { mg_http_reply(c, 200, "", "{%m:%llu}\n", MG_ESC("tick"), tick); } else { mg_http_reply(c, 200, "", "Hi from Mongoose, tick %llu\n", tick); } } } static void driver_init(struct mg_mgr *mgr) { d.wifi.apip = MG_IPV4(192, 168, 169, 1), d.wifi.apmask = MG_IPV4(255, 255, 255, 0), state = d.wifi.apmode ? AP : CONNECTING; // Initialise Mongoose network stack // Either set use_dhcp or enter a static config. // For static configuration, specify IP/mask/GW in network byte order struct mg_tcpip_if mif = { .ip = 0, .driver = (struct mg_tcpip_driver *)&mg_tcpip_driver_cyw, .driver_data = (struct mg_tcpip_driver_cyw_data*)&d, .fn = mif_fn, // .recv_queue.size = 8192 }; mg_tcpip_init(mgr, &mif); } // In an RTOS environment, give this task 8 KB of stack space. static void run_mongoose(void) { struct mg_mgr mgr; mg_mgr_init(&mgr); driver_init(&mgr); mg_log_set(MG_LL_DEBUG); // Set log level MG_INFO(("Hardware initialised, starting firmware...")); mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL); for (;;) { mg_mgr_poll(&mgr, 1); } } int main(void) { // initialize stdio stdio_init_all(); hwspecific_spi_init(); run_mongoose(); return 0; }