Pico W má na sobě wifi kartu, ale nemá operační systém. Přesněji, nemá síťové vlastnosti operačního systému jako Linux. Musíme proto při programování spoléhat na knihovny a doufat, že budeme mí stejné výsledky jako na Linuxu.

V Pico SDK máme k dispozici ovladač pro wifi kartu cyw43_driver, dále pico_cyw43_arch, pico_lwip a pico_mbedtls. Toto jsou nízkoúrovňové knihovny a je docela těžké s nimi pracovat i pokud jste síťový programátor seznámený s síťovým API, třeba sockety. Tato část by vám měla pomoci zaplnit mezery v dokumentaci a ukázat některé příklady. Cílem není jenom vytvořit třeba síťového TCP klienta, ale i rozumnět tomu, jak to všechno funguje.

Rozpracovaný dokument

Toto je rozpracovaný překlad z angličtiny, dokud to nebude hotové, můžete používat originální anglický text Master the Raspberry Pi Pico in C: Wifi with iwIP & mbedtls. Až budu mít překlad hotov, tento odstavec zmizí.

Architektura WiFi

Pico W má k dispozici dvě knihovny, pomocí nichž můžeme wifi používat, aniž bychom příliš zabředávali na základní úroveň programování hardwaru. Tyto knihovny můžeme považovat za základ, který má tři úrovně.

Na nejnižší úrovni je cyw43_driver, což je ovladač hardwaru a poskytuje SPI rozhraní, kterým je Pico spojeno s CYW43439 obvodem. V mnoha případech nemusíme funkce toho ovladače používat, protože si vystačíme s vyšší úrovní, kterou nám poskytuje pico_cyw43_arch.

pico_cyw43_arch je knihovna vyšší úrovně, jejíž funkce se týkají převážně nastavení parametrů rádia a navázání spojení. Je dobře dokumentována a odtud začneme.

pico_lwip další knihovna vyšší úrovně, je to množství funkcí, které nám umožňují pracovat s lwIP (A Lightweight TCP/IP stack), svobodnou implementací TCP/IP protokolu pro malá zařízení. Není mnoho dokumentace o této knihovně, ale naštěstí je lwIP popsán v dokuemtaci docela dobře. pico_lwip poskytuje řadu funkcí pro práci s vyššími protokoly postavenými nad IP (Internet Protocol), jako je TCP (Transmission Control Protokol), UDP (User Datagram Protocol), DNS (Domain Name System) atd. Jakmile bude Pico W radiově připojeno, tak budeme používat převážně funkce z knihovny pico_lwip.

Ovladač CYW43439

Pico W používá obvod Infineon CYW43439, což je dvojice ARM procesorů, která je připojena k Picu pomocí jednoduché třívodičové SPI sběrnice. Obvod umí Wifi 4 (802.11n) v pásmu 2.4 GHz a také Bluetooth.

Obvod Infineon CYW43439 — blokové schéma

Infineon CYW43439

Jak to vypadá je ukázáno v oficiální dokumentaci Pico W Datasheet na straně 23:

Pico W — zapojení CYW43439

picow cyw43439

Obvod CYW43439 má 4bitovou sběrnici Secure Digital Input Output (SDIO), která pochází z SD karet. SDIO sběrnice je rozšíření SPI protokolu, které používá přídavné datové linky. U SD karet se obvykle používá Quad nebo 4bit režim, někdy se nazývá QSPI (Quad SPI), existují však i 2bitové a 1bitové režimy a dvoulinkový SPI režim. To nejsou opravdové SPI sběrnice, protože datové linky jsou obousměrné. Obvod CYW43439 používá SPI sběrnici, ale režim sběrnice použitý v Picu je SD 1bitový, který používá jednu obousměrnou datovou linku.

Ovladač, který najdete v adresáři pico-sdk/lib/cyw43-driver má dva binární soubory (bloby), které obsahují program, nahrávaný do obvodu CYW43439. Dále zde najdete Céčkový kód pro čtení a zápis dat na SPI sběrnici a do některých registrů.

Ovladač nepoužívá příslušné piny SPI sběrnice v režimu GPIO, ale používá je jako programovatelné vstupně výstupní PIO piny. To znamená, že byste neměli používat stejné piny pro GPIO (to ani nejde) a stejný PIO, jako používá wifi ovladač. Jaký PIO je použit se nastavuje v:

#define CYW43_SPI_PIO_PREFERRED_PIO 1

Implicitně se používá PIO 1, můžeme to přenastavit, ale je lepší používat ve svém programu raději PIO 0. Ovladač používá jeden stavový automat a 10 bajtů instrukční paměti. Potřebujete-li používat PIO 1 v volné instrukční paměti, můžete zjistil volný stavový automat pomocí pio_claim_unused_sm.

Modul cyw43_ll — dokumentace

Ovladač používá nízkoúrovňový modul cyw43_ll, který pracuje přímo s hardwarem. Pokud se chcete dozvědět více, podívejte se do zdrojového kódu v souborech:

pico-sdk/lib/cyw43-driver/src/cyw43_ll.h
pico-sdk/lib/cyw43-driver/src/cyw43_ll.c

Mnoho funkcí je dokumentováno, ale je poměrně obtížné je používat, dokud nemáte kompletní přehled o tom jak pracuje Wifi na Picu kvůli tomu, že je složité najít význam jednotlivých konfiguračních parametrů.

Ovladač má množství funkcí, které můžete používat, ale používají je převážně vyšší vrstvy. Hlavní důvod dokumentace je v tom, abyste mohli debugovat nízkoúrovňové problémy.

Mnoho z nich používá stav self jako ukazatel na strukturu cyw43_t. Když dovolíte provést inicializaci přímo driveru, naleznete globální proměnnou cyw43_state definovanou v:

pico-sdk/lib/cyw43-driver/src/cyw43_ctrl.c

To znamená, že můžete použít cyw43_state kdykoliv, když uvidíte v definici funkce self. Podobně můžete použít CYW43_ITF_STA nebo CYW43_ITF_AP kdykoliv uvidíte parametr itf v nastavení režimu klienta nebo AP.

cyw43.h struktura cyw43_t
typedef struct _cyw43_t {
    cyw43_ll_t cyw43_ll;

    uint8_t itf_state;
    uint32_t trace_flags;

    // State for async events
    volatile uint32_t wifi_scan_state;
    uint32_t wifi_join_state;
    void *wifi_scan_env;
    int (*wifi_scan_cb)(void *, const cyw43_ev_scan_result_t *);

    bool initted;
    // Pending things to do
    bool pend_disassoc;
    bool pend_rejoin;
    bool pend_rejoin_wpa;

    // AP settings
    uint32_t ap_auth;
    uint8_t ap_channel;
    uint8_t ap_ssid_len;
    uint8_t ap_key_len;
    uint8_t ap_ssid[32];
    uint8_t ap_key[64];

    #if CYW43_LWIP
    // lwIP data
    struct netif netif[2];
    #if LWIP_IPV4 && LWIP_DHCP
    struct dhcp dhcp_client;
    #endif
    #endif

    #if CYW43_NETUTILS
    dhcp_server_t dhcp_server;
    #endif

    // mac from otp (or from cyw43_hal_generate_laa_mac if not set)
    uint8_t mac[6];

    #if CYW43_ENABLE_BLUETOOTH
    bool bt_loaded;
    #endif
} cyw43_t;

Inicializace a navázání spojení

  • void cyw43_init( *self )
    inicializuje ovladač

  • void cyw43_deinit( *self )
    ukončí ovladač

  • void cyw43_wifi_set_up( *self, itf, up, country )
    nastaví a inicializuje WiFi, kde parametr up (bool) řídí režim, 1 nebo true znamená AP, 0 false STA.
    country je nastavení WiFi z hlediska země používání, pro nás platí CYW43_COUNTRY_CZECH_REPUBLIC.
    Seznam všech zemí je v piso-sdk/lib/cyw43-driver/src/cyw43_country.h.

  • int cyw43_wifi_join(*self, ssid_len, *ssid, key_len, *key, auth_type, *bssid, channel) připojí se do WiFi sítě v módu STA, kde ssid je Service Set IDentifier, za použítí klíče key a auth_type může být jeden z:

    • CYW43_AUTH_OPEN

    • CYW43_AUTH_WPA_TKIP_PSK

    • CYW43_AUTH_WPA2_AES_PSK

    • CYW43_AUTH_WPA2_MIXED_PSK
      bssid je buď NULL nebo MAC adresa AP a channel je pásmo pokud je bssid nastaveno.

  • int cyw43 wifi_leave(*self, itf)
    odpojí se z WiFi sítě

  • void cyw43_cb_tcpip_init(*self, itf)
    inicializuje IP protokol

  • void cyw43_cb_tcpip_deinit(*self, itf)
    ukončí IP protokol

  • void cyw43_cb_tcpip_set_link_up(*self, itf)
    upozorní IP protokol, že spojení je navázáno (link up)

  • void cyw43_cb_tcpip_set_link_down(*self, itf)
    upozorní IP protokol, že spojení je ztraceno (link down)

Zjišťování stavu

  • bool cyw43_is_initialized(*self)
    zjistí, zda byl ovladač cyw43 inicializován

  • int cyw43_wifi_link_status (*self, itf)
    vrací stav WiFi linky, což může být:

    • CYw43_LINK_DOWN  — WiFi spadla

    • CYW43_LINK_JOIN — připojeno k WiFi

    • CYW43_LINK_FAIL — připojování selhalo

    • CYW43_LINK_NONET — nenalezeno SSID (může být nedostupné anebo spadlo)

    • CYW43_LINK_BADAUTH — chyba autentizace

  • int cyw43_tcpip_link_status(*self, itf)
    vrací stav linky, což může být pět předchozích stavů a:

    • CYW43_LINK_NOIP — připojeno k WiFi bez IP adresy

    • CYW43_LINK_UP — připojeno k WiFi máme IP adresu

  • int cyw43_wifi_get_mac (*self, itf, mac[6])
    vrací MAC adresu zařízení v 6 bajtovém poli

  • cyw43_wifi_get_rssi(*self, uint32_t *rssi)
    vrací sílu signálu RSSI u navázaného spojení

Ovládání napájení (power management)

  • int cyw43_wifi_pm(*self, pm)
    nastavuje šetření energií podle parametru pm (int), hodnota pm je počítána pomocnou funkcí.

  • uint32_t cyw43_pm_value(pm_mode, pm2_sleep_ret_ms, li_beacon_period, li_dtim_period, li_assoc)
    kde pm_mode jedna z:

    • CYW43_NO_POWERSAVE_MODE bez šetření energie

    • CYW43_PM1_POWERSAVE_MODE velké šetření energie, které omezuje propustnost WiFi

    • CYW43_PM2_POWERSAVE_MODE šetření energie bez ztráty propustnosti (preferované), šetří energi jenom pokud je WiFi nějaký čas neaktivní
      pm2_sleep_ret_ms maximum time to wait before going back to sleep for CYw43_PM2_POWERSAVE MODE mode measured in milliseconds and must be between 10 and 2000ms and divisible by 10
      li_beacon_period wake interval measured in beacon periods
      li_dtim_period wake interval measured in DTIMs; if set to 0, the wake interval is measured in beacon periods
      li_assoc Wake interval sent to the access point

Tři předdefinované režimy šetření energie:

  • CYW43_DEFAULT_PM cyw43_pm_value(CYW43_PM2_POWERSAVE_MODE, 200, 1, 1, 10)
    implicitní režim

  • CYW43_AGGRESSIVE_PM cyw43_pm_value(CYW43_PM2_POWERSAVE_MODE, 2000, 1, 1, 10)
    silně šetřící režim za cenu nižší propustnosti Wifi

  • CYW43_PERFORMANCE_PM cyw43_pm_value(CYW43_PM2_POWERSAVE MODE, 20, 1, 1, 1)
    menší setření energií s větším příkonem, aby byla lepší propustnost Wifi

Skenování WiFi sítě

Ostatní

Ovladač a lwIP operační módy

Použití threadsafe_background

Funkce knihovny cyw43_arch

Připojení

Funkce Connect

lwIP NETIF

Funkce pro připojení

Skenování sítě

Získání kvality signálu

..

Zdroje a odkazy