
Firmware para Raspberry Pi Pico W que cria um adaptador Wi-Fi USB sem driver, com bridging transparente de camada 2, autenticação WPA2/WPA3 e console de gerenciamento fora de banda.
= pico-usb-wifi :toc: macro :toclevels: 3 :idprefix: :idseparator: -
pico-usb-wifi é um firmware para o Raspberry Pi Pico W que o transforma em um adaptador Wi-Fi USB sem driver, enumerando-se como um dispositivo USB CDC-NCM.
:figure-caption: IA Generativa
.Diagrama do pico-usb-wifi image::images/openrouter-banana2-rpi-pico.png[]
O firmware funciona como uma ponte transparente de camada 2 que encaminha quadros entre a interface sem fio do Pico W e sua interface USB. A interface USB do host adota o endereço MAC da estação Wi-Fi do Pico W, o que fornece uma identidade MAC e IP de ponta a ponta.
Nenhum driver, módulo de kernel ou pilha sem fio do lado do host é necessário; consulte <<no-host-side-wi-fi-stack,Nenhuma Pilha Wi-Fi do Lado do Host>>.
O host precisa apenas dos drivers cdc_ncm e cdc_acm que já vêm integrados em todo Linux, macOS, Windows e sistemas operacionais móveis modernos.
== Funcionalidades
O pico-usb-wifi oferece estas funcionalidades:
.Uma Situação do Mundo Real image::images/slop_2.png[]
== Por Que Isso Existe
Eu precisava de um adaptador Wi-Fi USB para usar em um projeto Linux embarcado futuro. Eu não tinha um dongle Wi-Fi USB barato, então, em vez de ir comprar um em uma loja física por cinco dólares, passei dois dias de um fim de semana prolongado de feriado e cerca de um milhão de tokens do Claude Code construindo este firmware.
白一百, Autor do pico-usb-wifi
O Google disse que não era viável:
.pico-usb-wifi "Não Viável" image::images/gemini_says_not_possible.png[]
toc::[]
== Nenhuma Pilha Wi-Fi do Lado do Host
Ao contrário de um dongle Wi-Fi USB, este adaptador expõe apenas uma interface semelhante a Ethernet para o host. O Pico W contém todo o lado sem fio: o rádio, a associação, o supplicant WPA2/WPA3 e o domínio regulatório.
Isso permite que os sistemas evitem instalar wpa_supplicant, a pilha sem fio cfg80211/mac80211, um banco de dados regulatório e firmware de chipset ou driver de fornecedor.
O provisionamento das credenciais Wi-Fi ocorre no dispositivo, por meio de seu console de gerenciamento fora da banda, não por qualquer ferramenta sem fio do lado do host.
Isso mantém um host restrito ou eletrodoméstico, ou um sem drivers sem fio, ou cujo kernel do fornecedor não os possui, com a capacidade de se conectar a redes sem fio usando apenas drivers de classe CDC universais.
== Como Funciona
[#fig-topology] .Diagrama de Topologia image::images/topology.svg[Topologia de ponte transparente de camada 2,820]
A interface USB do host recebe o endereço MAC da estação Wi-Fi do Pico W, de modo que existe um único MAC de ponta a ponta e o Pico W pode encaminhar quadros Ethernet literalmente entre USB e Wi-Fi. Uma estação Wi-Fi não pode fazer ponte com vários endereços MAC, portanto, colapsar o host e a estação em um único MAC é o que torna uma ponte transparente possível. A lógica completa, o caminho de dados e o tratamento de IPv6/multicast são descritos em <<architecture,Arquitetura>>.
== Requisitos do Host
O host requer os drivers internos cdc_ncm e cdc_acm.
Ambos fazem parte do Linux mainline há mais de uma década, portanto, qualquer kernel atualmente suportado os inclui.
Nenhum módulo fora da árvore, blob de firmware ou driver de fornecedor está envolvido.
Os mesmos drivers de classe existem no macOS, Windows 10 e posteriores, Android e iOS.
[NOTA] Nenhum outro sistema operacional foi testado.
== Compilando
O projeto é um projeto CMake padrão do pico-sdk. Requer o conjunto de ferramentas ARM embarcado, CMake, um backend de compilação (Ninja ou Make), Python 3 e uma cópia do pico-sdk com seus submódulos. O TinyUSB e o lwIP incluídos no pico-sdk são usados sem modificação.
=== Dependências
Em sistemas baseados em Arch (Arch, CachyOS, Manjaro), o conjunto de ferramentas vem dos repositórios oficiais:
arm-none-eabi-newlib fornece a biblioteca C embarcada e os cabeçalhos; sem ela, o cross-compilador não consegue encontrar stdint.h e cabeçalhos semelhantes.
libusb só é necessário para picotool, que o pico-sdk compila a partir do código-fonte durante a primeira configuração para gerar o UF2; nenhum pacote picotool separado é necessário.
=== Etapas de Compilação
git clone -b 2.2.0 --recurse-submodules https://github.com/raspberrypi/pico-sdk export PICO_SDK_PATH="$PWD/pico-sdk"
cp src/wifi_config.h.example src/wifi_config.h # depois edite SSID/senha, ou deixe em branco cmake -S . -B build -G Ninja -DPICO_BOARD=pico_w -DCMAKE_BUILD_TYPE=Release cmake --build build
O sinalizador -G Ninja é opcional; omita-o para usar o gerador Make padrão (então cmake --build build -j).
wifi_config.h contém as credenciais padrão de tempo de compilação e está no .gitignore.
Deixá-lo em branco produz uma imagem sem credenciais incorporadas, que é provisionada em tempo de execução através do console de gerenciamento (<<management-console,Console de Gerenciamento>>); preenchê-lo incorpora uma rede padrão.
== Gravando o Firmware
As etapas aqui carregam o firmware na placa.
. Segure o botão BOOTSEL enquanto conecta a placa via USB.
Ela é montada como um volume de armazenamento em massa USB RPI-RP2, geralmente em /run/media/<user>/RPI-RP2 ou /media/<user>/RPI-RP2.
. Copie pico-usb-wifi.uf2 para esse volume.
A placa reinicia no firmware automaticamente.
. Conecte a placa ao host que receberá a conectividade Wi-Fi.
== Usando em um Host Linux
Conecte o dispositivo ao host e provisione suas credenciais Wi-Fi uma vez através do console de gerenciamento (<<management-console,Console de Gerenciamento>>). A interface do host então se comporta como qualquer conexão com fio na rede do ponto de acesso.
Um host que gerencia interfaces automaticamente (NetworkManager, systemd-networkd, dhcpcd) não precisa de configuração: ele executa DHCP e SLAAC através da ponte e recebe um único endereço IPv4, um endereço IPv6, o gateway do ponto de acesso e DNS, exatamente como um cliente com fio faria.
Não há endereço ou gateway do lado do dispositivo para configurar, porque o Pico não possui nenhum.
O endereço MAC da interface é o MAC da estação Wi-Fi, que é como uma identidade é apresentada à rede.
A saída do comando ip aqui mostra a interface resultante: um cliente DHCP/SLAAC comum na própria sub-rede do ponto de acesso, com o MAC da estação e nenhum traço do Pico.
== Console de Gerenciamento
O console de gerenciamento é a interface de configuração, na primeira função serial CDC-ACM (geralmente /dev/ttyACM0).
Ele é acessível assim que o dispositivo é enumerado, antes da associação Wi-Fi, portanto, o provisionamento nunca requer uma rede.
Abra-o com um terminal serial como picocom ou screen; a taxa de transmissão é irrelevante para USB CDC.
O console ecoa a entrada e mostra um prompt, e cada comando imprime o estado completo do dispositivo.
A autenticação Wi-Fi é WPA2-PSK ou WPA3-SAE (AES).
A senha é a frase secreta da rede ou aberta quando a senha é deixada em branco.
Um perfil protegido por senha usa o modo de transição WPA2/WPA3, portanto, ele se conecta a qualquer tipo de ponto de acesso.
O console armazena até oito perfis de credenciais; um é o perfil ativo, e o dispositivo associa a ele.
set ssid/set pass editam o perfil ativo, list/use/del gerenciam o conjunto, e scan descobre redes próximas e se conecta a uma a partir de uma lista numerada — útil quando um SSID tem caracteres difíceis de digitar.
As palavras de comando não diferenciam maiúsculas de minúsculas; o console as mostra em minúsculas.
A sessão aqui provisiona uma rede escaneando por ela.
$ picocom /dev/ttyACM0
Uma alteração entra em vigor imediatamente, re-associando com o perfil ativo; uma reinicialização não é necessária.
Repita para salvar mais redes; list as mostra e use <n> alterna a ativa:
save persiste cada perfil na flash; restore descarta edições não salvas recarregando o registro salvo.
A tabela aqui lista o conjunto de comandos.
[#tbl-config-commands] .Comandos do Console de Gerenciamento [cols="2,3", options="header"] |=== |Comando |Efeito
|set ssid <text>
|Define o SSID do perfil ativo (um valor pode conter espaços) e re-associa; cria o primeiro perfil se nenhum existir.
|set pass <text>
|Define a frase secreta WPA2/WPA3 do perfil ativo (em branco para uma rede aberta) e re-associa.
|set country <CC\|WORLDWIDE>
|Define o país regulatório (totalmente aplicado na próxima inicialização).
|set debug <on\|off>
|Transmite diagnósticos no console de depuração; consulte <<debug-console,Console de Depuração>>.
|list
|Lista os perfis salvos, marcando o ativo.
|use <n>
|Torna o perfil n ativo e re-associa.
|del <n>
|Exclui o perfil n.
|scan
|Escaneia redes próximas e entra no submenu de escaneamento (back, join <n>, scan para repetir, ou live para um fluxo contínuo desassociado). join prepara a rede escolhida como o perfil ativo, pronto para set pass.
|save
|Persiste todos os perfis e configurações na flash.
|restore
|Descarta alterações não salvas recarregando as configurações salvas.
|===
O endereço atribuído ao host é mostrado no dump de estado como host IPv4 e host IPv6, espionado passivamente a partir do tráfego em ponte, já que o Pico não possui nenhum endereço para relatar.
O setor de configuração reside no final da flash, separado da imagem do programa no início, portanto, uma regravação comum de pico-usb-wifi.uf2 deixa os perfis salvos intactos (um apagamento de chip completo os limpa).
A exceção é a atualização para v1.1.0: o layout do registro mudou para conter vários perfis, portanto, um registro anterior a 1.1.0 é descartado e as redes devem ser reinseridas uma vez (veja o changelog).
== Console de Depuração
O console de depuração é um fluxo de diagnóstico somente gravação na segunda função serial CDC-ACM (geralmente /dev/ttyACM1).
Ele fica silencioso até que set debug on seja emitido no console de gerenciamento, portanto, não tem custo quando desligado e nunca interfere no gerenciamento.
Quando ativado, ele relata mudanças de associação e uma linha periódica de estatísticas da ponte, como na sessão aqui.
Uma compilação -DTRACE_FRAMES=1 adiciona um resumo de uma linha de cada quadro em ponte, mas inunda o console sob carga, portanto, está desligado por padrão.
Os campos de estatísticas são descritos na tabela aqui.
[#tbl-debug-stats] .Campos de Estatísticas de Depuração [cols="1,3", options="header"] |=== |Campo |Significado
|->wifi
|Quadros encaminhados do host para Wi-Fi.
|->host
|Quadros encaminhados de Wi-Fi para o host.
|txdrop
|Quadros host-para-Wi-Fi descartados porque a estação ainda não estava associada (o host retenta).
|rxdrop
|Quadros Wi-Fi-para-host descartados porque o lado USB não conseguiu drenar rápido o suficiente.
|refl
|Quadros Wi-Fi-para-host descartados por serem a própria transmissão do host, refletida pelo ponto de acesso.
|poolfail
|Quadros host-para-Wi-Fi descartados porque o pool de pbufs do lwIP estava momentaneamente esgotado.
|ringpk
|Profundidade de pico da fila USB-TX Wi-Fi-para-host (de 32) desde a linha de estatísticas anterior, então reiniciada — um medidor ao vivo, onde um valor próximo a 32 significa que USB não consegue drenar tão rápido quanto Wi-Fi entrega. (Ao contrário de um máximo histórico, cai novamente quando uma rajada passa.)
|link
|Status do link Wi-Fi da estação: up (associado), join/down (associando), ou um motivo de falha — badauth (frase secreta errada), nonet (SSID não encontrado), fail.
|hangs
|Vezes que o watchdog recuperou o firmware de um travamento desde a última inicialização a frio; consulte <<automatic-recovery,Recuperação Automática>>.
|faults
|Falhas graves que o firmware recuperou desde a última inicialização a frio.
|faultpc
|Endereço da falha grave mais recente (0x00000000 se nenhuma), para mapear com addr2line.
|freeram
|RAM livre em bytes, para medir a margem ao ajustar tamanhos de buffer.
|===
O rastreamento por quadro compartilha o link USB Full-Speed com o tráfego em ponte, portanto, reduz a taxa de transferência e inunda o console; é uma opção de tempo de compilação (-DTRACE_FRAMES=1) destinada apenas para depuração profunda.
== Recuperação Automática
Um watchdog de hardware reinicia o dispositivo se o firmware nunca mais atender seu loop principal — um travamento ou deadlock de driver —, então ele se reenumera por conta própria em alguns segundos em vez de precisar ser desconectado. Um manipulador de falhas grave separado captura uma falha de CPU imediatamente e registra o endereço da falha.
Os contadores da ponte de momentos antes da falha sobrevivem à reinicialização na RAM não inicializada.
Na recuperação, o dispositivo imprime um relatório de uma linha RECOVERED from ... no console de depuração com esses contadores (e o endereço da falha para uma falha grave), e a linha stats: em execução carrega as contagens de hangs, faults e faultpc, portanto, uma falha deixa um rastro de diagnóstico mesmo que tenha se auto-limpado.
== Estados do LED Integrado
A tabela aqui lista os padrões do LED integrado e seus significados.
[#tbl-led] .Padrões do LED Integrado [cols="1,3", options="header"] |=== |Padrão |Significado
|Sólido |Associado a um ponto de acesso — o estado normal de execução.
|Piscar lento — 1 Hz |Wi-Fi configurado, associando ou ainda não associado.
|Piscar rápido — 5 Hz |Nenhum Wi-Fi configurado; provisione-o através do console de gerenciamento.
|Flash duplo — dois pulsos rápidos, depois uma pausa |Escaneamento contínuo (ao vivo) em execução; o dispositivo está desassociado e transmitindo pontos de acesso próximos para o console de gerenciamento até que uma tecla seja pressionada.
|Desligado |USB não pronto. |===
== Trabalho Futuro
A ponte opera sobre o USB Full-Speed nativo do RP2040 (12 Mbit/s), portanto, a taxa de transferência máxima gira em torno de 4-5 Mbit/s de carga útil TCP — amplo para um painel ou superfície de controle, mas um teto rígido. O gargalo é o link USB, não o rádio Wi-Fi. Algumas direções que poderiam aumentá-lo, em ordem aproximada de esforço:
Nenhum destes é necessário para o uso pretendido do firmware; são pontos de partida para quem quiser mais taxa de transferência.
== Bibliotecas Upstream e Créditos
Este firmware é montado a partir de vários projetos upstream, registrados na tabela aqui.
[#tbl-upstream] .Componentes Upstream [cols="1,2,1,4", options="header"] |=== |Componente (arquivos na árvore) |Upstream |Licença |Função
|USBNet |https://github.com/mattmyne/usbnet[mattmyne/usbnet] |MIT a|Módulo base de rede USB, descritores USB e o esqueleto principal, estendido aqui para a ponte Wi-Fi.
usb_network.c, usb_network.h - reescritos como a ponte L2usb_descriptors.c - modificado para incluir CDC-NCM composto + CDC-ACM duplotusb_config.h - modificado|TinyUSB |https://github.com/hathach/tinyusb[hathach/tinyusb] |MIT a|Pilha de dispositivo USB CDC-NCM e CDC-ACM, usada como incluída no pico-sdk. +
|pico-sdk 2.2.0 |https://github.com/raspberrypi/pico-sdk[raspberrypi/pico-sdk] |BSD-3-Clause a|Suporte à placa, sistema de compilação e o TinyUSB, lwIP e cyw43-driver incluídos.
pico_sdk_import.cmake - cópia exatalwipopts.h - exemplo pico_w reduzido|Exemplo net_lwip_webserver do TinyUSB
|Peter Lawrence e Ha Thach, via https://github.com/hathach/tinyusb[hathach/tinyusb]
|MIT
a|Base original da cola de rede USB; reduzida ao caminho CDC-NCM. +
|lrndis |https://github.com/fetisov/lrndis[fetisov/lrndis] |MIT a|Influência de design na abordagem de rede USB +
Os códigos-fonte restantes são originais deste projeto:
main.cconfig.cconfig.hconfig_proto.cconfig_proto.hserial_console.cserial_console.hwifi_scan.cwifi_scan.hdebug_console.cdebug_console.h== Licença
Este projeto é licenciado sob MIT; consulte link:LICENSE[LICENSE]. Os componentes upstream mantêm suas próprias licenças, conforme registrado em <<upstream-libraries-and-credits,Bibliotecas Upstream e Créditos>>.
== Arquitetura
=== Visão Geral
O dispositivo é um periférico USB CDC-NCM que faz ponte entre um host e Wi-Fi.
O Pico W executa a estação Wi-Fi e transporta quadros Ethernet entre o link USB e o rádio.
O host executa sua própria pilha IP e detém a única identidade de rede; o Pico não possui IP próprio.
O host não precisa de nada além dos drivers cdc_ncm e cdc_acm já integrados.
=== Por Que Uma Ponte de Camada 2 Via Adoção de MAC
O objetivo é que o host apareça na rede Wi-Fi como um dispositivo comum com um endereço, enquanto o Pico permanece invisível. Uma restrição de camada física difícil molda como isso é alcançado.
Uma estação Wi-Fi não pode fazer ponte transparente com vários endereços MAC. Quando o Infineon CYW43 associa a um ponto de acesso no modo estação, a associação concede exatamente um endereço MAC, e os quadros de dados 802.11 que ele envia estão vinculados a esse MAC da estação. Sem quadros de quatro endereços (WDS), que o ponto de acesso também deve suportar e permitir, o rádio não pode transportar quadros em nome de outros endereços MAC atrás dele. Esta é a limitação bem conhecida de que um cliente Wi-Fi não pode ser colocado em ponte.Este firmware não luta contra essa restrição; ele a remove. A interface USB do hospedeiro é instruída a adotar o endereço MAC da estação Wi-Fi, de modo que há exatamente um MAC de ponta a ponta. Com o hospedeiro e a estação compartilhando uma identidade, o Pico é uma ponte burra de camada 2: ele encaminha quadros Ethernet literalmente entre USB e Wi-Fi, sem tocar em nada acima da camada 2. O ponto de acesso vê uma única estação comum; o hospedeiro executa DHCP, SLAAC e Neighbor Discovery por si só e detém os endereços resultantes.
As consequências estão listadas na tabela aqui.
[#tbl-bridge-effects] .Propriedades Da Ponte De Adoção De MAC [cols="1,3", options="header"] |=== |Propriedade |Por que é válida
|Um IP, mantido pelo hospedeiro |O Pico não atribui a si mesmo nenhum endereço, portanto há uma identidade única, na própria sub-rede do ponto de acesso — não uma sub-rede tether privada.
|IPv4 e IPv6 igualmente |O encaminhamento é na camada 2, portanto SLAAC, DHCPv6, anúncios de roteador e Neighbor Discovery passam inalterados, sem código específico de versão.
|Sem NAT e sem redirecionamentos de porta |Nada é reescrito, portanto conexões de entrada alcançam o hospedeiro diretamente; não há nada a mascarar ou mapear.
|Sem pilha Wi-Fi no hospedeiro
|O Pico é dono da associação e do supplicant, portanto o hospedeiro não precisa de wpa_supplicant, banco de dados regulatório ou driver sem fio — apenas os drivers de classe CDC.
|===
=== Caminho De Dados
No lado USB, o TinyUSB fornece o dispositivo CDC-NCM, e o MAC da interface do hospedeiro é definido como o MAC da estação na inicialização (usb_network_set_host_mac, antes da enumeração).
Hospedeiro para Wi-Fi: um quadro chega via tud_network_recv_cb, é armazenado e, no loop principal, é transmitido pelo rádio com cyw43_send_ethernet.
Wi-Fi para hospedeiro: o manipulador input da netif da estação é substituído, portanto todo quadro que o driver cyw43 recebe é entregue à ponte em vez do lwIP, enfileirado e transmitido ao hospedeiro com tud_network_xmit.
Nenhuma interface IP lwIP existe no lado USB, e a netif da estação não carrega IP; o lwIP serve apenas o estado de link da netif cyw43 e o pool pbuf.
=== Modelo De Concorrência
O firmware usa pico_cyw43_arch_lwip_threadsafe_background.
O Wi-Fi é atendido em um IRQ de fundo e contexto assíncrono, de modo que nunca priva o USB, cujo tud_task() é executado no loop principal.
Esse arranjo tem uma consequência estrita para a ponte.
O TinyUSB deve ser tocado apenas a partir do loop principal, mas os quadros Wi-Fi são recebidos no contexto de fundo.
O manipulador de recepção Wi-Fi, portanto, apenas enfileira cada quadro em um buffer circular, e o loop principal drena esse buffer para tud_network_xmit.
Violar essa regra manifestou-se no lado do hospedeiro como NETDEV WATCHDOG: transmit queue timed out, com o USB caindo.
O envio de quadros do hospedeiro para o Wi-Fi ocorre no loop principal e mantém cyw43_arch_lwip_begin()/cyw43_arch_lwip_end() em torno da chamada cyw43.
=== Multicast E IPv6
Uma estação, por padrão, recebe apenas os grupos multicast aos quais se juntou. A ponte não executa pilha IP própria e não se junta a nada; portanto, sem intervenção, o rádio descartaria o multicast do qual o IPv6 depende, e o IPv6 do hospedeiro não funcionaria através da ponte. Anúncios de roteador, detecção de endereço duplicado e resolução de endereço dependem de multicast.
Em cada associação, o firmware define o iovar allmulti do CYW43, para que a estação entregue todos os quadros multicast independentemente do filtro.
Isso é feito com o cyw43_ioctl público contra WLC_SET_VAR, não entrando no modo monitor; portanto, o formato do quadro Ethernet permanece inalterado.
Uma rede por trás de um switch com snooping IGMP ou MLD ainda pode podar algum multicast que o hospedeiro nunca solicitou; um ponto de acesso doméstico plano o inunda.
=== Filtro De Auto-Reflexão
Como o hospedeiro compartilha o MAC da estação, um multicast ou broadcast que o hospedeiro envia é inundado pelo ponto de acesso de volta para a estação, que agora recebe todo o multicast, e seria entregue de volta ao hospedeiro como seu próprio quadro.
O manipulador de recepção descarta qualquer quadro Wi-Fi-para-hospedeiro cujo MAC de origem seja o MAC da estação, pois esse quadro só pode ser a própria transmissão do hospedeiro refletida pelo ponto de acesso.
Uma ponte não deve ecoar os quadros de uma estação de volta para ela; o descarte é contado como refl nas estatísticas de depuração.
=== Os Dois Consoles Seriais
Gerenciamento e diagnósticos são fora da banda, em duas funções CDC-ACM do mesmo dispositivo USB composto, em vez de na rede. Isso é uma consequência deliberada da transparência: o lado da rede carrega apenas o tráfego do hospedeiro e não tem endereço para o Pico responder.
O console de gerenciamento (/dev/ttyACM0) executa o protocolo de linha de configuração e é acessível no instante em que o USB enumera, antes de o Wi-Fi estar ativo, portanto o dispositivo é sempre provisionável sem nenhum IP.
O console de depuração (/dev/ttyACM1) é um fluxo de diagnósticos somente gravação — eventos de associação, contadores periódicos da ponte e resumos opcionais de pacotes por quadro — emitido apenas quando ativado, portanto não custa nada quando desligado e nunca polui o console de gerenciamento.
Nenhum console toca na rede, portanto nenhum gera tráfego que um firewall do hospedeiro registre.
=== Armazenamento De Configuração
As configurações de tempo de execução — até oito perfis de credenciais Wi-Fi, o índice do perfil ativo, o país regulatório e o sinalizador de depuração — residem em um único registro no último setor da flash, longe da imagem do programa no início da flash.
O registro abrange várias páginas da flash, portanto um save programa todo o setor de uma vez (a apagamento é em todo o setor independentemente).
Na inicialização, o registro é aceito apenas com uma correspondência exata de seu número mágico e um CRC-32 sobre o resto da struct; qualquer incompatibilidade carrega as predefinições de tempo de compilação.
Não há migração versionada: uma alteração no layout do registro simplesmente falha na verificação mágica/CRC e recai sobre as predefinições, o que é aceitável porque uma predefinição de tempo de compilação ainda sementeia o primeiro perfil. (É por isso que atualizar para v1.1.0, que ampliou o registro para uma lista de perfis, descarta um registro anterior à v1.1.0.)
Um save grava o registro de volta através de flash_safe_execute, que coordena a apagamento e programação contra o outro núcleo e desabilita interrupções pelos poucos milissegundos que leva.
Essa gravação é executada a partir do manipulador do console enquanto o bloqueio lwIP está mantido; a breve janela de interrupções desabilitadas pausa o atendimento Wi-Fi de fundo, o que é aceitável para um salvamento infrequente iniciado pelo hospedeiro.
=== Peculiaridades De Hardware E Toolchain
Esses comportamentos do RP2040, do Infineon CYW43 e do pico-sdk custaram tempo real de depuração e são fáceis de reintroduzir.
==== Atendimento Em Segundo Plano Exige TinyUSB Somente No Loop Principal
Esta é a regra de concorrência declarada em <<concurrency-model, Modelo De Concorrência>>. Com atendimento em segundo plano, a recepção Wi-Fi é executada em um contexto que não pode chamar o TinyUSB, razão pela qual existe o buffer circular de transmissão adiada.
==== Associação Não É Um IP
O auxiliar cyw43 cyw43_tcpip_link_status reporta CYW43_LINK_UP apenas quando a estação possui um endereço IP, e esta estação deliberadamente nunca obtém um.
O estado de associado é, portanto, lido do sinalizador de link da netif (netif_is_link_up), que a ponte também usa para decidir se deve encaminhar.
==== Uma Identidade Alterada Precisa De Um Novo ID De Produto
Um dispositivo composto que altera seu conjunto de interfaces mantendo o mesmo fornecedor USB e ID de produto pode receber um descritor em cache do hospedeiro.
O ID do produto é derivado das classes habilitadas; portanto, adicionar cada função CDC-ACM o desloca (cafe:4020 para cafe:4022) e o hospedeiro relê o novo layout.
==== Builds De Release Tornam assert Um No-Op
Um CMAKE_BUILD_TYPE=Release define NDEBUG, que compila assert() como nada; portanto, uma alocação protegida apenas por uma afirmação passa por uma falha e desreferencia NULL.
Uma falha do firmware antes de tud_task ser executado aparece no lado do hospedeiro como erro de enumeração USB -110, um timeout de leitura do descritor do dispositivo.
Guardas NULL reais são usados em vez de asserções no caminho de inicialização.
=== Ambiente Verificado
A configuração confirmada como funcional usa pico-sdk 2.2.0, a toolchain GCC arm-none-eabi e o TinyUSB e lwIP embutidos no pico-sdk, sem modificações.
A placa de referência é a Pico W (RP2040).
Espera-se que a Pico 2 W (RP2350) funcione.
Uma build produz um build/pico-usb-wifi.uf2 de aproximadamente 670 KB.