mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-14 10:20:01 +00:00
187 lines
6.0 KiB
C
187 lines
6.0 KiB
C
#if MG_ENABLE_TCPIP && MG_ARCH == MG_ARCH_PICOSDK && \
|
|
defined(MG_ENABLE_DRIVER_PICO_W) && MG_ENABLE_DRIVER_PICO_W
|
|
|
|
#include "drivers/pico-w.h"
|
|
#include "net_builtin.h"
|
|
#include "pico/stdlib.h"
|
|
|
|
static struct mg_tcpip_if *s_ifp;
|
|
static uint32_t s_ip, s_mask;
|
|
static bool s_aplink = false, s_scanning = false;
|
|
static bool s_stalink = false, s_connecting = false;
|
|
|
|
static void wifi_cb(struct mg_tcpip_if *ifp, int ev, void *ev_data) {
|
|
struct mg_wifi_data *wifi =
|
|
&((struct mg_tcpip_driver_pico_w_data *) ifp->driver_data)->wifi;
|
|
if (wifi->apmode && ev == MG_TCPIP_EV_STATE_CHANGE &&
|
|
*(uint8_t *) ev_data == MG_TCPIP_STATE_UP) {
|
|
MG_DEBUG(("Access Point started"));
|
|
s_ip = ifp->ip, ifp->ip = wifi->apip;
|
|
s_mask = ifp->mask, ifp->mask = wifi->apmask;
|
|
ifp->enable_dhcp_client = false;
|
|
ifp->enable_dhcp_server = true;
|
|
}
|
|
}
|
|
|
|
static bool mg_tcpip_driver_pico_w_init(struct mg_tcpip_if *ifp) {
|
|
struct mg_tcpip_driver_pico_w_data *d =
|
|
(struct mg_tcpip_driver_pico_w_data *) ifp->driver_data;
|
|
struct mg_wifi_data *wifi = &d->wifi;
|
|
s_ifp = ifp;
|
|
s_ip = ifp->ip;
|
|
s_mask = ifp->mask;
|
|
ifp->pfn = wifi_cb;
|
|
if (cyw43_arch_init() != 0)
|
|
return false; // initialize async_context and WiFi chip
|
|
if (wifi->apmode && wifi->apssid != NULL) {
|
|
if (!mg_wifi_ap_start(wifi)) return false;
|
|
cyw43_wifi_get_mac(&cyw43_state, CYW43_ITF_STA, ifp->mac); // same MAC
|
|
} else {
|
|
cyw43_arch_enable_sta_mode();
|
|
cyw43_wifi_get_mac(&cyw43_state, CYW43_ITF_STA, ifp->mac);
|
|
if (wifi->ssid != NULL) {
|
|
return mg_wifi_connect(wifi);
|
|
} else {
|
|
cyw43_arch_disable_sta_mode();
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static size_t mg_tcpip_driver_pico_w_tx(const void *buf, size_t len,
|
|
struct mg_tcpip_if *ifp) {
|
|
struct mg_tcpip_driver_pico_w_data *d =
|
|
(struct mg_tcpip_driver_pico_w_data *) ifp->driver_data;
|
|
return cyw43_send_ethernet(&cyw43_state,
|
|
d->wifi.apmode ? CYW43_ITF_AP : CYW43_ITF_STA, len,
|
|
buf, false) == 0
|
|
? len
|
|
: 0;
|
|
}
|
|
|
|
static bool mg_tcpip_driver_pico_w_poll(struct mg_tcpip_if *ifp, bool s1) {
|
|
cyw43_arch_poll(); // not necessary, except when IRQs are disabled (OTA)
|
|
if (s_scanning && !cyw43_wifi_scan_active(&cyw43_state)) {
|
|
MG_VERBOSE(("scan complete"));
|
|
s_scanning = 0;
|
|
mg_tcpip_call(ifp, MG_TCPIP_EV_WIFI_SCAN_END, NULL);
|
|
}
|
|
if (ifp->update_mac_hash_table) {
|
|
// first call to _poll() is after _init(), so this is safe
|
|
cyw43_wifi_update_multicast_filter(&cyw43_state, (uint8_t *) mcast_addr,
|
|
true);
|
|
ifp->update_mac_hash_table = false;
|
|
}
|
|
if (!s1) return false;
|
|
struct mg_tcpip_driver_pico_w_data *d =
|
|
(struct mg_tcpip_driver_pico_w_data *) ifp->driver_data;
|
|
if (d->wifi.apmode) return s_aplink;
|
|
int sdkstate = cyw43_wifi_link_status(&cyw43_state, CYW43_ITF_STA);
|
|
MG_VERBOSE(("conn: %c state: %d", s_connecting ? '1' : '0', sdkstate));
|
|
if (sdkstate < 0 && s_connecting) {
|
|
mg_tcpip_call(ifp, MG_TCPIP_EV_WIFI_CONNECT_ERR, &sdkstate);
|
|
s_connecting = false;
|
|
}
|
|
return s_stalink;
|
|
}
|
|
|
|
struct mg_tcpip_driver mg_tcpip_driver_pico_w = {
|
|
mg_tcpip_driver_pico_w_init,
|
|
mg_tcpip_driver_pico_w_tx,
|
|
NULL,
|
|
mg_tcpip_driver_pico_w_poll,
|
|
};
|
|
|
|
// Called once per outstanding frame by async_context
|
|
void cyw43_cb_process_ethernet(void *cb_data, int itf, size_t len,
|
|
const uint8_t *buf) {
|
|
mg_tcpip_qwrite((void *) buf, len, s_ifp);
|
|
(void) cb_data;
|
|
}
|
|
|
|
// Called by async_context
|
|
void cyw43_cb_tcpip_set_link_up(cyw43_t *self, int itf) {
|
|
if (itf == CYW43_ITF_AP) {
|
|
s_aplink = true;
|
|
} else {
|
|
s_stalink = true;
|
|
s_connecting = false;
|
|
}
|
|
}
|
|
void cyw43_cb_tcpip_set_link_down(cyw43_t *self, int itf) {
|
|
if (itf == CYW43_ITF_AP) {
|
|
s_aplink = false;
|
|
} else {
|
|
s_stalink = false;
|
|
// SDK calls this before we check status, don't clear s_connecting here
|
|
}
|
|
}
|
|
|
|
// there's life beyond lwIP
|
|
void pbuf_copy_partial(void) {
|
|
(void) 0;
|
|
}
|
|
|
|
static int result_cb(void *arg, const cyw43_ev_scan_result_t *data) {
|
|
struct mg_wifi_scan_bss_data bss;
|
|
bss.SSID = mg_str_n(data->ssid, data->ssid_len);
|
|
bss.BSSID = (char *) data->bssid;
|
|
bss.RSSI = (int8_t) data->rssi;
|
|
bss.has_n = 0; // SDK ignores this
|
|
bss.channel = (uint8_t) data->channel;
|
|
bss.band = MG_WIFI_BAND_2G;
|
|
// SDK-internal dependency, 2.1.0
|
|
bss.security = data->auth_mode & MG_BIT(0) ? MG_WIFI_SECURITY_WEP
|
|
: MG_WIFI_SECURITY_OPEN;
|
|
if (data->auth_mode & MG_BIT(1)) bss.security |= MG_WIFI_SECURITY_WPA;
|
|
if (data->auth_mode & MG_BIT(2)) bss.security |= MG_WIFI_SECURITY_WPA2;
|
|
MG_VERBOSE(("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));
|
|
mg_tcpip_call(s_ifp, MG_TCPIP_EV_WIFI_SCAN_RESULT, &bss);
|
|
return 0;
|
|
}
|
|
|
|
bool mg_wifi_scan(void) {
|
|
cyw43_wifi_scan_options_t opts;
|
|
memset(&opts, 0, sizeof(opts));
|
|
bool res = (cyw43_wifi_scan(&cyw43_state, &opts, NULL, result_cb) == 0);
|
|
if (res) s_scanning = true;
|
|
return res;
|
|
}
|
|
|
|
bool mg_wifi_connect(struct mg_wifi_data *wifi) {
|
|
s_ifp->ip = s_ip;
|
|
s_ifp->mask = s_mask;
|
|
if (s_ifp->ip == 0) s_ifp->enable_dhcp_client = true;
|
|
s_ifp->enable_dhcp_server = false;
|
|
cyw43_arch_enable_sta_mode();
|
|
MG_DEBUG(("Connecting to '%s'", wifi->ssid));
|
|
int res = cyw43_arch_wifi_connect_async(wifi->ssid, wifi->pass,
|
|
CYW43_AUTH_WPA2_AES_PSK);
|
|
MG_VERBOSE(("res: %d", res));
|
|
if (res == 0) s_connecting = true;
|
|
return (res == 0);
|
|
}
|
|
|
|
bool mg_wifi_disconnect(void) {
|
|
cyw43_arch_disable_sta_mode();
|
|
s_connecting = false;
|
|
return true;
|
|
}
|
|
|
|
bool mg_wifi_ap_start(struct mg_wifi_data *wifi) {
|
|
MG_DEBUG(("Starting AP '%s' (%u)", wifi->apssid, wifi->apchannel));
|
|
cyw43_wifi_ap_set_channel(&cyw43_state, wifi->apchannel);
|
|
cyw43_arch_enable_ap_mode(wifi->apssid, wifi->appass,
|
|
CYW43_AUTH_WPA2_AES_PSK);
|
|
return true;
|
|
}
|
|
|
|
bool mg_wifi_ap_stop(void) {
|
|
cyw43_arch_disable_ap_mode();
|
|
return true;
|
|
}
|
|
|
|
#endif
|